mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-02 12:01:32 +01:00
Merge branch 'master' into switch-to-gpgk
--
This commit is contained in:
commit
a52d883fdb
@ -189,7 +189,7 @@ release:
|
||||
$(MAKE) -f $(RELEASE_NAME)/build-aux/speedo.mk w32-release ;\
|
||||
echo "/* Build finished at $$(date -uIseconds) */" ;\
|
||||
echo "/*" ;\
|
||||
echo " * Please run the final step interactivly:" ;\
|
||||
echo " * Please run the final step interactively:" ;\
|
||||
echo " * make sign-release" ;\
|
||||
echo " */" ;\
|
||||
) 2>&1 | tee "$(RELEASE_NAME).buildlog"
|
||||
|
88
NEWS
88
NEWS
@ -1,6 +1,66 @@
|
||||
Noteworthy changes in version 2.3.0 (unreleased)
|
||||
------------------------------------------------
|
||||
|
||||
Changes also found in 2.2.11:
|
||||
|
||||
* gpgsm: Fix CRL loading when intermediate certicates are not yet
|
||||
trusted.
|
||||
|
||||
* gpgsm: Fix an error message about the digest algo. [#4219]
|
||||
|
||||
* gpg: Fix a wrong warning due to new sign usage check introduced
|
||||
with 2.2.9. [#4014]
|
||||
|
||||
* gpg: Print the "data source" even for an unsuccessful keyserver
|
||||
query.
|
||||
|
||||
* gpg: Do not store the TOFU trust model in the trustdb. This
|
||||
allows to enable or disable a TOFO model without triggering a
|
||||
trustdb rebuild. [#4134]
|
||||
|
||||
* scd: Fix cases of "Bad PIN" after using "forcesig". [#4177]
|
||||
|
||||
* agent: Fix possible hang in the ssh handler. [#4221]
|
||||
|
||||
* dirmngr: Tack the unmodified mail address to a WKD request. See
|
||||
commit a2bd4a64e5b057f291a60a9499f881dd47745e2f for details.
|
||||
|
||||
* dirmngr: Tweak diagnostic about missing LDAP server file.
|
||||
|
||||
* dirmngr: In verbose mode print the OCSP responder id.
|
||||
|
||||
* dirmngr: Fix parsing of the LDAP port. [#4230]
|
||||
|
||||
* wks: Add option --directory/-C to the server. Always build the
|
||||
server on Unix systems.
|
||||
|
||||
* wks: Add option --with-colons to the client. Support sites which
|
||||
use the policy file instead of the submission-address file.
|
||||
|
||||
* Fix EBADF when gpg et al. are called by broken CGI scripts.
|
||||
|
||||
* Fix some minor memory leaks and bugs.
|
||||
|
||||
Release-info: https://dev.gnupg.org/T4233
|
||||
See-also: gnupg-announce/2018q4/000432.html
|
||||
|
||||
Changes also found in 2.2.10:
|
||||
|
||||
* gpg: Refresh expired keys originating from the WKD. [#2917]
|
||||
|
||||
* gpg: Use a 256 KiB limit for a WKD imported key.
|
||||
|
||||
* gpg: New option --known-notation. [#4060]
|
||||
|
||||
* scd: Add support for the Trustica Cryptoucan reader.
|
||||
|
||||
* agent: Speed up starting during on-demand launching. [#3490]
|
||||
|
||||
* dirmngr: Validate SRV records in WKD queries.
|
||||
|
||||
Release-info: https://dev.gnupg.org/T4112
|
||||
See-also: gnupg-announce/2018q3/000428.html
|
||||
|
||||
Changes also found in 2.2.9:
|
||||
|
||||
* dirmngr: Fix recursive resolver mode and other bugs in the libdns
|
||||
@ -98,7 +158,7 @@ Noteworthy changes in version 2.3.0 (unreleased)
|
||||
* dirmngr: Fallback to CRL if no default OCSP responder is configured.
|
||||
|
||||
* dirmngr: Implement CRL fetching via https. Here a redirection to
|
||||
http is explictly allowed.
|
||||
http is explicitly allowed.
|
||||
|
||||
* dirmngr: Make LDAP searching and CRL fetching work under Windows.
|
||||
This stopped working with 2.1. [#3937]
|
||||
@ -326,6 +386,8 @@ Noteworthy changes in version 2.3.0 (unreleased)
|
||||
Version 2.2.7 (2018-05-02)
|
||||
Version 2.2.8 (2018-06-08)
|
||||
Version 2.2.9 (2018-07-12)
|
||||
Version 2.2.10 (2018-08-30)
|
||||
Version 2.2.11 (2018-11-06)
|
||||
|
||||
|
||||
Noteworthy changes in version 2.2.0 (2017-08-28)
|
||||
@ -959,7 +1021,7 @@ Noteworthy changes in version 2.1.11 (2016-01-26)
|
||||
|
||||
* gpg: Emit PROGRESS status lines during key generation.
|
||||
|
||||
* gpg: Don't check for ambigious or non-matching key specification in
|
||||
* gpg: Don't check for ambiguous or non-matching key specification in
|
||||
the config file or given to --encrypt-to. This feature will return
|
||||
in 2.3.x.
|
||||
|
||||
@ -986,7 +1048,7 @@ Noteworthy changes in version 2.1.11 (2016-01-26)
|
||||
* dirmmgr: All configured keyservers are now searched.
|
||||
|
||||
* dirmngr: Install CA certificate for hkps.pool.sks-keyservers.net.
|
||||
Use this certiticate even if --hkp-cacert is not used.
|
||||
Use this certificate even if --hkp-cacert is not used.
|
||||
|
||||
* gpgtar: Add actual encryption code. gpgtar does now fully replace
|
||||
gpg-zip.
|
||||
@ -1020,7 +1082,7 @@ Noteworthy changes in version 2.1.10 (2015-12-04)
|
||||
* gpg: New option --only-sign-text-ids to exclude photo IDs from key
|
||||
signing.
|
||||
|
||||
* gpg: Check for ambigious or non-matching key specification in the
|
||||
* gpg: Check for ambiguous or non-matching key specification in the
|
||||
config file or given to --encrypt-to.
|
||||
|
||||
* gpg: Show the used card reader with --card-status.
|
||||
@ -1310,7 +1372,7 @@ Noteworthy changes in version 2.1.1 (2014-12-16)
|
||||
|
||||
* gpg: Fixed regression in --refresh-keys.
|
||||
|
||||
* gpg: Fixed regresion in %g and %p codes for --sig-notation.
|
||||
* gpg: Fixed regression in %g and %p codes for --sig-notation.
|
||||
|
||||
* gpg: Fixed best matching hash algo detection for ECDSA and EdDSA.
|
||||
|
||||
@ -1390,7 +1452,7 @@ Noteworthy changes in version 2.1.0 (2014-11-06)
|
||||
|
||||
* gpg: Default keyring is now created with a .kbx suffix.
|
||||
|
||||
* gpg: Add a shortcut to the key capabilies menu (e.g. "=e" sets the
|
||||
* gpg: Add a shortcut to the key capabilities menu (e.g. "=e" sets the
|
||||
encryption capabilities).
|
||||
|
||||
* gpg: Fixed obsolete options parsing.
|
||||
@ -1582,7 +1644,7 @@ Noteworthy changes in version 2.1.0 (2014-11-06)
|
||||
* scdaemon: Does not anymore block after changing a card (regression
|
||||
fix).
|
||||
|
||||
* tools: gpg-connect-agent does now proberly display the help output
|
||||
* tools: gpg-connect-agent does now properly display the help output
|
||||
for "SCD HELP" commands.
|
||||
|
||||
|
||||
@ -1707,7 +1769,7 @@ Noteworthy changes in version 2.0.13 (2009-09-04)
|
||||
* Add hack to the internal CCID driver to allow the use of some
|
||||
Omnikey based card readers with 2048 bit keys.
|
||||
|
||||
* GPG now repeatly asks the user to insert the requested OpenPGP
|
||||
* GPG now repeatedly asks the user to insert the requested OpenPGP
|
||||
card. This can be disabled with --limit-card-insert-tries=1.
|
||||
|
||||
* Minor bug fixes.
|
||||
@ -1833,7 +1895,7 @@ Noteworthy changes in version 2.0.9 (2008-03-26)
|
||||
|
||||
* Extended the PKITS framework.
|
||||
|
||||
* Fixed a bug in the ambigious name detection.
|
||||
* Fixed a bug in the ambiguous name detection.
|
||||
|
||||
* Fixed possible memory corruption while importing OpenPGP keys (bug
|
||||
introduced with 2.0.8). [CVE-2008-1530]
|
||||
@ -2383,7 +2445,7 @@ Noteworthy changes in version 1.9.2 (2003-11-17)
|
||||
command but from the menu provided by the new --card-edit command.
|
||||
|
||||
* PINs are now properly cached and there are only 2 PINs visible.
|
||||
The 3rd PIN (CHV2) is internally syncronized with the regular PIN.
|
||||
The 3rd PIN (CHV2) is internally synchronized with the regular PIN.
|
||||
|
||||
* All kind of other internal stuff.
|
||||
|
||||
@ -3087,7 +3149,7 @@ Noteworthy changes in version 1.0.1 (1999-12-16)
|
||||
* Fixed some minor bugs and the problem with conventional encrypted
|
||||
packets which did use the gpg v3 partial length headers.
|
||||
|
||||
* Add Indonesian and Portugese translations.
|
||||
* Add Indonesian and Portuguese translations.
|
||||
|
||||
* Fixed a bug with symmetric-only encryption using the non-default 3DES.
|
||||
The option --emulate-3des-s2k-bug may be used to decrypt documents
|
||||
@ -3190,7 +3252,7 @@ Noteworthy changes in version 0.9.8 (1999-06-26)
|
||||
|
||||
* New option --with-key-data to list the public key parameters.
|
||||
New option -N to insert notations and a --set-policy-url.
|
||||
A couple of other options to allow reseting of options.
|
||||
A couple of other options to allow resetting of options.
|
||||
|
||||
* Better support for HPUX.
|
||||
|
||||
@ -3669,7 +3731,7 @@ Noteworthy changes in version 0.2.19 (1998-05-29)
|
||||
Noteworthy changes in version 0.2.18 (1998-05-15)
|
||||
------------------------------------
|
||||
|
||||
* Splitted cipher/random.c, add new option "--disable-dev-random"
|
||||
* Split cipher/random.c, add new option "--disable-dev-random"
|
||||
to configure to support the development of a random source for
|
||||
other systems. Prepared sourcefiles rand-unix.c, rand-w32.c
|
||||
and rand-dummy.c (which is used to allow compilation on systems
|
||||
|
@ -124,7 +124,11 @@ struct
|
||||
passphrase change. */
|
||||
int enable_passphrase_history;
|
||||
|
||||
/* If set the extended key format is used for new keys. */
|
||||
/* If set the extended key format is used for new keys. Note that
|
||||
* this may vave the value 2 in which case
|
||||
* --disable-extended-key-format won't have any effect and thus
|
||||
* effectivley locking it. This is required to support existing
|
||||
* profiles which lock the use of --enable-extended-key-format. */
|
||||
int enable_extended_key_format;
|
||||
|
||||
int running_detached; /* We are running detached from the tty. */
|
||||
@ -266,6 +270,14 @@ struct server_control_s
|
||||
};
|
||||
|
||||
|
||||
/* Status of pinentry. */
|
||||
enum
|
||||
{
|
||||
PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
|
||||
PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
|
||||
PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9
|
||||
};
|
||||
|
||||
/* Information pertaining to pinentry requests. */
|
||||
struct pin_entry_info_s
|
||||
{
|
||||
@ -276,6 +288,7 @@ struct pin_entry_info_s
|
||||
int with_qualitybar; /* Set if the quality bar should be displayed. */
|
||||
int with_repeat; /* Request repetition of the passphrase. */
|
||||
int repeat_okay; /* Repetition worked. */
|
||||
unsigned int status; /* Status. */
|
||||
gpg_error_t (*check_cb)(struct pin_entry_info_s *); /* CB used to check
|
||||
the PIN */
|
||||
void *check_cb_arg; /* optional argument which might be of use in the CB */
|
||||
@ -488,6 +501,7 @@ gpg_error_t agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
||||
char **passphrase_addr);
|
||||
|
||||
/*-- protect.c --*/
|
||||
void set_s2k_calibration_time (unsigned int milliseconds);
|
||||
unsigned long get_calibrated_s2k_count (void);
|
||||
unsigned long get_standard_s2k_count (void);
|
||||
unsigned char get_standard_s2k_count_rfc4880 (void);
|
||||
@ -538,15 +552,15 @@ int divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
char **r_buf, size_t *r_len, int *r_padding);
|
||||
int divert_generic_cmd (ctrl_t ctrl,
|
||||
const char *cmdline, void *assuan_context);
|
||||
int divert_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||
const char *id, const char *keydata, size_t keydatalen);
|
||||
gpg_error_t divert_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||
const char *keyref,
|
||||
const char *keydata, size_t keydatalen);
|
||||
|
||||
|
||||
/*-- call-scd.c --*/
|
||||
void initialize_module_call_scd (void);
|
||||
void agent_scd_dump_state (void);
|
||||
int agent_scd_check_running (void);
|
||||
void agent_scd_check_aliveness (void);
|
||||
int agent_reset_scd (ctrl_t ctrl);
|
||||
int agent_card_learn (ctrl_t ctrl,
|
||||
void (*kpinfo_cb)(void*, const char *),
|
||||
@ -577,9 +591,9 @@ int agent_card_pkdecrypt (ctrl_t ctrl,
|
||||
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, unsigned char **r_buf);
|
||||
int agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||
const char *id, const char *keydata,
|
||||
size_t keydatalen,
|
||||
gpg_error_t agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||
const char *keyref,
|
||||
const char *keydata, size_t keydatalen,
|
||||
int (*getpin_cb)(void *, const char *,
|
||||
const char *, char*, size_t),
|
||||
void *getpin_cb_arg);
|
||||
|
@ -85,6 +85,7 @@ struct entry_parm_s
|
||||
int lines;
|
||||
size_t size;
|
||||
unsigned char *buffer;
|
||||
int status;
|
||||
};
|
||||
|
||||
|
||||
@ -98,10 +99,14 @@ void
|
||||
initialize_module_call_pinentry (void)
|
||||
{
|
||||
static int initialized;
|
||||
int err;
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
if (npth_mutex_init (&entry_lock, NULL))
|
||||
err = npth_mutex_init (&entry_lock, NULL);
|
||||
if (err)
|
||||
log_fatal ("error initializing mutex: %s\n", strerror (err));
|
||||
|
||||
initialized = 1;
|
||||
}
|
||||
}
|
||||
@ -497,14 +502,16 @@ start_pinentry (ctrl_t ctrl)
|
||||
|
||||
{
|
||||
/* Provide a few default strings for use by the pinentries. This
|
||||
may help a pinentry to avoid implementing localization code. */
|
||||
* may help a pinentry to avoid implementing localization code.
|
||||
* Note that gpg-agent has been set to utf-8 so that the strings
|
||||
* are in the expected encoding. */
|
||||
static const struct { const char *key, *value; int what; } tbl[] = {
|
||||
/* TRANSLATORS: These are labels for buttons etc used in
|
||||
Pinentries. An underscore indicates that the next letter
|
||||
should be used as an accelerator. Double the underscore for
|
||||
a literal one. The actual to be translated text starts after
|
||||
the second vertical bar. Note that gpg-agent has been set to
|
||||
utf-8 so that the strings are in the expected encoding. */
|
||||
/* TRANSLATORS: These are labels for buttons etc as used in
|
||||
* Pinentries. In your translation copy the text before the
|
||||
* second vertical bar verbatim; translate only the following
|
||||
* text. An underscore indicates that the next letter should be
|
||||
* used as an accelerator. Double the underscore to have
|
||||
* pinentry display a literal underscore. */
|
||||
{ "ok", N_("|pinentry-label|_OK") },
|
||||
{ "cancel", N_("|pinentry-label|_Cancel") },
|
||||
{ "yes", N_("|pinentry-label|_Yes") },
|
||||
@ -888,13 +895,6 @@ setup_qualitybar (ctrl_t ctrl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
|
||||
PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
|
||||
PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9
|
||||
};
|
||||
|
||||
/* Check the button_info line for a close action. Also check for the
|
||||
PIN_REPEATED flag. */
|
||||
static gpg_error_t
|
||||
@ -941,6 +941,112 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Watch the socket's EOF condition, while checking finish of
|
||||
foreground thread. When EOF condition is detected, terminate
|
||||
the pinentry process behind the assuan pipe.
|
||||
*/
|
||||
static void *
|
||||
watch_sock (void *arg)
|
||||
{
|
||||
gnupg_fd_t *p = (gnupg_fd_t *)arg;
|
||||
pid_t pid = assuan_get_pid (entry_ctx);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int err;
|
||||
gnupg_fd_t sock = *p;
|
||||
fd_set fdset;
|
||||
struct timeval timeout = { 0, 500000 };
|
||||
|
||||
if (sock == GNUPG_INVALID_FD)
|
||||
return NULL;
|
||||
|
||||
FD_ZERO (&fdset);
|
||||
FD_SET (FD2INT (sock), &fdset);
|
||||
err = npth_select (FD2INT (sock)+1, &fdset, NULL, NULL, &timeout);
|
||||
|
||||
if (err < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Possibly, it's EOF. */
|
||||
if (err > 0)
|
||||
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
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Ask pinentry to get a pin by "GETPIN" command, spawning a thread
|
||||
detecting the socket's EOF.
|
||||
*/
|
||||
static gpg_error_t
|
||||
do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
|
||||
{
|
||||
npth_attr_t tattr;
|
||||
gpg_error_t rc;
|
||||
int err;
|
||||
npth_t thread;
|
||||
int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
|
||||
gnupg_fd_t sock_watched = ctrl->thread_startup.fd;
|
||||
|
||||
err = npth_attr_init (&tattr);
|
||||
if (err)
|
||||
{
|
||||
log_error ("do_getpin: error npth_attr_init: %s\n", strerror (err));
|
||||
return gpg_error_from_errno (err);
|
||||
}
|
||||
npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
|
||||
|
||||
err = npth_create (&thread, &tattr, watch_sock, (void *)&sock_watched);
|
||||
npth_attr_destroy (&tattr);
|
||||
if (err)
|
||||
{
|
||||
log_error ("do_getpin: error spawning thread: %s\n", strerror (err));
|
||||
return gpg_error_from_errno (err);
|
||||
}
|
||||
|
||||
assuan_begin_confidential (entry_ctx);
|
||||
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm,
|
||||
inq_quality, entry_ctx,
|
||||
pinentry_status_cb, &parm->status);
|
||||
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
|
||||
/* Most pinentries out in the wild return the old Assuan error code
|
||||
for canceled which gets translated to an assuan Cancel error and
|
||||
not to the code for a user cancel. Fix this here. */
|
||||
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
|
||||
/* Change error code in case the window close button was clicked
|
||||
to cancel the operation. */
|
||||
if ((parm->status & PINENTRY_STATUS_CLOSE_BUTTON)
|
||||
&& gpg_err_code (rc) == GPG_ERR_CANCELED)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
|
||||
|
||||
sock_watched = GNUPG_INVALID_FD;
|
||||
err = npth_join (thread, NULL);
|
||||
if (err)
|
||||
log_error ("do_getpin: error joining thread: %s\n", strerror (err));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Call the Entry and ask for the PIN. We do check for a valid PIN
|
||||
number here and repeat it as long as we have invalid formed
|
||||
@ -958,8 +1064,6 @@ agent_askpin (ctrl_t ctrl,
|
||||
struct entry_parm_s parm;
|
||||
const char *errtext = NULL;
|
||||
int is_pin = 0;
|
||||
int saveflag;
|
||||
unsigned int pinentry_status;
|
||||
|
||||
if (opt.batch)
|
||||
return 0; /* fixme: we should return BAD PIN */
|
||||
@ -1070,6 +1174,7 @@ agent_askpin (ctrl_t ctrl,
|
||||
pininfo->with_repeat = 0; /* Pinentry does not support it. */
|
||||
}
|
||||
pininfo->repeat_okay = 0;
|
||||
pininfo->status = 0;
|
||||
|
||||
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
|
||||
{
|
||||
@ -1101,27 +1206,8 @@ agent_askpin (ctrl_t ctrl,
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
}
|
||||
|
||||
saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
|
||||
assuan_begin_confidential (entry_ctx);
|
||||
pinentry_status = 0;
|
||||
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
|
||||
inq_quality, entry_ctx,
|
||||
pinentry_status_cb, &pinentry_status);
|
||||
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
|
||||
/* Most pinentries out in the wild return the old Assuan error code
|
||||
for canceled which gets translated to an assuan Cancel error and
|
||||
not to the code for a user cancel. Fix this here. */
|
||||
if (rc && gpg_err_source (rc)
|
||||
&& gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
|
||||
|
||||
|
||||
/* Change error code in case the window close button was clicked
|
||||
to cancel the operation. */
|
||||
if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
|
||||
&& gpg_err_code (rc) == GPG_ERR_CANCELED)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
|
||||
|
||||
rc = do_getpin (ctrl, &parm);
|
||||
pininfo->status = parm.status;
|
||||
if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
|
||||
errtext = is_pin? L_("PIN too long")
|
||||
: L_("Passphrase too long");
|
||||
@ -1145,12 +1231,19 @@ agent_askpin (ctrl_t ctrl,
|
||||
/* More checks by utilizing the optional callback. */
|
||||
pininfo->cb_errtext = NULL;
|
||||
rc = pininfo->check_cb (pininfo);
|
||||
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||
&& pininfo->cb_errtext)
|
||||
/* When pinentry cache causes an error, return now. */
|
||||
if (rc
|
||||
&& (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
|
||||
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
|
||||
{
|
||||
if (pininfo->cb_errtext)
|
||||
errtext = pininfo->cb_errtext;
|
||||
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
|
||||
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
|
||||
}
|
||||
else if (rc)
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
}
|
||||
@ -1158,12 +1251,12 @@ agent_askpin (ctrl_t ctrl,
|
||||
if (!errtext)
|
||||
{
|
||||
if (pininfo->with_repeat
|
||||
&& (pinentry_status & PINENTRY_STATUS_PIN_REPEATED))
|
||||
&& (pininfo->status & PINENTRY_STATUS_PIN_REPEATED))
|
||||
pininfo->repeat_okay = 1;
|
||||
return unlock_pinentry (ctrl, 0); /* okay, got a PIN or passphrase */
|
||||
}
|
||||
|
||||
if ((pinentry_status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||
if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||
/* The password was read from the cache. Don't count this
|
||||
against the retry count. */
|
||||
pininfo->failed_tries --;
|
||||
@ -1183,12 +1276,9 @@ agent_get_passphrase (ctrl_t ctrl,
|
||||
const char *errtext, int with_qualitybar,
|
||||
const char *keyinfo, cache_mode_t cache_mode)
|
||||
{
|
||||
|
||||
int rc;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct entry_parm_s parm;
|
||||
int saveflag;
|
||||
unsigned int pinentry_status;
|
||||
|
||||
*retpass = NULL;
|
||||
if (opt.batch)
|
||||
@ -1272,24 +1362,7 @@ agent_get_passphrase (ctrl_t ctrl,
|
||||
if (!parm.buffer)
|
||||
return unlock_pinentry (ctrl, out_of_core ());
|
||||
|
||||
saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
|
||||
assuan_begin_confidential (entry_ctx);
|
||||
pinentry_status = 0;
|
||||
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
|
||||
inq_quality, entry_ctx,
|
||||
pinentry_status_cb, &pinentry_status);
|
||||
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
|
||||
/* Most pinentries out in the wild return the old Assuan error code
|
||||
for canceled which gets translated to an assuan Cancel error and
|
||||
not to the code for a user cancel. Fix this here. */
|
||||
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
|
||||
/* Change error code in case the window close button was clicked
|
||||
to cancel the operation. */
|
||||
if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
|
||||
&& gpg_err_code (rc) == GPG_ERR_CANCELED)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
|
||||
|
||||
rc = do_getpin (ctrl, &parm);
|
||||
if (rc)
|
||||
xfree (parm.buffer);
|
||||
else
|
||||
@ -1537,14 +1610,6 @@ agent_popup_message_stop (ctrl_t ctrl)
|
||||
TerminateProcess (process, 1);
|
||||
}
|
||||
#else
|
||||
else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
|
||||
{ /* The daemon already died. No need to send a kill. However
|
||||
because we already waited for the process, we need to tell
|
||||
assuan that it should not wait again (done by
|
||||
unlock_pinentry). */
|
||||
if (rc == pid)
|
||||
assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
|
||||
}
|
||||
else if (pid > 0)
|
||||
kill (pid, SIGINT);
|
||||
#endif
|
||||
|
322
agent/call-scd.c
322
agent/call-scd.c
@ -54,17 +54,10 @@ struct scd_local_s
|
||||
SCD_LOCAL_LIST (see below). */
|
||||
struct scd_local_s *next_local;
|
||||
|
||||
/* We need to get back to the ctrl object actually referencing this
|
||||
structure. This is really an awkward way of enumerating the local
|
||||
contexts. A much cleaner way would be to keep a global list of
|
||||
ctrl objects to enumerate them. */
|
||||
ctrl_t ctrl_backlink;
|
||||
|
||||
assuan_context_t ctx; /* NULL or session context for the SCdaemon
|
||||
used with this connection. */
|
||||
int locked; /* This flag is used to assert proper use of
|
||||
start_scd and unlock_scd. */
|
||||
|
||||
unsigned int in_use: 1; /* CTX is in use. */
|
||||
unsigned int invalid:1; /* CTX is invalid, should be released. */
|
||||
};
|
||||
|
||||
|
||||
@ -168,14 +161,33 @@ agent_scd_dump_state (void)
|
||||
static int
|
||||
unlock_scd (ctrl_t ctrl, int rc)
|
||||
{
|
||||
if (ctrl->scd_local->locked != 1)
|
||||
int err;
|
||||
|
||||
if (ctrl->scd_local->in_use == 0)
|
||||
{
|
||||
log_error ("unlock_scd: invalid lock count (%d)\n",
|
||||
ctrl->scd_local->locked);
|
||||
log_error ("unlock_scd: CTX is not in use\n");
|
||||
if (!rc)
|
||||
rc = gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
ctrl->scd_local->locked = 0;
|
||||
err = npth_mutex_lock (&start_scd_lock);
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to acquire the start_scd lock: %s\n", strerror (err));
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
ctrl->scd_local->in_use = 0;
|
||||
if (ctrl->scd_local->invalid)
|
||||
{
|
||||
assuan_release (ctrl->scd_local->ctx);
|
||||
ctrl->scd_local->ctx = NULL;
|
||||
ctrl->scd_local->invalid = 0;
|
||||
}
|
||||
err = npth_mutex_unlock (&start_scd_lock);
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to release the start_scd lock: %s\n", strerror (err));
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -191,6 +203,86 @@ atfork_cb (void *opaque, int where)
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
wait_child_thread (void *arg)
|
||||
{
|
||||
int err;
|
||||
struct scd_local_s *sl;
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
HANDLE pid = (HANDLE)arg;
|
||||
|
||||
npth_unprotect ();
|
||||
WaitForSingleObject ((HANDLE)pid, INFINITE);
|
||||
npth_protect ();
|
||||
log_info ("scdaemon finished\n");
|
||||
#else
|
||||
int wstatus;
|
||||
pid_t pid = (pid_t)(uintptr_t)arg;
|
||||
|
||||
again:
|
||||
npth_unprotect ();
|
||||
err = waitpid (pid, &wstatus, 0);
|
||||
npth_protect ();
|
||||
|
||||
if (err < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
goto again;
|
||||
log_error ("waitpid failed: %s\n", strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WIFEXITED (wstatus))
|
||||
log_info ("scdaemon finished (status %d)\n", WEXITSTATUS (wstatus));
|
||||
else if (WIFSIGNALED (wstatus))
|
||||
log_info ("scdaemon killed by signal %d\n", WTERMSIG (wstatus));
|
||||
else
|
||||
{
|
||||
if (WIFSTOPPED (wstatus))
|
||||
log_info ("scdaemon stopped by signal %d\n", WSTOPSIG (wstatus));
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
err = npth_mutex_lock (&start_scd_lock);
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to acquire the start_scd lock: %s\n",
|
||||
strerror (err));
|
||||
}
|
||||
else
|
||||
{
|
||||
assuan_set_flag (primary_scd_ctx, ASSUAN_NO_WAITPID, 1);
|
||||
|
||||
for (sl = scd_local_list; sl; sl = sl->next_local)
|
||||
{
|
||||
sl->invalid = 1;
|
||||
if (!sl->in_use && sl->ctx)
|
||||
{
|
||||
assuan_release (sl->ctx);
|
||||
sl->ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
primary_scd_ctx = NULL;
|
||||
primary_scd_ctx_reusable = 0;
|
||||
|
||||
xfree (socket_name);
|
||||
socket_name = NULL;
|
||||
|
||||
err = npth_mutex_unlock (&start_scd_lock);
|
||||
if (err)
|
||||
log_error ("failed to release the start_scd lock after waitpid: %s\n",
|
||||
strerror (err));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Fork off the SCdaemon if this has not already been done. Lock the
|
||||
daemon and make sure that a proper context has been setup in CTRL.
|
||||
This function might also lock the daemon, which means that the
|
||||
@ -211,37 +303,19 @@ start_scd (ctrl_t ctrl)
|
||||
if (opt.disable_scdaemon)
|
||||
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
|
||||
/* If this is the first call for this session, setup the local data
|
||||
structure. */
|
||||
if (!ctrl->scd_local)
|
||||
if (ctrl->scd_local && ctrl->scd_local->ctx)
|
||||
{
|
||||
ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local);
|
||||
if (!ctrl->scd_local)
|
||||
return gpg_error_from_syserror ();
|
||||
ctrl->scd_local->ctrl_backlink = ctrl;
|
||||
ctrl->scd_local->next_local = scd_local_list;
|
||||
scd_local_list = ctrl->scd_local;
|
||||
ctrl->scd_local->in_use = 1;
|
||||
return 0; /* Okay, the context is fine. */
|
||||
}
|
||||
|
||||
|
||||
/* Assert that the lock count is as expected. */
|
||||
if (ctrl->scd_local->locked)
|
||||
if (ctrl->scd_local && ctrl->scd_local->in_use)
|
||||
{
|
||||
log_error ("start_scd: invalid lock count (%d)\n",
|
||||
ctrl->scd_local->locked);
|
||||
log_error ("start_scd: CTX is in use\n");
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
ctrl->scd_local->locked++;
|
||||
|
||||
if (ctrl->scd_local->ctx)
|
||||
return 0; /* Okay, the context is fine. We used to test for an
|
||||
alive context here and do an disconnect. Now that we
|
||||
have a ticker function to check for it, it is easier
|
||||
not to check here but to let the connection run on an
|
||||
error instead. */
|
||||
|
||||
|
||||
/* We need to protect the following code. */
|
||||
/* We need to serialize the access to scd_local_list and primary_scd_ctx. */
|
||||
rc = npth_mutex_lock (&start_scd_lock);
|
||||
if (rc)
|
||||
{
|
||||
@ -250,6 +324,25 @@ start_scd (ctrl_t ctrl)
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
|
||||
/* If this is the first call for this session, setup the local data
|
||||
structure. */
|
||||
if (!ctrl->scd_local)
|
||||
{
|
||||
ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local);
|
||||
if (!ctrl->scd_local)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
rc = npth_mutex_unlock (&start_scd_lock);
|
||||
if (rc)
|
||||
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
|
||||
return err;
|
||||
}
|
||||
ctrl->scd_local->next_local = scd_local_list;
|
||||
scd_local_list = ctrl->scd_local;
|
||||
}
|
||||
|
||||
ctrl->scd_local->in_use = 1;
|
||||
|
||||
/* Check whether the pipe server has already been started and in
|
||||
this case either reuse a lingering pipe connection or establish a
|
||||
new socket based one. */
|
||||
@ -415,7 +508,29 @@ start_scd (ctrl_t ctrl)
|
||||
primary_scd_ctx = ctx;
|
||||
primary_scd_ctx_reusable = 0;
|
||||
|
||||
{
|
||||
npth_t thread;
|
||||
npth_attr_t tattr;
|
||||
pid_t pid;
|
||||
|
||||
pid = assuan_get_pid (primary_scd_ctx);
|
||||
err = npth_attr_init (&tattr);
|
||||
if (!err)
|
||||
{
|
||||
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
|
||||
err = npth_create (&thread, &tattr, wait_child_thread,
|
||||
(void *)(uintptr_t)pid);
|
||||
if (err)
|
||||
log_error ("error spawning wait_child_thread: %s\n", strerror (err));
|
||||
npth_attr_destroy (&tattr);
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
rc = npth_mutex_unlock (&start_scd_lock);
|
||||
if (rc)
|
||||
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
|
||||
|
||||
xfree (abs_homedir);
|
||||
if (err)
|
||||
{
|
||||
@ -425,11 +540,9 @@ start_scd (ctrl_t ctrl)
|
||||
}
|
||||
else
|
||||
{
|
||||
ctrl->scd_local->invalid = 0;
|
||||
ctrl->scd_local->ctx = ctx;
|
||||
}
|
||||
rc = npth_mutex_unlock (&start_scd_lock);
|
||||
if (rc)
|
||||
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -444,105 +557,25 @@ agent_scd_check_running (void)
|
||||
}
|
||||
|
||||
|
||||
/* Check whether the Scdaemon is still alive and clean it up if not. */
|
||||
void
|
||||
agent_scd_check_aliveness (void)
|
||||
{
|
||||
pid_t pid;
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
DWORD rc;
|
||||
#else
|
||||
int rc;
|
||||
#endif
|
||||
struct timespec abstime;
|
||||
int err;
|
||||
|
||||
if (!primary_scd_ctx)
|
||||
return; /* No scdaemon running. */
|
||||
|
||||
/* This is not a critical function so we use a short timeout while
|
||||
acquiring the lock. */
|
||||
npth_clock_gettime (&abstime);
|
||||
abstime.tv_sec += 1;
|
||||
err = npth_mutex_timedlock (&start_scd_lock, &abstime);
|
||||
if (err)
|
||||
{
|
||||
if (err == ETIMEDOUT)
|
||||
{
|
||||
if (opt.verbose > 1)
|
||||
log_info ("failed to acquire the start_scd lock while"
|
||||
" doing an aliveness check: %s\n", strerror (err));
|
||||
}
|
||||
else
|
||||
log_error ("failed to acquire the start_scd lock while"
|
||||
" doing an aliveness check: %s\n", strerror (err));
|
||||
return;
|
||||
}
|
||||
|
||||
if (primary_scd_ctx)
|
||||
{
|
||||
pid = assuan_get_pid (primary_scd_ctx);
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* If we have a PID we disconnect if either GetExitProcessCode
|
||||
fails or if ir returns the exit code of the scdaemon. 259 is
|
||||
the error code for STILL_ALIVE. */
|
||||
if (pid != (pid_t)(void*)(-1) && pid
|
||||
&& (!GetExitCodeProcess ((HANDLE)pid, &rc) || rc != 259))
|
||||
#else
|
||||
if (pid != (pid_t)(-1) && pid
|
||||
&& ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
|
||||
#endif
|
||||
{
|
||||
/* Okay, scdaemon died. Disconnect the primary connection
|
||||
now but take care that it won't do another wait. Also
|
||||
cleanup all other connections and release their
|
||||
resources. The next use will start a new daemon then.
|
||||
Due to the use of the START_SCD_LOCAL we are sure that
|
||||
none of these context are actually in use. */
|
||||
struct scd_local_s *sl;
|
||||
|
||||
assuan_set_flag (primary_scd_ctx, ASSUAN_NO_WAITPID, 1);
|
||||
assuan_release (primary_scd_ctx);
|
||||
|
||||
for (sl=scd_local_list; sl; sl = sl->next_local)
|
||||
{
|
||||
if (sl->ctx)
|
||||
{
|
||||
if (sl->ctx != primary_scd_ctx)
|
||||
assuan_release (sl->ctx);
|
||||
sl->ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
primary_scd_ctx = NULL;
|
||||
primary_scd_ctx_reusable = 0;
|
||||
|
||||
xfree (socket_name);
|
||||
socket_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
err = npth_mutex_unlock (&start_scd_lock);
|
||||
if (err)
|
||||
log_error ("failed to release the start_scd lock while"
|
||||
" doing the aliveness check: %s\n", strerror (err));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Reset the SCD if it has been used. Actually it is not a reset but
|
||||
a cleanup of resources used by the current connection. */
|
||||
int
|
||||
agent_reset_scd (ctrl_t ctrl)
|
||||
{
|
||||
int err = npth_mutex_lock (&start_scd_lock);
|
||||
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to acquire the start_scd lock: %s\n",
|
||||
strerror (err));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctrl->scd_local)
|
||||
{
|
||||
if (ctrl->scd_local->ctx)
|
||||
{
|
||||
/* We can't disconnect the primary context because libassuan
|
||||
does a waitpid on it and thus the system would hang.
|
||||
Instead we send a reset and keep that connection for
|
||||
reuse. */
|
||||
/* We send a reset and keep that connection for reuse. */
|
||||
if (ctrl->scd_local->ctx == primary_scd_ctx)
|
||||
{
|
||||
/* Send a RESTART to the SCD. This is required for the
|
||||
@ -584,6 +617,11 @@ agent_reset_scd (ctrl_t ctrl)
|
||||
ctrl->scd_local = NULL;
|
||||
}
|
||||
|
||||
err = npth_mutex_unlock (&start_scd_lock);
|
||||
if (err)
|
||||
log_error ("failed to release the start_scd lock: %s\n", strerror (err));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1055,23 +1093,27 @@ inq_writekey_parms (void *opaque, const char *line)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
/* Call scd to write a key to a card under the id KEYREF. */
|
||||
gpg_error_t
|
||||
agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||
const char *id, const char *keydata, size_t keydatalen,
|
||||
const char *keyref,
|
||||
const char *keydata, size_t keydatalen,
|
||||
int (*getpin_cb)(void *, const char *,
|
||||
const char *, char*, size_t),
|
||||
void *getpin_cb_arg)
|
||||
{
|
||||
int rc;
|
||||
gpg_error_t err;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct inq_needpin_parm_s parms;
|
||||
|
||||
(void)serialno;
|
||||
rc = start_scd (ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
(void)serialno; /* NULL or a number to check for the correct card.
|
||||
* But is is not implemented. */
|
||||
|
||||
snprintf (line, DIM(line), "WRITEKEY %s%s", force ? "--force " : "", id);
|
||||
err = start_scd (ctrl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
snprintf (line, DIM(line), "WRITEKEY %s%s", force ? "--force " : "", keyref);
|
||||
parms.ctx = ctrl->scd_local->ctx;
|
||||
parms.getpin_cb = getpin_cb;
|
||||
parms.getpin_cb_arg = getpin_cb_arg;
|
||||
@ -1080,9 +1122,9 @@ agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||
parms.keydata = keydata;
|
||||
parms.keydatalen = keydatalen;
|
||||
|
||||
rc = assuan_transact (ctrl->scd_local->ctx, line, NULL, NULL,
|
||||
err = assuan_transact (ctrl->scd_local->ctx, line, NULL, NULL,
|
||||
inq_writekey_parms, &parms, NULL, NULL);
|
||||
return unlock_scd (ctrl, rc);
|
||||
return unlock_scd (ctrl, err);
|
||||
}
|
||||
|
||||
|
||||
|
@ -195,9 +195,14 @@ struct ssh_key_type_spec
|
||||
algorithm. */
|
||||
ssh_signature_encoder_t signature_encoder;
|
||||
|
||||
/* The name of the ECC curve or NULL. */
|
||||
/* The name of the ECC curve or NULL for non-ECC algos. This is the
|
||||
* canonical name for the curve as specified by RFC-5656. */
|
||||
const char *curve_name;
|
||||
|
||||
/* An alias for curve_name or NULL. Actually this is Libcgrypt's
|
||||
* primary name of the curve. */
|
||||
const char *alt_curve_name;
|
||||
|
||||
/* The hash algorithm to be used with this key. 0 for using the
|
||||
default. */
|
||||
int hash_algo;
|
||||
@ -297,68 +302,71 @@ static const ssh_key_type_spec_t ssh_key_types[] =
|
||||
{
|
||||
"ssh-ed25519", "Ed25519", GCRY_PK_EDDSA, "qd", "q", "rs", "qd",
|
||||
NULL, ssh_signature_encoder_eddsa,
|
||||
"Ed25519", 0, SPEC_FLAG_IS_EdDSA
|
||||
"Ed25519", NULL, 0, SPEC_FLAG_IS_EdDSA
|
||||
},
|
||||
{
|
||||
"ssh-rsa", "RSA", GCRY_PK_RSA, "nedupq", "en", "s", "nedpqu",
|
||||
ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
|
||||
NULL, 0, SPEC_FLAG_USE_PKCS1V2
|
||||
NULL, NULL, 0, SPEC_FLAG_USE_PKCS1V2
|
||||
},
|
||||
{
|
||||
"ssh-dss", "DSA", GCRY_PK_DSA, "pqgyx", "pqgy", "rs", "pqgyx",
|
||||
NULL, ssh_signature_encoder_dsa,
|
||||
NULL, 0, 0
|
||||
NULL, NULL, 0, 0
|
||||
},
|
||||
{
|
||||
"ecdsa-sha2-nistp256", "ECDSA", GCRY_PK_ECC, "qd", "q", "rs", "qd",
|
||||
NULL, ssh_signature_encoder_ecdsa,
|
||||
"nistp256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA
|
||||
"nistp256", "NIST P-256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA
|
||||
},
|
||||
{
|
||||
"ecdsa-sha2-nistp384", "ECDSA", GCRY_PK_ECC, "qd", "q", "rs", "qd",
|
||||
NULL, ssh_signature_encoder_ecdsa,
|
||||
"nistp384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA
|
||||
"nistp384", "NIST P-384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA
|
||||
},
|
||||
{
|
||||
"ecdsa-sha2-nistp521", "ECDSA", GCRY_PK_ECC, "qd", "q", "rs", "qd",
|
||||
NULL, ssh_signature_encoder_ecdsa,
|
||||
"nistp521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA
|
||||
"nistp521", "NIST P-521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA
|
||||
},
|
||||
{
|
||||
"ssh-ed25519-cert-v01@openssh.com", "Ed25519",
|
||||
GCRY_PK_EDDSA, "qd", "q", "rs", "qd",
|
||||
NULL, ssh_signature_encoder_eddsa,
|
||||
"Ed25519", 0, SPEC_FLAG_IS_EdDSA | SPEC_FLAG_WITH_CERT
|
||||
"Ed25519", NULL, 0, SPEC_FLAG_IS_EdDSA | SPEC_FLAG_WITH_CERT
|
||||
},
|
||||
{
|
||||
"ssh-rsa-cert-v01@openssh.com", "RSA",
|
||||
GCRY_PK_RSA, "nedupq", "en", "s", "nedpqu",
|
||||
ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
|
||||
NULL, 0, SPEC_FLAG_USE_PKCS1V2 | SPEC_FLAG_WITH_CERT
|
||||
NULL, NULL, 0, SPEC_FLAG_USE_PKCS1V2 | SPEC_FLAG_WITH_CERT
|
||||
},
|
||||
{
|
||||
"ssh-dss-cert-v01@openssh.com", "DSA",
|
||||
GCRY_PK_DSA, "pqgyx", "pqgy", "rs", "pqgyx",
|
||||
NULL, ssh_signature_encoder_dsa,
|
||||
NULL, 0, SPEC_FLAG_WITH_CERT | SPEC_FLAG_WITH_CERT
|
||||
NULL, NULL, 0, SPEC_FLAG_WITH_CERT | SPEC_FLAG_WITH_CERT
|
||||
},
|
||||
{
|
||||
"ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA",
|
||||
GCRY_PK_ECC, "qd", "q", "rs", "qd",
|
||||
NULL, ssh_signature_encoder_ecdsa,
|
||||
"nistp256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT
|
||||
"nistp256", "NIST P-256", GCRY_MD_SHA256,
|
||||
SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT
|
||||
},
|
||||
{
|
||||
"ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA",
|
||||
GCRY_PK_ECC, "qd", "q", "rs", "qd",
|
||||
NULL, ssh_signature_encoder_ecdsa,
|
||||
"nistp384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT
|
||||
"nistp384", "NIST P-384", GCRY_MD_SHA384,
|
||||
SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT
|
||||
},
|
||||
{
|
||||
"ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA",
|
||||
GCRY_PK_ECC, "qd", "q", "rs", "qd",
|
||||
NULL, ssh_signature_encoder_ecdsa,
|
||||
"nistp521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT
|
||||
"nistp521", "NIST P-521", GCRY_MD_SHA512,
|
||||
SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT
|
||||
}
|
||||
};
|
||||
|
||||
@ -389,16 +397,24 @@ realloc_secure (void *a, size_t n)
|
||||
|
||||
|
||||
/* Lookup the ssh-identifier for the ECC curve CURVE_NAME. Returns
|
||||
NULL if not found. */
|
||||
* NULL if not found. If found the ssh indetifier is returned and a
|
||||
* pointer to the canonical curve name as specified for ssh is stored
|
||||
* at R_CANON_NAME. */
|
||||
static const char *
|
||||
ssh_identifier_from_curve_name (const char *curve_name)
|
||||
ssh_identifier_from_curve_name (const char *curve_name,
|
||||
const char **r_canon_name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DIM (ssh_key_types); i++)
|
||||
if (ssh_key_types[i].curve_name
|
||||
&& !strcmp (ssh_key_types[i].curve_name, curve_name))
|
||||
&& (!strcmp (ssh_key_types[i].curve_name, curve_name)
|
||||
|| (ssh_key_types[i].alt_curve_name
|
||||
&& !strcmp (ssh_key_types[i].alt_curve_name, curve_name))))
|
||||
{
|
||||
*r_canon_name = ssh_key_types[i].curve_name;
|
||||
return ssh_key_types[i].ssh_identifier;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -1849,7 +1865,6 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
|
||||
gpg_error_t err = 0;
|
||||
gcry_sexp_t value_list = NULL;
|
||||
gcry_sexp_t value_pair = NULL;
|
||||
char *curve_name = NULL;
|
||||
estream_t stream = NULL;
|
||||
void *blob = NULL;
|
||||
size_t blob_size;
|
||||
@ -1867,7 +1882,7 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get the type of the key extpression. */
|
||||
/* Get the type of the key expression. */
|
||||
data = gcry_sexp_nth_data (sexp, 0, &datalen);
|
||||
if (!data)
|
||||
{
|
||||
@ -1898,49 +1913,17 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
|
||||
/* Write the ssh algorithm identifier. */
|
||||
if ((key_spec.flags & SPEC_FLAG_IS_ECDSA))
|
||||
{
|
||||
/* Parse the "curve" parameter. We currently expect the curve
|
||||
name for ECC and not the parameters of the curve. This can
|
||||
easily be changed but then we need to find the curve name
|
||||
from the parameters using gcry_pk_get_curve. */
|
||||
const char *mapped;
|
||||
const char *sshname;
|
||||
/* Map the curve name to the ssh name. */
|
||||
const char *name, *sshname, *canon_name;
|
||||
|
||||
gcry_sexp_release (value_pair);
|
||||
value_pair = gcry_sexp_find_token (value_list, "curve", 5);
|
||||
if (!value_pair)
|
||||
name = gcry_pk_get_curve (sexp, 0, NULL);
|
||||
if (!name)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_CURVE);
|
||||
goto out;
|
||||
}
|
||||
curve_name = gcry_sexp_nth_string (value_pair, 1);
|
||||
if (!curve_name)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_CURVE); /* (Or out of core.) */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Fixme: The mapping should be done by using gcry_pk_get_curve
|
||||
et al to iterate over all name aliases. */
|
||||
if (!strcmp (curve_name, "NIST P-256"))
|
||||
mapped = "nistp256";
|
||||
else if (!strcmp (curve_name, "NIST P-384"))
|
||||
mapped = "nistp384";
|
||||
else if (!strcmp (curve_name, "NIST P-521"))
|
||||
mapped = "nistp521";
|
||||
else
|
||||
mapped = NULL;
|
||||
if (mapped)
|
||||
{
|
||||
xfree (curve_name);
|
||||
curve_name = xtrystrdup (mapped);
|
||||
if (!curve_name)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
sshname = ssh_identifier_from_curve_name (curve_name);
|
||||
sshname = ssh_identifier_from_curve_name (name, &canon_name);
|
||||
if (!sshname)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||
@ -1949,7 +1932,7 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
|
||||
err = stream_write_cstring (stream, sshname);
|
||||
if (err)
|
||||
goto out;
|
||||
err = stream_write_cstring (stream, curve_name);
|
||||
err = stream_write_cstring (stream, canon_name);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
@ -2022,7 +2005,6 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
|
||||
out:
|
||||
gcry_sexp_release (value_list);
|
||||
gcry_sexp_release (value_pair);
|
||||
xfree (curve_name);
|
||||
es_fclose (stream);
|
||||
es_free (blob);
|
||||
|
||||
@ -2081,7 +2063,7 @@ ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret,
|
||||
ssh_key_type_spec_t spec;
|
||||
gcry_mpi_t *mpi_list = NULL;
|
||||
const char *elems;
|
||||
char *curve_name = NULL;
|
||||
const char *curve_name = NULL;
|
||||
|
||||
|
||||
err = stream_read_cstring (stream, &key_type);
|
||||
@ -2204,34 +2186,19 @@ ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret,
|
||||
* certificate.
|
||||
*/
|
||||
unsigned char *buffer;
|
||||
const char *mapped;
|
||||
|
||||
err = stream_read_string (cert? cert : stream, 0, &buffer, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
curve_name = buffer;
|
||||
/* Fixme: Check that curve_name matches the keytype. */
|
||||
/* Because Libgcrypt < 1.6 has no support for the "nistpNNN"
|
||||
curve names, we need to translate them here to Libgcrypt's
|
||||
native names. */
|
||||
if (!strcmp (curve_name, "nistp256"))
|
||||
mapped = "NIST P-256";
|
||||
else if (!strcmp (curve_name, "nistp384"))
|
||||
mapped = "NIST P-384";
|
||||
else if (!strcmp (curve_name, "nistp521"))
|
||||
mapped = "NIST P-521";
|
||||
else
|
||||
mapped = NULL;
|
||||
if (mapped)
|
||||
/* Get the canonical name. Should be the same as the read
|
||||
* string but we use this mapping to validate that name. */
|
||||
if (!ssh_identifier_from_curve_name (buffer, &curve_name))
|
||||
{
|
||||
xfree (curve_name);
|
||||
curve_name = xtrystrdup (mapped);
|
||||
if (!curve_name)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||
xfree (buffer);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
xfree (buffer);
|
||||
|
||||
err = ssh_receive_mpint_list (stream, secret, &spec, cert, &mpi_list);
|
||||
if (err)
|
||||
@ -2299,7 +2266,6 @@ ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret,
|
||||
out:
|
||||
es_fclose (cert);
|
||||
mpint_list_free (mpi_list);
|
||||
xfree (curve_name);
|
||||
xfree (key_type);
|
||||
xfree (comment);
|
||||
|
||||
@ -2647,6 +2613,8 @@ ssh_handler_request_identities (ctrl_t ctrl,
|
||||
continue;
|
||||
|
||||
err = ssh_send_key_public (key_blobs, key_public, cardsn);
|
||||
if (err && opt.verbose)
|
||||
gcry_log_debugsxp ("pubkey", key_public);
|
||||
gcry_sexp_release (key_public);
|
||||
key_public = NULL;
|
||||
xfree (cardsn);
|
||||
@ -2722,6 +2690,8 @@ ssh_handler_request_identities (ctrl_t ctrl,
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error ("ssh request identities failed: %s <%s>\n",
|
||||
gpg_strerror (err), gpg_strsource (err));
|
||||
ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
|
||||
}
|
||||
|
||||
@ -2751,7 +2721,7 @@ data_hash (unsigned char *data, size_t data_n,
|
||||
allow the use of signature algorithms that implement the hashing
|
||||
internally (e.g. Ed25519). On success the created signature is
|
||||
stored in ssh format at R_SIG and it's size at R_SIGLEN; the caller
|
||||
must use es_free to releaase this memory. */
|
||||
must use es_free to release this memory. */
|
||||
static gpg_error_t
|
||||
data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec,
|
||||
const void *hash, size_t hashlen,
|
||||
@ -3249,8 +3219,9 @@ ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
|
||||
while (1)
|
||||
{
|
||||
err = stream_read_byte (request, &b);
|
||||
if (gpg_err_code (err) == GPG_ERR_EOF)
|
||||
if (err)
|
||||
{
|
||||
if (gpg_err_code (err) == GPG_ERR_EOF)
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
@ -3625,7 +3596,7 @@ static void
|
||||
get_client_info (int fd, struct peer_info_s *out)
|
||||
{
|
||||
pid_t client_pid = (pid_t)(-1);
|
||||
uid_t client_uid = (uid_t)-1;
|
||||
int client_uid = -1;
|
||||
|
||||
#ifdef SO_PEERCRED
|
||||
{
|
||||
@ -3640,10 +3611,10 @@ get_client_info (int fd, struct peer_info_s *out)
|
||||
{
|
||||
#if defined (HAVE_STRUCT_SOCKPEERCRED_PID) || defined (HAVE_STRUCT_UCRED_PID)
|
||||
client_pid = cr.pid;
|
||||
client_uid = cr.uid;
|
||||
client_uid = (int)cr.uid;
|
||||
#elif defined (HAVE_STRUCT_UCRED_CR_PID)
|
||||
client_pid = cr.cr_pid;
|
||||
client_pid = cr.cr_uid;
|
||||
client_uid = (int)cr.cr_uid;
|
||||
#else
|
||||
#error "Unknown SO_PEERCRED struct"
|
||||
#endif
|
||||
@ -3660,7 +3631,7 @@ get_client_info (int fd, struct peer_info_s *out)
|
||||
len = sizeof (struct xucred);
|
||||
|
||||
if (!getsockopt (fd, SOL_LOCAL, LOCAL_PEERCRED, &cr, &len))
|
||||
client_uid = cr.cr_uid;
|
||||
client_uid = (int)cr.cr_uid;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -3670,8 +3641,10 @@ get_client_info (int fd, struct peer_info_s *out)
|
||||
socklen_t unpl = sizeof unp;
|
||||
|
||||
if (getsockopt (fd, 0, LOCAL_PEEREID, &unp, &unpl) != -1)
|
||||
{
|
||||
client_pid = unp.unp_pid;
|
||||
client_uid = unp.unp_euid;
|
||||
client_uid = (int)unp.unp_euid;
|
||||
}
|
||||
}
|
||||
#elif defined (HAVE_GETPEERUCRED)
|
||||
{
|
||||
@ -3680,7 +3653,7 @@ get_client_info (int fd, struct peer_info_s *out)
|
||||
if (getpeerucred (fd, &ucred) != -1)
|
||||
{
|
||||
client_pid = ucred_getpid (ucred);
|
||||
client_uid = ucred_geteuid (ucred);
|
||||
client_uid = (int)ucred_geteuid (ucred);
|
||||
ucred_free (ucred);
|
||||
}
|
||||
}
|
||||
@ -3689,7 +3662,7 @@ get_client_info (int fd, struct peer_info_s *out)
|
||||
#endif
|
||||
|
||||
out->pid = (client_pid == (pid_t)(-1)? 0 : (unsigned long)client_pid);
|
||||
out->uid = (int)client_uid;
|
||||
out->uid = client_uid;
|
||||
}
|
||||
|
||||
|
||||
|
111
agent/command.c
111
agent/command.c
@ -887,7 +887,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
int no_protection;
|
||||
unsigned char *value;
|
||||
unsigned char *value = NULL;
|
||||
size_t valuelen;
|
||||
unsigned char *newpasswd = NULL;
|
||||
membuf_t outbuf;
|
||||
@ -1595,19 +1595,24 @@ static const char hlp_clear_passphrase[] =
|
||||
"may be used to invalidate the cache entry for a passphrase. The\n"
|
||||
"function returns with OK even when there is no cached passphrase.\n"
|
||||
"The --mode=normal option is used to clear an entry for a cacheid\n"
|
||||
"added by the agent.\n";
|
||||
"added by the agent. The --mode=ssh option is used for a cacheid\n"
|
||||
"added for ssh.\n";
|
||||
static gpg_error_t
|
||||
cmd_clear_passphrase (assuan_context_t ctx, char *line)
|
||||
{
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
char *cacheid = NULL;
|
||||
char *p;
|
||||
int opt_normal;
|
||||
cache_mode_t cache_mode = CACHE_MODE_USER;
|
||||
|
||||
if (ctrl->restricted)
|
||||
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
||||
|
||||
opt_normal = has_option (line, "--mode=normal");
|
||||
if (has_option (line, "--mode=normal"))
|
||||
cache_mode = CACHE_MODE_NORMAL;
|
||||
else if (has_option (line, "--mode=ssh"))
|
||||
cache_mode = CACHE_MODE_SSH;
|
||||
|
||||
line = skip_options (line);
|
||||
|
||||
/* parse the stuff */
|
||||
@ -1620,12 +1625,9 @@ cmd_clear_passphrase (assuan_context_t ctx, char *line)
|
||||
if (!*cacheid || strlen (cacheid) > 50)
|
||||
return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
|
||||
|
||||
agent_put_cache (ctrl, cacheid,
|
||||
opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
|
||||
NULL, 0);
|
||||
agent_put_cache (ctrl, cacheid, cache_mode, NULL, 0);
|
||||
|
||||
agent_clear_passphrase (ctrl, cacheid,
|
||||
opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER);
|
||||
agent_clear_passphrase (ctrl, cacheid, cache_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2482,19 +2484,23 @@ cmd_delete_key (assuan_context_t ctx, char *line)
|
||||
#endif
|
||||
|
||||
static const char hlp_keytocard[] =
|
||||
"KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n"
|
||||
"\n";
|
||||
"KEYTOCARD [--force] <hexgrip> <serialno> <keyref> [<timestamp>]\n"
|
||||
"\n"
|
||||
"TIMESTAMP is required for OpenPGP and defaults to the Epoch. The\n"
|
||||
"SERIALNO is used for checking; use \"-\" to disable the check.";
|
||||
static gpg_error_t
|
||||
cmd_keytocard (assuan_context_t ctx, char *line)
|
||||
{
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
int force;
|
||||
gpg_error_t err = 0;
|
||||
char *argv[5];
|
||||
int argc;
|
||||
unsigned char grip[20];
|
||||
const char *serialno, *timestamp_str, *keyref;
|
||||
gcry_sexp_t s_skey = NULL;
|
||||
unsigned char *keydata;
|
||||
size_t keydatalen;
|
||||
const char *serialno, *timestamp_str, *id;
|
||||
unsigned char *shadow_info = NULL;
|
||||
time_t timestamp;
|
||||
|
||||
@ -2504,7 +2510,14 @@ cmd_keytocard (assuan_context_t ctx, char *line)
|
||||
force = has_option (line, "--force");
|
||||
line = skip_options (line);
|
||||
|
||||
err = parse_keygrip (ctx, line, grip);
|
||||
argc = split_fields (line, argv, DIM (argv));
|
||||
if (argc < 3)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = parse_keygrip (ctx, argv[0], grip);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
@ -2514,39 +2527,19 @@ cmd_keytocard (assuan_context_t ctx, char *line)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Fixme: Replace the parsing code by split_fields(). */
|
||||
line += 40;
|
||||
while (*line && (*line == ' ' || *line == '\t'))
|
||||
line++;
|
||||
serialno = line;
|
||||
while (*line && (*line != ' ' && *line != '\t'))
|
||||
line++;
|
||||
if (!*line)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
||||
goto leave;
|
||||
}
|
||||
*line = '\0';
|
||||
line++;
|
||||
while (*line && (*line == ' ' || *line == '\t'))
|
||||
line++;
|
||||
id = line;
|
||||
while (*line && (*line != ' ' && *line != '\t'))
|
||||
line++;
|
||||
if (!*line)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
||||
goto leave;
|
||||
}
|
||||
*line = '\0';
|
||||
line++;
|
||||
while (*line && (*line == ' ' || *line == '\t'))
|
||||
line++;
|
||||
timestamp_str = line;
|
||||
while (*line && (*line != ' ' && *line != '\t'))
|
||||
line++;
|
||||
if (*line)
|
||||
*line = '\0';
|
||||
/* Note that checking of the s/n is currently not implemented but we
|
||||
* want to provide a clean interface if we ever implement it. */
|
||||
serialno = argv[1];
|
||||
if (!strcmp (serialno, "-"))
|
||||
serialno = NULL;
|
||||
|
||||
keyref = argv[2];
|
||||
|
||||
/* FIXME: Default to the creation time as stored in the private
|
||||
* key. The parameter is here so that gpg can make sure that the
|
||||
* timestamp as used for key creation (and thus the openPGP
|
||||
* fingerprint) is used. */
|
||||
timestamp_str = argc > 3? argv[3] : "19700101T000000";
|
||||
|
||||
if ((timestamp = isotime2epoch (timestamp_str)) == (time_t)(-1))
|
||||
{
|
||||
@ -2558,38 +2551,37 @@ cmd_keytocard (assuan_context_t ctx, char *line)
|
||||
&shadow_info, CACHE_MODE_IGNORE, NULL,
|
||||
&s_skey, NULL);
|
||||
if (err)
|
||||
{
|
||||
xfree (shadow_info);
|
||||
goto leave;
|
||||
}
|
||||
if (shadow_info)
|
||||
{
|
||||
/* Key is on a smartcard already. */
|
||||
xfree (shadow_info);
|
||||
gcry_sexp_release (s_skey);
|
||||
/* Key is already on a smartcard - we can't extract it. */
|
||||
err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Note: We can't use make_canon_sexp because we need to allocate a
|
||||
* few extra bytes for our hack below. */
|
||||
keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||
keydata = xtrymalloc_secure (keydatalen + 30);
|
||||
if (keydata == NULL)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
gcry_sexp_release (s_skey);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
|
||||
gcry_sexp_release (s_skey);
|
||||
s_skey = NULL;
|
||||
keydatalen--; /* Decrement for last '\0'. */
|
||||
/* Add timestamp "created-at" in the private key */
|
||||
/* Hack to insert the timestamp "created-at" into the private key. */
|
||||
snprintf (keydata+keydatalen-1, 30, KEYTOCARD_TIMESTAMP_FORMAT, timestamp);
|
||||
keydatalen += 10 + 19 - 1;
|
||||
err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
|
||||
|
||||
err = divert_writekey (ctrl, force, serialno, keyref, keydata, keydatalen);
|
||||
xfree (keydata);
|
||||
|
||||
leave:
|
||||
gcry_sexp_release (s_skey);
|
||||
xfree (shadow_info);
|
||||
return leave_cmd (ctx, err);
|
||||
}
|
||||
|
||||
@ -2751,7 +2743,7 @@ cmd_put_secret (assuan_context_t ctx, char *line)
|
||||
* into a string. Instead of resorting to base64 encoding we use a
|
||||
* special percent escaping which only quoted the Nul and the
|
||||
* percent character. */
|
||||
string = percent_data_escape (value? value : valstr, valuelen);
|
||||
string = percent_data_escape (0, NULL, value? value : valstr, valuelen);
|
||||
if (!string)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
@ -3588,8 +3580,13 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
pid = assuan_get_pid (ctx);
|
||||
ctrl->client_uid = -1;
|
||||
#else
|
||||
pid = client_creds->pid;
|
||||
ctrl->client_uid = client_creds->uid;
|
||||
#endif
|
||||
}
|
||||
ctrl->client_pid = (pid == ASSUAN_INVALID_PID)? 0 : (unsigned long)pid;
|
||||
ctrl->server_local->connect_from_self = (pid == getpid ());
|
||||
|
@ -195,7 +195,7 @@ has_percent0A_suffix (const char *string)
|
||||
string with the passphrase, the buffer may optionally be padded
|
||||
with arbitrary characters.
|
||||
|
||||
If DESC_TEXT is not NULL it can be used as further informtion shown
|
||||
If DESC_TEXT is not NULL it can be used as further information shown
|
||||
atop of the INFO message.
|
||||
|
||||
INFO gets displayed as part of a generic string. However if the
|
||||
@ -278,25 +278,47 @@ getpin_cb (void *opaque, const char *desc_text, const char *info,
|
||||
{
|
||||
if (info)
|
||||
{
|
||||
char *desc, *desc2;
|
||||
char *desc;
|
||||
const char *desc2;
|
||||
|
||||
if ( asprintf (&desc,
|
||||
L_("%s%%0A%%0AUse the reader's pinpad for input."),
|
||||
info) < 0 )
|
||||
if (!strcmp (info, "--ack"))
|
||||
{
|
||||
desc2 = L_("Push ACK button on card/token.");
|
||||
|
||||
if (desc_text)
|
||||
{
|
||||
desc = strconcat (desc_text,
|
||||
has_percent0A_suffix (desc_text)
|
||||
? "%0A" : "%0A%0A",
|
||||
desc2, NULL);
|
||||
desc2 = NULL;
|
||||
}
|
||||
else
|
||||
desc = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc2 = NULL;
|
||||
|
||||
if (desc_text)
|
||||
desc = strconcat (desc_text,
|
||||
has_percent0A_suffix (desc_text)
|
||||
? "%0A" : "%0A%0A",
|
||||
info, "%0A%0A",
|
||||
L_("Use the reader's pinpad for input."),
|
||||
NULL);
|
||||
else
|
||||
desc = strconcat (info, "%0A%0A",
|
||||
L_("Use the reader's pinpad for input."),
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!desc2 && !desc)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
/* Prepend DESC_TEXT to INFO. */
|
||||
if (desc_text)
|
||||
desc2 = strconcat (desc_text,
|
||||
has_percent0A_suffix (desc_text)
|
||||
? "%0A" : "%0A%0A",
|
||||
desc, NULL);
|
||||
else
|
||||
desc2 = NULL;
|
||||
rc = agent_popup_message_start (ctrl,
|
||||
desc2? desc2:desc, NULL);
|
||||
xfree (desc2);
|
||||
xfree (desc);
|
||||
}
|
||||
}
|
||||
@ -476,6 +498,7 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
char *kid;
|
||||
const unsigned char *s;
|
||||
size_t n;
|
||||
int depth;
|
||||
const unsigned char *ciphertext;
|
||||
size_t ciphertextlen;
|
||||
char *plaintext;
|
||||
@ -484,7 +507,6 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
(void)desc_text;
|
||||
|
||||
*r_padding = -1;
|
||||
|
||||
s = cipher;
|
||||
if (*s != '(')
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
@ -500,6 +522,21 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
|
||||
/* First check whether we have a flags parameter and skip it. */
|
||||
if (smatch (&s, n, "flags"))
|
||||
{
|
||||
depth = 1;
|
||||
if (sskip (&s, &depth) || depth)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
if (*s != '(')
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
|
||||
if (smatch (&s, n, "rsa"))
|
||||
{
|
||||
if (*s != '(')
|
||||
@ -560,12 +597,13 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
gpg_error_t
|
||||
divert_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||
const char *id, const char *keydata, size_t keydatalen)
|
||||
const char *keyref, const char *keydata, size_t keydatalen)
|
||||
{
|
||||
return agent_card_writekey (ctrl, force, serialno, id, keydata, keydatalen,
|
||||
getpin_cb, ctrl);
|
||||
return agent_card_writekey (ctrl, force, serialno, keyref,
|
||||
keydata, keydatalen, getpin_cb, ctrl);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -632,7 +632,17 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
|
||||
pi->check_cb_arg = &arg;
|
||||
|
||||
rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi, hexgrip, cache_mode);
|
||||
if (!rc)
|
||||
if (rc)
|
||||
{
|
||||
if ((pi->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||
{
|
||||
log_error ("Clearing pinentry cache which caused error %s\n",
|
||||
gpg_strerror (rc));
|
||||
|
||||
agent_clear_passphrase (ctrl, hexgrip, cache_mode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (arg.unprotected_key);
|
||||
if (arg.change_required)
|
||||
|
@ -112,6 +112,7 @@ enum cmd_and_opt_values
|
||||
oCheckPassphrasePattern,
|
||||
oMaxPassphraseDays,
|
||||
oEnablePassphraseHistory,
|
||||
oDisableExtendedKeyFormat,
|
||||
oEnableExtendedKeyFormat,
|
||||
oUseStandardSocket,
|
||||
oNoUseStandardSocket,
|
||||
@ -135,10 +136,13 @@ enum cmd_and_opt_values
|
||||
oDisableScdaemon,
|
||||
oDisableCheckOwnSocket,
|
||||
oS2KCount,
|
||||
oS2KCalibration,
|
||||
oAutoExpandSecmem,
|
||||
oListenBacklog,
|
||||
|
||||
oWriteEnvFile
|
||||
oWriteEnvFile,
|
||||
|
||||
oNoop
|
||||
};
|
||||
|
||||
|
||||
@ -250,9 +254,11 @@ static ARGPARSE_OPTS opts[] = {
|
||||
/* */ "@"
|
||||
#endif
|
||||
),
|
||||
ARGPARSE_s_n (oDisableExtendedKeyFormat, "disable-extended-key-format", "@"),
|
||||
ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"),
|
||||
|
||||
ARGPARSE_s_u (oS2KCount, "s2k-count", "@"),
|
||||
ARGPARSE_s_u (oS2KCalibration, "s2k-calibration", "@"),
|
||||
|
||||
ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"),
|
||||
|
||||
@ -263,6 +269,9 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_n (oUseStandardSocket, "use-standard-socket", "@"),
|
||||
ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
|
||||
|
||||
/* Dummy options. */
|
||||
|
||||
|
||||
ARGPARSE_end () /* End of list */
|
||||
};
|
||||
|
||||
@ -823,7 +832,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
||||
opt.check_passphrase_pattern = NULL;
|
||||
opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
|
||||
opt.enable_passphrase_history = 0;
|
||||
opt.enable_extended_key_format = 0;
|
||||
opt.enable_extended_key_format = 1;
|
||||
opt.ignore_cache_for_signing = 0;
|
||||
opt.allow_mark_trusted = 1;
|
||||
opt.allow_external_cache = 1;
|
||||
@ -834,6 +843,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
||||
/* Note: When changing the next line, change also gpgconf_list. */
|
||||
opt.ssh_fingerprint_digest = GCRY_MD_MD5;
|
||||
opt.s2k_count = 0;
|
||||
set_s2k_calibration_time (0); /* Set to default. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -851,7 +861,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
||||
|
||||
case oLogFile:
|
||||
if (!reread)
|
||||
return 0; /* not handeld */
|
||||
return 0; /* not handled */
|
||||
if (!current_logfile || !pargs->r.ret_str
|
||||
|| strcmp (current_logfile, pargs->r.ret_str))
|
||||
{
|
||||
@ -898,7 +908,11 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
||||
break;
|
||||
|
||||
case oEnableExtendedKeyFormat:
|
||||
opt.enable_extended_key_format = 1;
|
||||
opt.enable_extended_key_format = 2;
|
||||
break;
|
||||
case oDisableExtendedKeyFormat:
|
||||
if (opt.enable_extended_key_format != 2)
|
||||
opt.enable_extended_key_format = 0;
|
||||
break;
|
||||
|
||||
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
|
||||
@ -929,6 +943,12 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
||||
opt.s2k_count = pargs->r.ret_ulong;
|
||||
break;
|
||||
|
||||
case oS2KCalibration:
|
||||
set_s2k_calibration_time (pargs->r.ret_ulong);
|
||||
break;
|
||||
|
||||
case oNoop: break;
|
||||
|
||||
default:
|
||||
return 0; /* not handled */
|
||||
}
|
||||
@ -1444,8 +1464,6 @@ main (int argc, char **argv )
|
||||
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
||||
es_printf ("pinentry-timeout:%lu:0:\n",
|
||||
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
|
||||
es_printf ("enable-extended-key-format:%lu:\n",
|
||||
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
||||
es_printf ("grab:%lu:\n",
|
||||
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
||||
|
||||
@ -1768,7 +1786,7 @@ main (int argc, char **argv )
|
||||
|
||||
/* 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 tye regular stat calls. */
|
||||
* we can avoid the regular stat calls. */
|
||||
if (!argc)
|
||||
reliable_homedir_inotify = 1;
|
||||
}
|
||||
@ -2108,7 +2126,7 @@ get_agent_scd_notify_event (void)
|
||||
GetCurrentProcess(), &h2,
|
||||
EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
|
||||
{
|
||||
log_error ("setting syncronize for scd notify event failed: %s\n",
|
||||
log_error ("setting synchronize for scd notify event failed: %s\n",
|
||||
w32_strerror (-1) );
|
||||
CloseHandle (h);
|
||||
}
|
||||
@ -2370,9 +2388,6 @@ handle_tick (void)
|
||||
if (!last_minute)
|
||||
last_minute = time (NULL);
|
||||
|
||||
/* Check whether the scdaemon has died and cleanup in this case. */
|
||||
agent_scd_check_aliveness ();
|
||||
|
||||
/* 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
|
||||
|
@ -234,7 +234,7 @@ The currently defined protection modes are:
|
||||
(csum n)
|
||||
(protection PROTTYPE PROTALGO IV S2KMODE S2KHASH S2KSALT S2KCOUNT)))
|
||||
|
||||
Note that the public key paramaters in SKEY are duplicated and
|
||||
Note that the public key parameters in SKEY are duplicated and
|
||||
should be identical to their copies in the standard parameter
|
||||
elements. Here is an example of an entire protected private key
|
||||
using this format:
|
||||
@ -359,8 +359,8 @@ KEY_1 to KEY_N are unique identifiers for the shared secret, for
|
||||
example an URI. In case this information should be kept confidential
|
||||
as well, they may not appear in the unprotected part; however they are
|
||||
mandatory in the encrypted_octet_string. The list of keywords is
|
||||
optional. The oder of the "key" lists and the order of the "value"
|
||||
lists mut match, that is the first "key"-list is associated with the
|
||||
optional. The order of the "key" lists and the order of the "value"
|
||||
lists must match, that is the first "key"-list is associated with the
|
||||
first "value" list in the encrypted_octet_string.
|
||||
|
||||
The protection mode etc. is identical to the protection mode as
|
||||
|
@ -40,7 +40,7 @@ struct keypair_info_s
|
||||
char hexgrip[1]; /* The keygrip (i.e. a hash over the public key
|
||||
parameters) formatted as a hex string.
|
||||
Allocated somewhat large to also act as
|
||||
memeory for the above ID field. */
|
||||
memory for the above ID field. */
|
||||
};
|
||||
typedef struct keypair_info_s *KEYPAIR_INFO;
|
||||
|
||||
|
@ -367,20 +367,29 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
||||
|
||||
if (is_RSA)
|
||||
{
|
||||
check_signature = 1;
|
||||
if (*buf & 0x80)
|
||||
{
|
||||
len++;
|
||||
buf = xtryrealloc (buf, len);
|
||||
if (!buf)
|
||||
goto leave;
|
||||
unsigned char *p = buf;
|
||||
|
||||
memmove (buf + 1, buf, len - 1);
|
||||
*buf = 0;
|
||||
check_signature = 1;
|
||||
|
||||
/*
|
||||
* Smartcard returns fixed-size data, which is good for
|
||||
* PKCS1. If variable-size unsigned MPI is needed, remove
|
||||
* zeros.
|
||||
*/
|
||||
if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1
|
||||
|| ctrl->digest.raw_value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len - 1; i++)
|
||||
if (p[i])
|
||||
break;
|
||||
p += i;
|
||||
len -= i;
|
||||
}
|
||||
|
||||
err = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))",
|
||||
(int)len, buf);
|
||||
(int)len, p);
|
||||
}
|
||||
else if (is_EdDSA)
|
||||
{
|
||||
@ -389,53 +398,34 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
||||
}
|
||||
else if (is_ECDSA)
|
||||
{
|
||||
unsigned char *r_buf_allocated = NULL;
|
||||
unsigned char *s_buf_allocated = NULL;
|
||||
unsigned char *r_buf, *s_buf;
|
||||
int r_buflen, s_buflen;
|
||||
int i;
|
||||
|
||||
r_buflen = s_buflen = len/2;
|
||||
|
||||
if (*buf & 0x80)
|
||||
{
|
||||
r_buflen++;
|
||||
r_buf_allocated = xtrymalloc (r_buflen);
|
||||
if (!r_buf_allocated)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
r_buf = r_buf_allocated;
|
||||
memcpy (r_buf + 1, buf, len/2);
|
||||
*r_buf = 0;
|
||||
}
|
||||
else
|
||||
/*
|
||||
* Smartcard returns fixed-size data. For ECDSA signature,
|
||||
* variable-size unsigned MPI is assumed, thus, remove
|
||||
* zeros.
|
||||
*/
|
||||
r_buf = buf;
|
||||
for (i = 0; i < r_buflen - 1; i++)
|
||||
if (r_buf[i])
|
||||
break;
|
||||
r_buf += i;
|
||||
r_buflen -= i;
|
||||
|
||||
if (*(buf + len/2) & 0x80)
|
||||
{
|
||||
s_buflen++;
|
||||
s_buf_allocated = xtrymalloc (s_buflen);
|
||||
if (!s_buf_allocated)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
xfree (r_buf_allocated);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
s_buf = s_buf_allocated;
|
||||
memcpy (s_buf + 1, buf + len/2, len/2);
|
||||
*s_buf = 0;
|
||||
}
|
||||
else
|
||||
s_buf = buf + len/2;
|
||||
for (i = 0; i < s_buflen - 1; i++)
|
||||
if (s_buf[i])
|
||||
break;
|
||||
s_buf += i;
|
||||
s_buflen -= i;
|
||||
|
||||
err = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))",
|
||||
r_buflen, r_buf,
|
||||
s_buflen, s_buf);
|
||||
xfree (r_buf_allocated);
|
||||
xfree (s_buf_allocated);
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "cvt-openpgp.h"
|
||||
#include "../common/sexp-parse.h"
|
||||
#include "../common/openpgpdefs.h" /* For s2k functions. */
|
||||
|
||||
|
||||
/* The protection mode for encryption. The supported modes for
|
||||
@ -49,9 +50,6 @@
|
||||
#define PROT_CIPHER_STRING "aes"
|
||||
#define PROT_CIPHER_KEYLEN (128/8)
|
||||
|
||||
/* Decode an rfc4880 encoded S2K count. */
|
||||
#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6))
|
||||
|
||||
|
||||
/* A table containing the information needed to create a protected
|
||||
private key. */
|
||||
@ -71,6 +69,13 @@ static const struct {
|
||||
};
|
||||
|
||||
|
||||
/* The number of milliseconds we use in the S2K function and the
|
||||
* calibrated count value. A count value of zero indicates that the
|
||||
* calibration has not yet been done or needs to be done again. */
|
||||
static unsigned int s2k_calibration_time = AGENT_S2K_CALIBRATION;
|
||||
static unsigned long s2k_calibrated_count;
|
||||
|
||||
|
||||
/* A helper object for time measurement. */
|
||||
struct calibrate_time_s
|
||||
{
|
||||
@ -175,11 +180,11 @@ calibrate_s2k_count (void)
|
||||
ms = calibrate_s2k_count_one (count);
|
||||
if (opt.verbose > 1)
|
||||
log_info ("S2K calibration: %lu -> %lums\n", count, ms);
|
||||
if (ms > AGENT_S2K_CALIBRATION)
|
||||
if (ms > s2k_calibration_time)
|
||||
break;
|
||||
}
|
||||
|
||||
count = (unsigned long)(((double)count / ms) * AGENT_S2K_CALIBRATION);
|
||||
count = (unsigned long)(((double)count / ms) * s2k_calibration_time);
|
||||
count /= 1024;
|
||||
count *= 1024;
|
||||
if (count < 65536)
|
||||
@ -195,18 +200,30 @@ calibrate_s2k_count (void)
|
||||
}
|
||||
|
||||
|
||||
/* Set the calibration time. This may be called early at startup or
|
||||
* at any time. Thus it should one set variables. */
|
||||
void
|
||||
set_s2k_calibration_time (unsigned int milliseconds)
|
||||
{
|
||||
if (!milliseconds)
|
||||
milliseconds = AGENT_S2K_CALIBRATION;
|
||||
else if (milliseconds > 60 * 1000)
|
||||
milliseconds = 60 * 1000; /* Cap at 60 seconds. */
|
||||
s2k_calibration_time = milliseconds;
|
||||
s2k_calibrated_count = 0; /* Force re-calibration. */
|
||||
}
|
||||
|
||||
|
||||
/* Return the calibrated S2K count. This is only public for the use
|
||||
* of the Assuan getinfo s2k_count_cal command. */
|
||||
unsigned long
|
||||
get_calibrated_s2k_count (void)
|
||||
{
|
||||
static unsigned long count;
|
||||
|
||||
if (!count)
|
||||
count = calibrate_s2k_count ();
|
||||
if (!s2k_calibrated_count)
|
||||
s2k_calibrated_count = calibrate_s2k_count ();
|
||||
|
||||
/* Enforce a lower limit. */
|
||||
return count < 65536 ? 65536 : count;
|
||||
return s2k_calibrated_count < 65536 ? 65536 : s2k_calibrated_count;
|
||||
}
|
||||
|
||||
|
||||
@ -606,7 +623,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||
int have_curve = 0;
|
||||
|
||||
if (use_ocb == -1)
|
||||
use_ocb = opt.enable_extended_key_format;
|
||||
use_ocb = !!opt.enable_extended_key_format;
|
||||
|
||||
/* Create an S-expression with the protected-at timestamp. */
|
||||
memcpy (timestamp_exp, "(12:protected-at15:", 19);
|
||||
@ -1109,7 +1126,7 @@ agent_unprotect (ctrl_t ctrl,
|
||||
if (!protect_info[infidx].algo)
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||
|
||||
/* See wether we have a protected-at timestamp. */
|
||||
/* See whether we have a protected-at timestamp. */
|
||||
protect_list = s; /* Save for later. */
|
||||
if (protected_at)
|
||||
{
|
||||
|
10
autogen.rc
10
autogen.rc
@ -17,25 +17,15 @@ esac
|
||||
case "$myhost" in
|
||||
w32)
|
||||
configure_opts="
|
||||
--with-gpg-error-prefix=@SYSROOT@
|
||||
--with-ksba-prefix=@SYSROOT@
|
||||
--with-libgcrypt-prefix=@SYSROOT@
|
||||
--with-libassuan-prefix=@SYSROOT@
|
||||
--with-zlib=@SYSROOT@
|
||||
--with-regex=@SYSROOT@
|
||||
--with-npth-prefix=@SYSROOT@
|
||||
--disable-g13
|
||||
"
|
||||
;;
|
||||
|
||||
amd64)
|
||||
configure_opts="
|
||||
--with-gpg-error-prefix=@SYSROOT@
|
||||
--with-ksba-prefix=@SYSROOT@
|
||||
--with-libgcrypt-prefix=@SYSROOT@
|
||||
--with-libassuan-prefix=@SYSROOT@
|
||||
--with-zlib=/usr/x86_64-linux-gnu/usr
|
||||
--with-pth-prefix=/usr/x86_64-linux-gnu/usr
|
||||
"
|
||||
;;
|
||||
esac
|
||||
|
@ -157,8 +157,9 @@ INST_NAME=gnupg-w32
|
||||
# Use this to override the installaion directory for native builds.
|
||||
INSTALL_PREFIX=none
|
||||
|
||||
# The Authenticode key used to sign the Windows installer
|
||||
# The Authenticode key and cert chain used to sign the Windows installer
|
||||
AUTHENTICODE_KEY=${HOME}/.gnupg/g10code-authenticode-key.p12
|
||||
AUTHENTICODE_CERTS=${HOME}/.gnupg/g10code-authenticode-certs.pem
|
||||
|
||||
|
||||
# Directory names.
|
||||
@ -520,12 +521,12 @@ endif
|
||||
# The LDFLAGS is needed for -lintl for glib.
|
||||
ifeq ($(WITH_GUI),1)
|
||||
speedo_pkg_gpgme_configure = \
|
||||
--enable-static --enable-w32-glib --disable-w32-qt \
|
||||
--enable-static --enable-w32-glib \
|
||||
--with-gpg-error-prefix=$(idir) \
|
||||
LDFLAGS=-L$(idir)/lib
|
||||
else
|
||||
speedo_pkg_gpgme_configure = \
|
||||
--disable-static --disable-w32-glib --disable-w32-qt \
|
||||
--disable-static --disable-w32-glib \
|
||||
--with-gpg-error-prefix=$(idir) \
|
||||
LDFLAGS=-L$(idir)/lib
|
||||
endif
|
||||
@ -970,7 +971,7 @@ else
|
||||
endif
|
||||
@touch $(stampdir)/stamp-$(1)-01-configure
|
||||
|
||||
# Note that unpack has no 64 bit version becuase it is just the source.
|
||||
# Note that unpack has no 64 bit version because it is just the source.
|
||||
# Fixme: We should use templates to create the standard and w64
|
||||
# version of these rules.
|
||||
$(stampdir)/stamp-w64-$(1)-01-configure: $(stampdir)/stamp-$(1)-00-unpack
|
||||
@ -1142,7 +1143,7 @@ all-speedo: $(stampdir)/stamp-final
|
||||
|
||||
report-speedo: $(addprefix report-,$(speedo_build_list))
|
||||
|
||||
# Just to check if we catched all stamps.
|
||||
# Just to check if we caught all stamps.
|
||||
clean-stamps:
|
||||
$(RM) -fR $(stampdir)
|
||||
|
||||
@ -1211,7 +1212,9 @@ extra_installer_options += -DWITH_GUI=1
|
||||
endif
|
||||
|
||||
installer: all w32_insthelpers $(w32src)/inst-options.ini $(bdir)/README.txt
|
||||
$(MAKENSIS) -V2 \
|
||||
(nsis3_args=$$(makensis -version | grep -q "^v3" && \
|
||||
echo "-INPUTCHARSET CP1252"); \
|
||||
$(MAKENSIS) -V2 $$nsis3_args \
|
||||
-DINST_DIR=$(idir) \
|
||||
-DINST6_DIR=$(idir6) \
|
||||
-DBUILD_DIR=$(bdir) \
|
||||
@ -1222,7 +1225,7 @@ installer: all w32_insthelpers $(w32src)/inst-options.ini $(bdir)/README.txt
|
||||
-DNAME=$(INST_NAME) \
|
||||
-DVERSION=$(INST_VERSION) \
|
||||
-DPROD_VERSION=$(INST_PROD_VERSION) \
|
||||
$(extra_installer_options) $(w32src)/inst.nsi
|
||||
$(extra_installer_options) $(w32src)/inst.nsi)
|
||||
@echo "Ready: $(idir)/$(INST_NAME)-$(INST_VERSION)_$(BUILD_DATESTR).exe"
|
||||
|
||||
|
||||
@ -1266,8 +1269,11 @@ sign-installer:
|
||||
echo "speedo: * Signing installer" ;\
|
||||
echo "speedo: * Key: $(AUTHENTICODE_KEY)";\
|
||||
echo "speedo: */" ;\
|
||||
osslsigncode sign -pkcs12 $(AUTHENTICODE_KEY) -askpass \
|
||||
-h sha256 -in "PLAY/inst/$$exefile" -out "../../$$exefile" ;\
|
||||
osslsigncode sign -certs $(AUTHENTICODE_CERTS)\
|
||||
-pkcs12 $(AUTHENTICODE_KEY) -askpass \
|
||||
-ts "http://timestamp.globalsign.com/scripts/timstamp.dll" \
|
||||
-h sha256 -n GnuPG -i https://gnupg.org \
|
||||
-in "PLAY/inst/$$exefile" -out "../../$$exefile" ;\
|
||||
exefile="../../$$exefile" ;\
|
||||
$(call MKSWDB_commands,$${exefile},$${reldate}); \
|
||||
echo "speedo: /*" ;\
|
||||
@ -1283,7 +1289,7 @@ endif
|
||||
|
||||
|
||||
#
|
||||
# Check availibility of standard tools
|
||||
# Check availability of standard tools
|
||||
#
|
||||
check-tools:
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
% Load plain if necessary, i.e., if running under initex.
|
||||
\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
|
||||
%
|
||||
\def\texinfoversion{2007-05-03.09}
|
||||
\def\texinfoversion{2018-10-25.16}
|
||||
%
|
||||
% Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
|
||||
% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||||
@ -4598,7 +4598,7 @@ end
|
||||
\chardef\maxseclevel = 3
|
||||
%
|
||||
% A numbered section within an unnumbered changes to unnumbered too.
|
||||
% To achive this, remember the "biggest" unnum. sec. we are currently in:
|
||||
% To achieve this, remember the "biggest" unnum. sec. we are currently in:
|
||||
\chardef\unmlevel = \maxseclevel
|
||||
%
|
||||
% Trace whether the current chapter is an appendix or not:
|
||||
|
@ -83,7 +83,7 @@ common_sources = \
|
||||
localename.c \
|
||||
session-env.c session-env.h \
|
||||
userids.c userids.h \
|
||||
openpgp-oid.c \
|
||||
openpgp-oid.c openpgp-s2k.c \
|
||||
ssh-utils.c ssh-utils.h \
|
||||
agent-opt.c \
|
||||
helpfile.c \
|
||||
|
@ -408,7 +408,7 @@ static void
|
||||
store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
|
||||
{
|
||||
/* TODO: replace this dummy function with a rea one
|
||||
* and fix the probelms IRIX has with (ALIAS_DEV)arg..
|
||||
* and fix the problems IRIX has with (ALIAS_DEV)arg..
|
||||
* used as lvalue
|
||||
*/
|
||||
(void)arg;
|
||||
@ -439,7 +439,7 @@ ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword)
|
||||
|
||||
/* Add the keywords up to the next LF to the list of to be ignored
|
||||
options. After returning FP will either be at EOF or the next
|
||||
character read wll be the first of a new line. The function
|
||||
character read will be the first of a new line. The function
|
||||
returns 0 on success or true on malloc failure. */
|
||||
static int
|
||||
ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
|
||||
@ -1280,7 +1280,7 @@ long_opt_strlen( ARGPARSE_OPTS *o )
|
||||
* this option
|
||||
* - a description,ine which starts with a '@' and is followed by
|
||||
* any other characters is printed as is; this may be used for examples
|
||||
* ans such.
|
||||
* and such.
|
||||
* - A description which starts with a '|' outputs the string between this
|
||||
* bar and the next one as arguments of the long option.
|
||||
*/
|
||||
|
@ -185,7 +185,7 @@ typedef enum
|
||||
if no real recipient has been given. */
|
||||
|
||||
AUDIT_SESSION_KEY, /* string */
|
||||
/* Mark the creation or availibility of the session key. The
|
||||
/* Mark the creation or availability of the session key. The
|
||||
parameter is the algorithm ID. */
|
||||
|
||||
AUDIT_ENCRYPTED_TO, /* cert, err */
|
||||
|
@ -177,7 +177,7 @@ bin2hexcolon (const void *buffer, size_t length, char *stringbuf)
|
||||
string or a white space character. The function makes sure that
|
||||
the resulting string in BUFFER is terminated by a Nul byte. Note
|
||||
that the returned string may include embedded Nul bytes; the extra
|
||||
Nul byte at the end is used to make sure tha the result can always
|
||||
Nul byte at the end is used to make sure that the result can always
|
||||
be used as a C-string.
|
||||
|
||||
BUFSIZE is the available length of BUFFER; if the converted result
|
||||
|
@ -140,7 +140,7 @@
|
||||
you pass (0) instead of (-1) the function does not wait in case the
|
||||
file is already locked but returns -1 and sets ERRNO to EACCES.
|
||||
Any other positive value for the second parameter is considered a
|
||||
timeout valuie in milliseconds.
|
||||
timeout value in milliseconds.
|
||||
|
||||
To release the lock you call:
|
||||
|
||||
|
@ -53,6 +53,7 @@ typedef struct
|
||||
exec_tool_status_cb_t status_cb;
|
||||
void *status_cb_value;
|
||||
int cont;
|
||||
int quiet;
|
||||
size_t used;
|
||||
size_t buffer_size;
|
||||
char *buffer;
|
||||
@ -110,6 +111,8 @@ read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
|
||||
state->status_cb (state->status_cb_value,
|
||||
state->buffer + 9, rest);
|
||||
}
|
||||
else if (state->quiet)
|
||||
;
|
||||
else if (!state->cont
|
||||
&& !strncmp (state->buffer, pname, len)
|
||||
&& strlen (state->buffer) > strlen (pname)
|
||||
@ -331,10 +334,16 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
int count;
|
||||
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);
|
||||
|
||||
/* If the first argument to the program is "--quiet" avoid all extra
|
||||
* diagnostics. */
|
||||
quiet = (argv && argv[0] && !strcmp (argv[0], "--quiet"));
|
||||
|
||||
cpbuf_in = xtrymalloc (sizeof *cpbuf_in);
|
||||
if (cpbuf_in == NULL)
|
||||
{
|
||||
@ -360,6 +369,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
copy_buffer_init (cpbuf_extra);
|
||||
|
||||
fderrstate.pgmname = pgmname;
|
||||
fderrstate.quiet = quiet;
|
||||
fderrstate.status_cb = status_cb;
|
||||
fderrstate.status_cb_value = status_cb_value;
|
||||
fderrstate.buffer_size = 256;
|
||||
@ -375,7 +385,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error running outbound pipe for extra fp: %s\n",
|
||||
log_error ("error creating outbound pipe for extra fp: %s\n",
|
||||
gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
@ -411,6 +421,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
argv[argsaveidx] = argsave;
|
||||
if (err)
|
||||
{
|
||||
if (!quiet)
|
||||
log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
@ -535,7 +546,7 @@ 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, NULL);
|
||||
err = gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
|
||||
pid = (pid_t)(-1);
|
||||
|
||||
leave:
|
||||
@ -547,7 +558,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
es_fclose (outfp);
|
||||
es_fclose (errfp);
|
||||
if (pid != (pid_t)(-1))
|
||||
gnupg_wait_process (pgmname, pid, 1, NULL);
|
||||
gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
|
||||
gnupg_release_process (pid);
|
||||
|
||||
copy_buffer_shred (cpbuf_in);
|
||||
|
@ -68,8 +68,8 @@
|
||||
|
||||
/*-- End configurable part. --*/
|
||||
|
||||
/* The size of the iobuffers. This can be chnages using the
|
||||
* iobuf_set_buffer_size fucntion. */
|
||||
/* The size of the iobuffers. This can be changed using the
|
||||
* iobuf_set_buffer_size function. */
|
||||
static unsigned int iobuf_buffer_size = DEFAULT_IOBUF_BUFFER_SIZE;
|
||||
|
||||
|
||||
@ -878,9 +878,9 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
|
||||
}
|
||||
else if (c == 255)
|
||||
{
|
||||
a->size = (size_t)iobuf_get (chain) << 24;
|
||||
a->size |= iobuf_get (chain) << 16;
|
||||
a->size |= iobuf_get (chain) << 8;
|
||||
a->size = iobuf_get_noeof (chain) << 24;
|
||||
a->size |= iobuf_get_noeof (chain) << 16;
|
||||
a->size |= iobuf_get_noeof (chain) << 8;
|
||||
if ((c = iobuf_get (chain)) == -1)
|
||||
{
|
||||
log_error ("block_filter: invalid 4 byte length\n");
|
||||
@ -2262,6 +2262,7 @@ iobuf_copy (iobuf_t dest, iobuf_t source)
|
||||
|
||||
size_t nread;
|
||||
size_t nwrote = 0;
|
||||
size_t max_read = 0;
|
||||
int err;
|
||||
|
||||
assert (source->use == IOBUF_INPUT || source->use == IOBUF_INPUT_TEMP);
|
||||
@ -2278,6 +2279,9 @@ iobuf_copy (iobuf_t dest, iobuf_t source)
|
||||
/* EOF. */
|
||||
break;
|
||||
|
||||
if (nread > max_read)
|
||||
max_read = nread;
|
||||
|
||||
err = iobuf_write (dest, temp, nread);
|
||||
if (err)
|
||||
break;
|
||||
@ -2285,7 +2289,8 @@ iobuf_copy (iobuf_t dest, iobuf_t source)
|
||||
}
|
||||
|
||||
/* Burn the buffer. */
|
||||
wipememory (temp, sizeof (temp));
|
||||
if (max_read)
|
||||
wipememory (temp, max_read);
|
||||
xfree (temp);
|
||||
|
||||
return nwrote;
|
||||
@ -2610,12 +2615,50 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
|
||||
}
|
||||
|
||||
p = buffer;
|
||||
while ((c = iobuf_get (a)) != -1)
|
||||
while (1)
|
||||
{
|
||||
if (!a->nofast && a->d.start < a->d.len && nbytes < length - 1)
|
||||
/* Fast path for finding '\n' by using standard C library's optimized
|
||||
memchr. */
|
||||
{
|
||||
unsigned size = a->d.len - a->d.start;
|
||||
byte *newline_pos;
|
||||
|
||||
if (size > length - 1 - nbytes)
|
||||
size = length - 1 - nbytes;
|
||||
|
||||
newline_pos = memchr (a->d.buf + a->d.start, '\n', size);
|
||||
if (newline_pos)
|
||||
{
|
||||
/* Found newline, copy buffer and return. */
|
||||
size = (newline_pos - (a->d.buf + a->d.start)) + 1;
|
||||
memcpy (p, a->d.buf + a->d.start, size);
|
||||
p += size;
|
||||
nbytes += size;
|
||||
a->d.start += size;
|
||||
a->nbytes += size;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No newline, copy buffer and continue. */
|
||||
memcpy (p, a->d.buf + a->d.start, size);
|
||||
p += size;
|
||||
nbytes += size;
|
||||
a->d.start += size;
|
||||
a->nbytes += size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
c = iobuf_readbyte (a);
|
||||
if (c == -1)
|
||||
break;
|
||||
*p++ = c;
|
||||
nbytes++;
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
if (nbytes == length - 1)
|
||||
/* We don't have enough space to add a \n and a \0. Increase
|
||||
|
@ -173,11 +173,12 @@ is_valid_mailbox (const char *name)
|
||||
|
||||
|
||||
/* Return the mailbox (local-part@domain) form a standard user id.
|
||||
All plain ASCII characters in the result are converted to
|
||||
lowercase. Caller must free the result. Returns NULL if no valid
|
||||
mailbox was found (or we are out of memory). */
|
||||
* All plain ASCII characters in the result are converted to
|
||||
* lowercase. If SUBADDRESS is 1, '+' denoted sub-addresses are not
|
||||
* included in the result. Caller must free the result. Returns NULL
|
||||
* if no valid mailbox was found (or we are out of memory). */
|
||||
char *
|
||||
mailbox_from_userid (const char *userid)
|
||||
mailbox_from_userid (const char *userid, int subaddress)
|
||||
{
|
||||
const char *s, *s_end;
|
||||
size_t len;
|
||||
@ -226,6 +227,29 @@ mailbox_from_userid (const char *userid)
|
||||
else
|
||||
errno = EINVAL;
|
||||
|
||||
if (result && subaddress == 1)
|
||||
{
|
||||
char *atsign, *plus;
|
||||
|
||||
if ((atsign = strchr (result, '@')))
|
||||
{
|
||||
/* We consider a subaddress only if there is a single '+'
|
||||
* in the local part and the '+' is not the first or last
|
||||
* character. */
|
||||
*atsign = 0;
|
||||
if ((plus = strchr (result, '+'))
|
||||
&& !strchr (plus+1, '+')
|
||||
&& result != plus
|
||||
&& plus[1] )
|
||||
{
|
||||
*atsign = '@';
|
||||
memmove (plus, atsign, strlen (atsign)+1);
|
||||
}
|
||||
else
|
||||
*atsign = '@';
|
||||
}
|
||||
}
|
||||
|
||||
return result? ascii_strlwr (result): NULL;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
int has_invalid_email_chars (const void *buffer, size_t length);
|
||||
int is_valid_mailbox (const char *name);
|
||||
int is_valid_mailbox_mem (const void *buffer, size_t length);
|
||||
char *mailbox_from_userid (const char *userid);
|
||||
char *mailbox_from_userid (const char *userid, int subaddress);
|
||||
int is_valid_user_id (const char *uid);
|
||||
int is_valid_domain_name (const char *string);
|
||||
|
||||
|
@ -328,6 +328,82 @@ make_printable_string (const void *p, size_t n, int delim )
|
||||
}
|
||||
|
||||
|
||||
/* Decode the C formatted string SRC and return the result in a newly
|
||||
* allocated buffer. In error returns NULL and sets ERRNO. */
|
||||
char *
|
||||
decode_c_string (const char *src)
|
||||
{
|
||||
char *buffer, *dst;
|
||||
int val;
|
||||
|
||||
/* The converted string will never be larger than the original
|
||||
string. */
|
||||
buffer = dst = xtrymalloc (strlen (src) + 1);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
while (*src)
|
||||
{
|
||||
if (*src != '\\')
|
||||
{
|
||||
*dst++ = *src++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#define DECODE_ONE(_m,_r) case _m: src += 2; *dst++ = _r; break;
|
||||
|
||||
switch (src[1])
|
||||
{
|
||||
DECODE_ONE ('n', '\n');
|
||||
DECODE_ONE ('r', '\r');
|
||||
DECODE_ONE ('f', '\f');
|
||||
DECODE_ONE ('v', '\v');
|
||||
DECODE_ONE ('b', '\b');
|
||||
DECODE_ONE ('t', '\t');
|
||||
DECODE_ONE ('\\', '\\');
|
||||
DECODE_ONE ('\'', '\'');
|
||||
DECODE_ONE ('\"', '\"');
|
||||
|
||||
case 'x':
|
||||
val = hextobyte (src+2);
|
||||
if (val == -1) /* Bad coding, keep as is. */
|
||||
{
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
if (*src)
|
||||
*dst++ = *src++;
|
||||
if (*src)
|
||||
*dst++ = *src++;
|
||||
}
|
||||
else if (!val)
|
||||
{
|
||||
/* A binary zero is not representable in a C string thus
|
||||
* we keep the C-escaping. Note that this will also
|
||||
* never be larger than the source string. */
|
||||
*dst++ = '\\';
|
||||
*dst++ = '0';
|
||||
src += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(unsigned char *)dst++ = val;
|
||||
src += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* Bad coding; keep as is.. */
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
break;
|
||||
}
|
||||
#undef DECODE_ONE
|
||||
}
|
||||
*dst++ = 0;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
|
||||
* packet. LEN should be at least 6. */
|
||||
static int
|
||||
|
@ -49,6 +49,22 @@
|
||||
#include "mischelp.h"
|
||||
|
||||
|
||||
void
|
||||
wipememory (void *ptr, size_t len)
|
||||
{
|
||||
#if defined(HAVE_W32_SYSTEM) && defined(SecureZeroMemory)
|
||||
SecureZeroMemory (ptr, len);
|
||||
#elif defined(HAVE_EXPLICIT_BZERO)
|
||||
explicit_bzero (ptr, len);
|
||||
#else
|
||||
/* Prevent compiler from optimizing away the call to memset by accessing
|
||||
memset through volatile pointer. */
|
||||
static void *(*volatile memset_ptr)(void *, int, size_t) = (void *)memset;
|
||||
memset_ptr (ptr, 0, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Check whether the files NAME1 and NAME2 are identical. This is for
|
||||
example achieved by comparing the inode numbers of the files. */
|
||||
int
|
||||
|
@ -47,15 +47,9 @@ time_t timegm (struct tm *tm);
|
||||
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||
#define DIMof(type,member) DIM(((type *)0)->member)
|
||||
|
||||
/* To avoid that a compiler optimizes certain memset calls away, these
|
||||
macros may be used instead. */
|
||||
#define wipememory2(_ptr,_set,_len) do { \
|
||||
volatile char *_vptr=(volatile char *)(_ptr); \
|
||||
size_t _vlen=(_len); \
|
||||
while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
|
||||
} while(0)
|
||||
#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
|
||||
|
||||
/* To avoid that a compiler optimizes certain memset calls away,
|
||||
wipememory function may be used instead. */
|
||||
void wipememory(void *ptr, size_t len);
|
||||
|
||||
/* Include hacks which are mainly required for Slowaris. */
|
||||
#ifdef GNUPG_COMMON_NEED_AFLOCAL
|
||||
|
@ -30,7 +30,7 @@ cat <<EOF
|
||||
* gnupg_strerror:
|
||||
* @err: Error code
|
||||
*
|
||||
* This function returns a textual representaion of the given
|
||||
* This function returns a textual representation of the given
|
||||
* errorcode. If this is an unknown value, a string with the value
|
||||
* is returned (Beware: it is hold in a static buffer).
|
||||
*
|
||||
|
@ -26,7 +26,7 @@ cat <<EOF
|
||||
* gnupg_error_token:
|
||||
* @err: Error code
|
||||
*
|
||||
* This function returns a textual representaion of the given
|
||||
* This function returns a textual representation of the given
|
||||
* errorcode. If this is an unknown value, a static string is returned.
|
||||
* This function differs from gnupg_strerror that it yields the string
|
||||
* representation of the macro which is never subject to i18n.
|
||||
|
@ -184,48 +184,36 @@ openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi)
|
||||
}
|
||||
|
||||
|
||||
/* Return a malloced string represenation of the OID in the opaque MPI
|
||||
A. In case of an error NULL is returned and ERRNO is set. */
|
||||
/* Return a malloced string representation of the OID in the buffer
|
||||
* (BUF,LEN). In case of an error NULL is returned and ERRNO is set.
|
||||
* As per OpenPGP spec the first byte of the buffer is the length of
|
||||
* the rest; the function performs a consistency check. */
|
||||
char *
|
||||
openpgp_oid_to_str (gcry_mpi_t a)
|
||||
openpgp_oidbuf_to_str (const unsigned char *buf, size_t len)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t length;
|
||||
unsigned int lengthi;
|
||||
char *string, *p;
|
||||
int n = 0;
|
||||
unsigned long val, valmask;
|
||||
|
||||
valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
|
||||
|
||||
if (!a
|
||||
|| !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)
|
||||
|| !(buf = gcry_mpi_get_opaque (a, &lengthi)))
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = gcry_mpi_get_opaque (a, &lengthi);
|
||||
length = (lengthi+7)/8;
|
||||
|
||||
/* The first bytes gives the length; check consistency. */
|
||||
if (!length || buf[0] != length -1)
|
||||
|
||||
if (!len || buf[0] != len -1)
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
/* Skip length byte. */
|
||||
length--;
|
||||
len--;
|
||||
buf++;
|
||||
|
||||
/* To calculate the length of the string we can safely assume an
|
||||
upper limit of 3 decimal characters per byte. Two extra bytes
|
||||
account for the special first octect */
|
||||
string = p = xtrymalloc (length*(1+3)+2+1);
|
||||
account for the special first octet */
|
||||
string = p = xtrymalloc (len*(1+3)+2+1);
|
||||
if (!string)
|
||||
return NULL;
|
||||
if (!length)
|
||||
if (!len)
|
||||
{
|
||||
*p = 0;
|
||||
return string;
|
||||
@ -237,7 +225,7 @@ openpgp_oid_to_str (gcry_mpi_t a)
|
||||
p += sprintf (p, "1.%d", buf[n]-40);
|
||||
else {
|
||||
val = buf[n] & 0x7f;
|
||||
while ( (buf[n]&0x80) && ++n < length )
|
||||
while ( (buf[n]&0x80) && ++n < len )
|
||||
{
|
||||
if ( (val & valmask) )
|
||||
goto badoid; /* Overflow. */
|
||||
@ -250,10 +238,10 @@ openpgp_oid_to_str (gcry_mpi_t a)
|
||||
sprintf (p, "2.%lu", val);
|
||||
p += strlen (p);
|
||||
}
|
||||
for (n++; n < length; n++)
|
||||
for (n++; n < len; n++)
|
||||
{
|
||||
val = buf[n] & 0x7f;
|
||||
while ( (buf[n]&0x80) && ++n < length )
|
||||
while ( (buf[n]&0x80) && ++n < len )
|
||||
{
|
||||
if ( (val & valmask) )
|
||||
goto badoid; /* Overflow. */
|
||||
@ -278,6 +266,35 @@ openpgp_oid_to_str (gcry_mpi_t a)
|
||||
}
|
||||
|
||||
|
||||
/* Return a malloced string representation of the OID in the opaque
|
||||
* MPI A. In case of an error NULL is returned and ERRNO is set. */
|
||||
char *
|
||||
openpgp_oid_to_str (gcry_mpi_t a)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
unsigned int lengthi;
|
||||
|
||||
if (!a
|
||||
|| !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)
|
||||
|| !(buf = gcry_mpi_get_opaque (a, &lengthi)))
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = gcry_mpi_get_opaque (a, &lengthi);
|
||||
return openpgp_oidbuf_to_str (buf, (lengthi+7)/8);
|
||||
}
|
||||
|
||||
|
||||
/* Return true if (BUF,LEN) represents the OID for Ed25519. */
|
||||
int
|
||||
openpgp_oidbuf_is_ed25519 (const void *buf, size_t len)
|
||||
{
|
||||
return (buf && len == DIM (oid_ed25519)
|
||||
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519)));
|
||||
}
|
||||
|
||||
|
||||
/* Return true if A represents the OID for Ed25519. */
|
||||
int
|
||||
@ -285,32 +302,36 @@ openpgp_oid_is_ed25519 (gcry_mpi_t a)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
unsigned int nbits;
|
||||
size_t n;
|
||||
|
||||
if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
return 0;
|
||||
|
||||
buf = gcry_mpi_get_opaque (a, &nbits);
|
||||
n = (nbits+7)/8;
|
||||
return (n == DIM (oid_ed25519)
|
||||
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519)));
|
||||
return openpgp_oidbuf_is_ed25519 (buf, (nbits+7)/8);
|
||||
}
|
||||
|
||||
|
||||
/* Return true if (BUF,LEN) represents the OID for Curve25519. */
|
||||
int
|
||||
openpgp_oidbuf_is_cv25519 (const void *buf, size_t len)
|
||||
{
|
||||
return (buf && len == DIM (oid_cv25519)
|
||||
&& !memcmp (buf, oid_cv25519, DIM (oid_cv25519)));
|
||||
}
|
||||
|
||||
|
||||
/* Return true if the MPI A represents the OID for Curve25519. */
|
||||
int
|
||||
openpgp_oid_is_cv25519 (gcry_mpi_t a)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
unsigned int nbits;
|
||||
size_t n;
|
||||
|
||||
if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
return 0;
|
||||
|
||||
buf = gcry_mpi_get_opaque (a, &nbits);
|
||||
n = (nbits+7)/8;
|
||||
return (n == DIM (oid_cv25519)
|
||||
&& !memcmp (buf, oid_cv25519, DIM (oid_cv25519)));
|
||||
return openpgp_oidbuf_is_cv25519 (buf, (nbits+7)/8);
|
||||
}
|
||||
|
||||
|
||||
|
67
common/openpgp-s2k.c
Normal file
67
common/openpgp-s2k.c
Normal file
@ -0,0 +1,67 @@
|
||||
/* openpgp-s2ks.c - OpenPGP S2K helper functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
* 2005, 2006 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2010, 2019 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/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "openpgpdefs.h"
|
||||
|
||||
|
||||
/* Pack an s2k iteration count into the form specified in RFC-48800.
|
||||
* If we're in between valid values, round up. */
|
||||
unsigned char
|
||||
encode_s2k_iterations (int iterations)
|
||||
{
|
||||
unsigned char c=0;
|
||||
unsigned char result;
|
||||
unsigned int count;
|
||||
|
||||
if (iterations <= 1024)
|
||||
return 0; /* Command line arg compatibility. */
|
||||
|
||||
if (iterations >= 65011712)
|
||||
return 255;
|
||||
|
||||
/* Need count to be in the range 16-31 */
|
||||
for (count=iterations>>6; count>=32; count>>=1)
|
||||
c++;
|
||||
|
||||
result = (c<<4)|(count-16);
|
||||
|
||||
if (S2K_DECODE_COUNT(result) < iterations)
|
||||
result++;
|
||||
|
||||
return result;
|
||||
}
|
@ -196,5 +196,19 @@ typedef enum
|
||||
}
|
||||
compress_algo_t;
|
||||
|
||||
/* Limits to be used for static arrays. */
|
||||
#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. */
|
||||
|
||||
|
||||
/* Decode an rfc4880 encoded S2K count. */
|
||||
#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6))
|
||||
|
||||
|
||||
/*--openpgp-s2k.c --*/
|
||||
unsigned char encode_s2k_iterations (int iterations);
|
||||
|
||||
|
||||
#endif /*GNUPG_COMMON_OPENPGPDEFS_H*/
|
||||
|
@ -37,16 +37,16 @@
|
||||
|
||||
|
||||
/* Create a newly alloced string from STRING with all spaces and
|
||||
control characters converted to plus signs or %xx sequences. The
|
||||
function returns the new string or NULL in case of a malloc
|
||||
failure.
|
||||
|
||||
Note that we also escape the quote character to work around a bug
|
||||
in the mingw32 runtime which does not correcty handle command line
|
||||
quoting. We correctly double the quote mark when calling a program
|
||||
(i.e. gpg-protect-tool), but the pre-main code does not notice the
|
||||
double quote as an escaped quote. We do this also on POSIX systems
|
||||
for consistency. */
|
||||
* control characters converted to plus signs or %xx sequences. The
|
||||
* function returns the new string or NULL in case of a malloc
|
||||
* failure.
|
||||
*
|
||||
* Note that this fucntion also escapes the quote character to work
|
||||
* around a bug in the mingw32 runtime which does not correctly handle
|
||||
* command line quoting. We correctly double the quote mark when
|
||||
* calling a program (i.e. gpg-protect-tool), but the pre-main code
|
||||
* does not notice the double quote as an escaped quote. We do this
|
||||
* also on POSIX systems for consistency. */
|
||||
char *
|
||||
percent_plus_escape (const char *string)
|
||||
{
|
||||
@ -87,19 +87,36 @@ percent_plus_escape (const char *string)
|
||||
}
|
||||
|
||||
|
||||
/* Create a newly alloced string from (DATA,DATALEN) with embedded
|
||||
* Nuls quoted as %00. The standard percent unescaping can be
|
||||
* used to reverse this encoding. */
|
||||
/* Create a newly malloced string from (DATA,DATALEN) with embedded
|
||||
* nuls quoted as %00. The standard percent unescaping can be used to
|
||||
* reverse this encoding. With PLUS_ESCAPE set plus-escaping (spaces
|
||||
* are replaced by a '+') and escaping of characters with values less
|
||||
* than 0x20 is used. If PREFIX is not NULL it will be prepended to
|
||||
* the output in standard escape format; that is PLUS_ESCAPING is
|
||||
* ignored for PREFIX. */
|
||||
char *
|
||||
percent_data_escape (const void *data, size_t datalen)
|
||||
percent_data_escape (int plus_escape, const char *prefix,
|
||||
const void *data, size_t datalen)
|
||||
{
|
||||
char *buffer, *p;
|
||||
const char *s;
|
||||
size_t n, length;
|
||||
const unsigned char *s;
|
||||
size_t n;
|
||||
size_t length = 1;
|
||||
|
||||
for (length=1, s=data, n=datalen; n; s++, n--)
|
||||
if (prefix)
|
||||
{
|
||||
if (!*s || *s == '%')
|
||||
for (s = prefix; *s; s++)
|
||||
{
|
||||
if (*s == '%' || *s < 0x20)
|
||||
length += 3;
|
||||
else
|
||||
length++;
|
||||
}
|
||||
}
|
||||
|
||||
for (s=data, n=datalen; n; s++, n--)
|
||||
{
|
||||
if (!*s || *s == '%' || (plus_escape && (*s < ' ' || *s == '+')))
|
||||
length += 3;
|
||||
else
|
||||
length++;
|
||||
@ -109,6 +126,20 @@ percent_data_escape (const void *data, size_t datalen)
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
if (prefix)
|
||||
{
|
||||
for (s = prefix; *s; s++)
|
||||
{
|
||||
if (*s == '%' || *s < 0x20)
|
||||
{
|
||||
snprintf (p, 4, "%%%02X", *s);
|
||||
p += 3;
|
||||
}
|
||||
else
|
||||
*p++ = *s;
|
||||
}
|
||||
}
|
||||
|
||||
for (s=data, n=datalen; n; s++, n--)
|
||||
{
|
||||
if (!*s)
|
||||
@ -121,13 +152,21 @@ percent_data_escape (const void *data, size_t datalen)
|
||||
memcpy (p, "%25", 3);
|
||||
p += 3;
|
||||
}
|
||||
else if (plus_escape && *s == ' ')
|
||||
{
|
||||
*p++ = '+';
|
||||
}
|
||||
else if (plus_escape && (*s < ' ' || *s == '+'))
|
||||
{
|
||||
snprintf (p, 4, "%%%02X", *s);
|
||||
p += 3;
|
||||
}
|
||||
else
|
||||
*p++ = *s;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
return buffer;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,8 +30,22 @@
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "server-help.h"
|
||||
#include "util.h"
|
||||
#include "server-help.h"
|
||||
|
||||
|
||||
static GPGRT_INLINE gpg_error_t
|
||||
my_error (int e)
|
||||
{
|
||||
return gpg_err_make (default_errsource, (e));
|
||||
}
|
||||
|
||||
static GPGRT_INLINE gpg_error_t
|
||||
my_error_from_syserror (void)
|
||||
{
|
||||
return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
||||
}
|
||||
|
||||
|
||||
/* Skip over options in LINE.
|
||||
|
||||
@ -114,6 +128,40 @@ has_option_name (const char *line, const char *name)
|
||||
}
|
||||
|
||||
|
||||
/* Parse an option with the format "--NAME=VALUE" which must occur in
|
||||
* LINE before a double-dash. LINE is written to but not modified by
|
||||
* this function. If the option is found and has a value the value is
|
||||
* stored as a malloced string at R_VALUE. If the option was not
|
||||
* found or an error occurred NULL is stored there. Note that
|
||||
* currently the value must be a string without any space; we may
|
||||
* eventually update this function to allow for a quoted value. */
|
||||
gpg_error_t
|
||||
get_option_value (char *line, const char *name, char **r_value)
|
||||
{
|
||||
char *p, *pend;
|
||||
int c;
|
||||
|
||||
*r_value = NULL;
|
||||
|
||||
p = (char*)has_option_name (line, name);
|
||||
if (!p || p >= skip_options (line))
|
||||
return 0;
|
||||
|
||||
if (*p != '=' || !p[1] || spacep (p+1))
|
||||
return my_error (GPG_ERR_INV_ARG);
|
||||
p++;
|
||||
for (pend = p; *pend && !spacep (pend); pend++)
|
||||
;
|
||||
c = *pend;
|
||||
*pend = 0;
|
||||
*r_value = xtrystrdup (p);
|
||||
*pend = c;
|
||||
if (!p)
|
||||
return my_error_from_syserror ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return a pointer to the argument of the option with NAME. If such
|
||||
an option is not given, NULL is returned. */
|
||||
char *
|
||||
|
@ -55,6 +55,14 @@ int has_leading_option (const char *line, const char *name);
|
||||
or a space. */
|
||||
const char *has_option_name (const char *line, const char *name);
|
||||
|
||||
/* Same as has_option_name but ignores all options after a "--" and
|
||||
* does not return a const char ptr. */
|
||||
char *has_leading_option_name (char *line, const char *name);
|
||||
|
||||
/* Parse an option with the format "--NAME=VALUE" and return the value
|
||||
* as a malloced string. */
|
||||
gpg_error_t get_option_value (char *line, const char *name, char **r_value);
|
||||
|
||||
/* Return a pointer to the argument of the option with NAME. If such
|
||||
an option is not given, NULL is returned. */
|
||||
char *option_value (const char *line, const char *name);
|
||||
|
@ -105,7 +105,7 @@ smatch (unsigned char const **buf, size_t buflen, const char *token)
|
||||
}
|
||||
|
||||
/* Format VALUE for use as the length indicatior of an S-expression.
|
||||
The caller needs to provide a buffer HELP_BUFFER wth a length of
|
||||
The caller needs to provide a buffer HELP_BUFFER with a length of
|
||||
HELP_BUFLEN. The return value is a pointer into HELP_BUFFER with
|
||||
the formatted length string. The colon and a trailing nul are
|
||||
appended. HELP_BUFLEN must be at least 3 - a more useful value is
|
||||
|
@ -303,7 +303,7 @@ make_simple_sexp_from_hexstr (const char *line, size_t *nscanned)
|
||||
for (; n > 1; n -=2, s += 2)
|
||||
*p++ = xtoi_2 (s);
|
||||
*p++ = ')';
|
||||
*p = 0; /* (Not really neaded.) */
|
||||
*p = 0; /* (Not really needed.) */
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -577,3 +577,61 @@ get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen)
|
||||
gcry_sexp_release (sexp);
|
||||
return algo;
|
||||
}
|
||||
|
||||
|
||||
/* Given the public key S_PKEY, return a new buffer with a descriptive
|
||||
* string for its algorithm. This function may return NULL on memory
|
||||
* error. */
|
||||
char *
|
||||
pubkey_algo_string (gcry_sexp_t s_pkey)
|
||||
{
|
||||
const char *prefix;
|
||||
gcry_sexp_t l1;
|
||||
char *algoname;
|
||||
int algo;
|
||||
char *result;
|
||||
|
||||
l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
|
||||
if (!l1)
|
||||
return xtrystrdup ("E_no_key");
|
||||
{
|
||||
gcry_sexp_t l_tmp = gcry_sexp_cadr (l1);
|
||||
gcry_sexp_release (l1);
|
||||
l1 = l_tmp;
|
||||
}
|
||||
algoname = gcry_sexp_nth_string (l1, 0);
|
||||
gcry_sexp_release (l1);
|
||||
if (!algoname)
|
||||
return xtrystrdup ("E_no_algo");
|
||||
|
||||
algo = gcry_pk_map_name (algoname);
|
||||
switch (algo)
|
||||
{
|
||||
case GCRY_PK_RSA: prefix = "rsa"; break;
|
||||
case GCRY_PK_ELG: prefix = "elg"; break;
|
||||
case GCRY_PK_DSA: prefix = "dsa"; break;
|
||||
case GCRY_PK_ECC: prefix = ""; break;
|
||||
default: prefix = NULL; break;
|
||||
}
|
||||
|
||||
if (prefix && *prefix)
|
||||
result = xtryasprintf ("%s%u", prefix, gcry_pk_get_nbits (s_pkey));
|
||||
else if (prefix)
|
||||
{
|
||||
const char *curve = gcry_pk_get_curve (s_pkey, 0, NULL);
|
||||
const char *name = openpgp_oid_to_curve
|
||||
(openpgp_curve_to_oid (curve, NULL), 0);
|
||||
|
||||
if (name)
|
||||
result = xtrystrdup (name);
|
||||
else if (curve)
|
||||
result = xtryasprintf ("X_%s", curve);
|
||||
else
|
||||
result = xtrystrdup ("E_unknown");
|
||||
}
|
||||
else
|
||||
result = xtryasprintf ("X_algo_%d", algo);
|
||||
|
||||
xfree (algoname);
|
||||
return result;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@
|
||||
|
||||
|
||||
/* Name of the socket to be used. This is a kludge to keep on using
|
||||
the existsing code despite that we only support a standard socket. */
|
||||
the existing code despite that we only support a standard socket. */
|
||||
static char *default_gpg_agent_info;
|
||||
|
||||
|
||||
@ -246,6 +246,7 @@ agent_open (assuan_context_t *ctx)
|
||||
#ifdef SPWQ_USE_LOGGING
|
||||
log_error (_("no gpg-agent running in this session\n"));
|
||||
#endif
|
||||
*ctx = NULL;
|
||||
return SPWQ_NO_AGENT;
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,7 @@ get_fingerprint (gcry_sexp_t key, int algo,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
strncpy (*r_fpr, algo_name, strlen (algo_name));
|
||||
memcpy (*r_fpr, algo_name, strlen (algo_name));
|
||||
fpr = (char *) *r_fpr + strlen (algo_name);
|
||||
*fpr++ = ':';
|
||||
|
||||
|
@ -34,6 +34,10 @@
|
||||
#include "status.h"
|
||||
#include "status-codes.h"
|
||||
|
||||
/* The stream to output the status information. Output is disabled if
|
||||
* this is NULL. */
|
||||
static estream_t statusfp;
|
||||
|
||||
|
||||
/* Return the status string for code NO. */
|
||||
const char *
|
||||
@ -47,6 +51,60 @@ get_status_string ( int no )
|
||||
}
|
||||
|
||||
|
||||
/* Set a global status FD. */
|
||||
void
|
||||
gnupg_set_status_fd (int fd)
|
||||
{
|
||||
static int last_fd = -1;
|
||||
|
||||
if (fd != -1 && last_fd == fd)
|
||||
return;
|
||||
|
||||
if (statusfp && statusfp != es_stdout && statusfp != es_stderr)
|
||||
es_fclose (statusfp);
|
||||
statusfp = NULL;
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
if (fd == 1)
|
||||
statusfp = es_stdout;
|
||||
else if (fd == 2)
|
||||
statusfp = es_stderr;
|
||||
else
|
||||
statusfp = es_fdopen (fd, "w");
|
||||
if (!statusfp)
|
||||
{
|
||||
log_fatal ("can't open fd %d for status output: %s\n",
|
||||
fd, gpg_strerror (gpg_error_from_syserror ()));
|
||||
}
|
||||
last_fd = fd;
|
||||
}
|
||||
|
||||
|
||||
/* Write a status line with code NO followed by the output of the
|
||||
* printf style FORMAT. The caller needs to make sure that LFs and
|
||||
* CRs are not printed. */
|
||||
void
|
||||
gnupg_status_printf (int no, const char *format, ...)
|
||||
{
|
||||
va_list arg_ptr;
|
||||
|
||||
if (!statusfp)
|
||||
return; /* Not enabled. */
|
||||
|
||||
es_fputs ("[GNUPG:] ", statusfp);
|
||||
es_fputs (get_status_string (no), statusfp);
|
||||
if (format)
|
||||
{
|
||||
es_putc (' ', statusfp);
|
||||
va_start (arg_ptr, format);
|
||||
es_vfprintf (statusfp, format, arg_ptr);
|
||||
va_end (arg_ptr);
|
||||
}
|
||||
es_putc ('\n', statusfp);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
get_inv_recpsgnr_code (gpg_error_t err)
|
||||
{
|
||||
|
@ -163,6 +163,10 @@ enum
|
||||
|
||||
|
||||
const char *get_status_string (int code);
|
||||
void gnupg_set_status_fd (int fd);
|
||||
void gnupg_status_printf (int no, const char *format,
|
||||
...) GPGRT_ATTR_PRINTF(2,3);
|
||||
|
||||
const char *get_inv_recpsgnr_code (gpg_error_t err);
|
||||
|
||||
|
||||
|
@ -810,6 +810,19 @@ ascii_strlwr (char *s)
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Upcase all ASCII characters in S. */
|
||||
char *
|
||||
ascii_strupr (char *s)
|
||||
{
|
||||
char *p = s;
|
||||
|
||||
for (p=s; *p; p++ )
|
||||
if (isascii (*p) && *p >= 'a' && *p <= 'z')
|
||||
*p &= ~0x20;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
ascii_strcasecmp( const char *a, const char *b )
|
||||
{
|
||||
@ -1400,7 +1413,7 @@ parse_version_number (const char *s, int *number)
|
||||
|
||||
|
||||
/* This function breaks up the complete string-representation of the
|
||||
version number S, which is of the following struture: <major
|
||||
version number S, which is of the following structure: <major
|
||||
number>.<minor number>[.<micro number>]<patch level>. The major,
|
||||
minor, and micro number components will be stored in *MAJOR, *MINOR
|
||||
and *MICRO. If MICRO is not given 0 is used instead.
|
||||
|
@ -76,6 +76,7 @@ int ascii_islower (int c);
|
||||
int ascii_toupper (int c);
|
||||
int ascii_tolower (int c);
|
||||
char *ascii_strlwr (char *s);
|
||||
char *ascii_strupr (char *s);
|
||||
int ascii_strcasecmp( const char *a, const char *b );
|
||||
int ascii_strncasecmp (const char *a, const char *b, size_t n);
|
||||
int ascii_memcasecmp( const void *a, const void *b, size_t n );
|
||||
|
@ -551,14 +551,13 @@ gnupg_tmpfile (void)
|
||||
void
|
||||
gnupg_reopen_std (const char *pgmname)
|
||||
{
|
||||
#if defined(HAVE_STAT) && !defined(HAVE_W32_SYSTEM)
|
||||
struct stat statbuf;
|
||||
#ifdef F_GETFD
|
||||
int did_stdin = 0;
|
||||
int did_stdout = 0;
|
||||
int did_stderr = 0;
|
||||
FILE *complain;
|
||||
|
||||
if (fstat (STDIN_FILENO, &statbuf) == -1 && errno ==EBADF)
|
||||
if (fcntl (STDIN_FILENO, F_GETFD) == -1 && errno ==EBADF)
|
||||
{
|
||||
if (open ("/dev/null",O_RDONLY) == STDIN_FILENO)
|
||||
did_stdin = 1;
|
||||
@ -566,7 +565,7 @@ gnupg_reopen_std (const char *pgmname)
|
||||
did_stdin = 2;
|
||||
}
|
||||
|
||||
if (fstat (STDOUT_FILENO, &statbuf) == -1 && errno == EBADF)
|
||||
if (fcntl (STDOUT_FILENO, F_GETFD) == -1 && errno == EBADF)
|
||||
{
|
||||
if (open ("/dev/null",O_WRONLY) == STDOUT_FILENO)
|
||||
did_stdout = 1;
|
||||
@ -574,7 +573,7 @@ gnupg_reopen_std (const char *pgmname)
|
||||
did_stdout = 2;
|
||||
}
|
||||
|
||||
if (fstat (STDERR_FILENO, &statbuf)==-1 && errno==EBADF)
|
||||
if (fcntl (STDERR_FILENO, F_GETFD)==-1 && errno==EBADF)
|
||||
{
|
||||
if (open ("/dev/null", O_WRONLY) == STDERR_FILENO)
|
||||
did_stderr = 1;
|
||||
@ -607,7 +606,7 @@ gnupg_reopen_std (const char *pgmname)
|
||||
|
||||
if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
|
||||
exit (3);
|
||||
#else /* !(HAVE_STAT && !HAVE_W32_SYSTEM) */
|
||||
#else /* !F_GETFD */
|
||||
(void)pgmname;
|
||||
#endif
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ test_close_all_fds (void)
|
||||
free (array);
|
||||
|
||||
/* Now let's check the realloc we use. We do this and the next
|
||||
tests only if we are allowed to open enought descriptors. */
|
||||
tests only if we are allowed to open enough descriptors. */
|
||||
if (get_max_fds () > 32)
|
||||
{
|
||||
int except[] = { 20, 23, 24, -1 };
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include "util.h"
|
||||
#include "mbox-util.h"
|
||||
|
||||
#define PGM "t-mbox-util"
|
||||
|
||||
|
||||
#define pass() do { ; } while(0)
|
||||
#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
|
||||
__FILE__,__LINE__, (a)); \
|
||||
@ -32,6 +35,10 @@
|
||||
} while(0)
|
||||
|
||||
|
||||
static int verbose;
|
||||
static int debug;
|
||||
|
||||
|
||||
static void
|
||||
run_mbox_test (void)
|
||||
{
|
||||
@ -76,7 +83,86 @@ run_mbox_test (void)
|
||||
|
||||
for (idx=0; testtbl[idx].userid; idx++)
|
||||
{
|
||||
char *mbox = mailbox_from_userid (testtbl[idx].userid);
|
||||
char *mbox = mailbox_from_userid (testtbl[idx].userid, 0);
|
||||
|
||||
if (!testtbl[idx].mbox)
|
||||
{
|
||||
if (mbox)
|
||||
fail (idx);
|
||||
}
|
||||
else if (!mbox)
|
||||
fail (idx);
|
||||
else if (strcmp (mbox, testtbl[idx].mbox))
|
||||
fail (idx);
|
||||
|
||||
xfree (mbox);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
run_mbox_no_sub_test (void)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const char *userid;
|
||||
const char *mbox;
|
||||
} testtbl[] =
|
||||
{
|
||||
{ "foo+bar@example.org", "foo@example.org" },
|
||||
{ "Werner Koch <wk@gnupg.org>", "wk@gnupg.org" },
|
||||
{ "<wk@gnupg.org>", "wk@gnupg.org" },
|
||||
{ "wk@gnupg.org", "wk@gnupg.org" },
|
||||
{ "wk@gnupg.org ", NULL },
|
||||
{ " wk@gnupg.org", NULL },
|
||||
{ "Werner Koch (test) <wk@gnupg.org>", "wk@gnupg.org" },
|
||||
{ "Werner Koch <wk@gnupg.org> (test)", "wk@gnupg.org" },
|
||||
{ "Werner Koch <wk@gnupg.org (test)", NULL },
|
||||
{ "Werner Koch <wk@gnupg.org >", NULL },
|
||||
{ "Werner Koch <wk@gnupg.org", NULL },
|
||||
{ "", NULL },
|
||||
{ "@", NULL },
|
||||
{ "bar <>", NULL },
|
||||
{ "<foo@example.org>", "foo@example.org" },
|
||||
{ "<foo.@example.org>", "foo.@example.org" },
|
||||
{ "<.foo.@example.org>", ".foo.@example.org" },
|
||||
{ "<foo..@example.org>", "foo..@example.org" },
|
||||
{ "<foo..bar@example.org>", "foo..bar@example.org" },
|
||||
{ "<foo@example.org.>", NULL },
|
||||
{ "<foo@example..org>", NULL },
|
||||
{ "<foo@.>", NULL },
|
||||
{ "<@example.org>", NULL },
|
||||
{ "<foo@@example.org>", NULL },
|
||||
{ "<@foo@example.org>", NULL },
|
||||
{ "<foo@example.org> ()", "foo@example.org" },
|
||||
{ "<fo()o@example.org> ()", "fo()o@example.org" },
|
||||
{ "<fo()o@example.org> ()", "fo()o@example.org" },
|
||||
{ "fo()o@example.org", NULL},
|
||||
{ "Mr. Foo <foo@example.org><bar@example.net>", "foo@example.org"},
|
||||
{ "foo+bar@example.org", "foo@example.org" },
|
||||
{ "foo++bar@example.org", "foo++bar@example.org" },
|
||||
{ "foo++@example.org", "foo++@example.org" },
|
||||
{ "foo+@example.org", "foo+@example.org" },
|
||||
{ "+foo@example.org", "+foo@example.org" },
|
||||
{ "++foo@example.org", "++foo@example.org" },
|
||||
{ "+foo+@example.org", "+foo+@example.org" },
|
||||
{ "+@example.org", "+@example.org" },
|
||||
{ "++@example.org", "++@example.org" },
|
||||
{ "foo+b@example.org", "foo@example.org" },
|
||||
{ "foo+ba@example.org", "foo@example.org" },
|
||||
{ "foo+bar@example.org", "foo@example.org" },
|
||||
{ "foo+barb@example.org", "foo@example.org" },
|
||||
{ "foo+barba@example.org", "foo@example.org" },
|
||||
{ "f+b@example.org", "f@example.org" },
|
||||
{ "fo+b@example.org", "fo@example.org" },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
int idx;
|
||||
|
||||
for (idx=0; testtbl[idx].userid; idx++)
|
||||
{
|
||||
char *mbox = mailbox_from_userid (testtbl[idx].userid, 1);
|
||||
|
||||
if (!testtbl[idx].mbox)
|
||||
{
|
||||
@ -143,14 +229,105 @@ run_dns_test (void)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
run_filter (int no_sub)
|
||||
{
|
||||
char buf[4096];
|
||||
int c;
|
||||
char *p, *mbox;
|
||||
unsigned int count1 = 0;
|
||||
unsigned int count2 = 0;
|
||||
|
||||
while (fgets (buf, sizeof buf, stdin))
|
||||
{
|
||||
p = strchr (buf, '\n');
|
||||
if (p)
|
||||
*p = 0;
|
||||
else
|
||||
{
|
||||
/* Skip to the end of the line. */
|
||||
while ((c = getc (stdin)) != EOF && c != '\n')
|
||||
;
|
||||
}
|
||||
count1++;
|
||||
trim_spaces (buf);
|
||||
mbox = mailbox_from_userid (buf, no_sub);
|
||||
if (mbox)
|
||||
{
|
||||
printf ("%s\n", mbox);
|
||||
xfree (mbox);
|
||||
count2++;
|
||||
}
|
||||
}
|
||||
if (verbose)
|
||||
fprintf (stderr, PGM ": lines=%u mboxes=%u\n", count1, count2);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
int last_argc = -1;
|
||||
int opt_filter = 0;
|
||||
int opt_no_sub = 0;
|
||||
|
||||
if (argc)
|
||||
{ argc--; argv++; }
|
||||
while (argc && last_argc != argc )
|
||||
{
|
||||
last_argc = argc;
|
||||
if (!strcmp (*argv, "--"))
|
||||
{
|
||||
argc--; argv++;
|
||||
break;
|
||||
}
|
||||
else if (!strcmp (*argv, "--help"))
|
||||
{
|
||||
fputs ("usage: " PGM " [FILE]\n"
|
||||
"Options:\n"
|
||||
" --verbose Print timings etc.\n"
|
||||
" --debug Flyswatter\n"
|
||||
" --filter Filter mboxes from input lines\n"
|
||||
" --no-sub Ignore '+'-sub-addresses\n"
|
||||
, stdout);
|
||||
exit (0);
|
||||
}
|
||||
else if (!strcmp (*argv, "--verbose"))
|
||||
{
|
||||
verbose++;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "--debug"))
|
||||
{
|
||||
verbose += 2;
|
||||
debug++;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "--filter"))
|
||||
{
|
||||
opt_filter = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "--no-sub"))
|
||||
{
|
||||
opt_no_sub = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strncmp (*argv, "--", 2))
|
||||
{
|
||||
fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_filter)
|
||||
run_filter (opt_no_sub);
|
||||
else
|
||||
{
|
||||
run_mbox_test ();
|
||||
run_mbox_no_sub_test ();
|
||||
run_dns_test ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -142,7 +142,15 @@ test_openpgp_oid_to_str (void)
|
||||
fail (idx, 0);
|
||||
xfree (string);
|
||||
gcry_mpi_release (a);
|
||||
}
|
||||
|
||||
/* Again using the buffer variant. */
|
||||
string = openpgp_oidbuf_to_str (samples[idx].der, samples[idx].der[0]+1);
|
||||
if (!string)
|
||||
fail (idx, gpg_error_from_syserror ());
|
||||
if (strcmp (string, samples[idx].string))
|
||||
fail (idx, 0);
|
||||
xfree (string);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,142 @@ test_percent_plus_escape (void)
|
||||
|
||||
static void
|
||||
test_percent_data_escape (void)
|
||||
{
|
||||
static struct {
|
||||
const char *prefix;
|
||||
const char *data;
|
||||
size_t datalen;
|
||||
const char *expect;
|
||||
} tbl[] = {
|
||||
{
|
||||
NULL,
|
||||
"", 0,
|
||||
""
|
||||
}, {
|
||||
NULL,
|
||||
"a", 1,
|
||||
"a",
|
||||
}, {
|
||||
NULL,
|
||||
"%22", 3,
|
||||
"%2522"
|
||||
}, {
|
||||
NULL,
|
||||
"%%", 3,
|
||||
"%25%25%00"
|
||||
}, {
|
||||
NULL,
|
||||
"\n \0BC\t", 6,
|
||||
"\n %00BC\t"
|
||||
}, {
|
||||
"",
|
||||
"", 0,
|
||||
""
|
||||
}, {
|
||||
"",
|
||||
"a", 1,
|
||||
"a",
|
||||
}, {
|
||||
"",
|
||||
"%22", 3,
|
||||
"%2522"
|
||||
}, {
|
||||
"",
|
||||
"%%", 3,
|
||||
"%25%25%00"
|
||||
}, {
|
||||
"",
|
||||
"\n \0BC\t", 6,
|
||||
"\n %00BC\t"
|
||||
}, {
|
||||
"a",
|
||||
"", 0,
|
||||
"a"
|
||||
}, {
|
||||
"a",
|
||||
"a", 1,
|
||||
"aa",
|
||||
}, {
|
||||
"a",
|
||||
"%22", 3,
|
||||
"a%2522"
|
||||
}, {
|
||||
"a",
|
||||
"%%", 3,
|
||||
"a%25%25%00"
|
||||
}, {
|
||||
"a",
|
||||
"\n \0BC\t", 6,
|
||||
"a\n %00BC\t"
|
||||
}, {
|
||||
" ",
|
||||
"%%", 3,
|
||||
" %25%25%00"
|
||||
}, {
|
||||
"+",
|
||||
"%%", 3,
|
||||
"+%25%25%00"
|
||||
}, {
|
||||
"%",
|
||||
"%%", 3,
|
||||
"%25%25%25%00"
|
||||
}, {
|
||||
"a b",
|
||||
"%%", 3,
|
||||
"a b%25%25%00"
|
||||
}, {
|
||||
"a%2Bb",
|
||||
"%%", 3,
|
||||
"a%252Bb%25%25%00"
|
||||
}, {
|
||||
"\n",
|
||||
"%%", 3,
|
||||
"%0A%25%25%00"
|
||||
}, {
|
||||
NULL,
|
||||
NULL, 0,
|
||||
NULL }
|
||||
};
|
||||
char *buf;
|
||||
int i;
|
||||
size_t len, prefixlen;
|
||||
|
||||
for (i=0; tbl[i].data; i++)
|
||||
{
|
||||
buf = percent_data_escape (0, tbl[i].prefix, tbl[i].data, tbl[i].datalen);
|
||||
if (!buf)
|
||||
{
|
||||
fprintf (stderr, "out of core: %s\n", strerror (errno));
|
||||
exit (2);
|
||||
}
|
||||
if (strcmp (buf, tbl[i].expect))
|
||||
{
|
||||
fail (i);
|
||||
}
|
||||
len = percent_plus_unescape_inplace (buf, 0);
|
||||
prefixlen = tbl[i].prefix? strlen (tbl[i].prefix) : 0;
|
||||
if (len != tbl[i].datalen + prefixlen)
|
||||
fail (i);
|
||||
else if (tbl[i].prefix && memcmp (buf, tbl[i].prefix, prefixlen)
|
||||
&& !(prefixlen == 1 && *tbl[i].prefix == '+' && *buf == ' '))
|
||||
{
|
||||
/* Note extra condition above handles the one test case
|
||||
* which reverts a plus to a space due to the use of the
|
||||
* plus-unescape fucntion also for the prefix part. */
|
||||
fail (i);
|
||||
}
|
||||
else if (memcmp (buf+prefixlen, tbl[i].data, tbl[i].datalen))
|
||||
{
|
||||
fail (i);
|
||||
}
|
||||
xfree (buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_percent_data_escape_plus (void)
|
||||
{
|
||||
static struct {
|
||||
const char *data;
|
||||
@ -121,7 +257,28 @@ test_percent_data_escape (void)
|
||||
"%25%25%00"
|
||||
}, {
|
||||
"\n \0BC\t", 6,
|
||||
"\n %00BC\t"
|
||||
"%0A+%00BC%09"
|
||||
}, {
|
||||
" ", 1,
|
||||
"+"
|
||||
}, {
|
||||
" ", 2,
|
||||
"++"
|
||||
}, {
|
||||
"+ +", 3,
|
||||
"%2B+%2B"
|
||||
}, {
|
||||
"\" \"", 3, /* Note: This function does not escape quotes. */
|
||||
"\"+\""
|
||||
}, {
|
||||
"%22", 3,
|
||||
"%2522"
|
||||
}, {
|
||||
"%% ", 3,
|
||||
"%25%25+"
|
||||
}, {
|
||||
"\n ABC\t", 6,
|
||||
"%0A+ABC%09"
|
||||
}, { NULL, 0, NULL }
|
||||
};
|
||||
char *buf;
|
||||
@ -130,14 +287,16 @@ test_percent_data_escape (void)
|
||||
|
||||
for (i=0; tbl[i].data; i++)
|
||||
{
|
||||
buf = percent_data_escape (tbl[i].data, tbl[i].datalen);
|
||||
buf = percent_data_escape (1, NULL, tbl[i].data, tbl[i].datalen);
|
||||
if (!buf)
|
||||
{
|
||||
fprintf (stderr, "out of core: %s\n", strerror (errno));
|
||||
exit (2);
|
||||
}
|
||||
if (strcmp (buf, tbl[i].expect))
|
||||
{
|
||||
fail (i);
|
||||
}
|
||||
len = percent_plus_unescape_inplace (buf, 0);
|
||||
if (len != tbl[i].datalen)
|
||||
fail (i);
|
||||
@ -148,16 +307,15 @@ test_percent_data_escape (void)
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
/* FIXME: We escape_unescape is not tested - only
|
||||
percent_plus_unescape. */
|
||||
/* FIXME: escape_unescape is not tested - only percent_plus_unescape. */
|
||||
test_percent_plus_escape ();
|
||||
test_percent_data_escape ();
|
||||
test_percent_data_escape_plus ();
|
||||
return 0;
|
||||
}
|
||||
|
140
common/ttyio.c
140
common/ttyio.c
@ -410,60 +410,62 @@ do_get( const char *prompt, int hidden )
|
||||
#endif
|
||||
int c, n, i;
|
||||
|
||||
if( batchmode ) {
|
||||
log_error("Sorry, we are in batchmode - can't get input\n");
|
||||
exit(2);
|
||||
if (batchmode)
|
||||
{
|
||||
log_error ("Sorry, we are in batchmode - can't get input\n");
|
||||
exit (2);
|
||||
}
|
||||
|
||||
if (no_terminal) {
|
||||
log_error("Sorry, no terminal at all requested - can't get input\n");
|
||||
exit(2);
|
||||
if (no_terminal)
|
||||
{
|
||||
log_error ("Sorry, no terminal at all requested - can't get input\n");
|
||||
exit (2);
|
||||
}
|
||||
|
||||
if( !initialized )
|
||||
init_ttyfp();
|
||||
if (!initialized)
|
||||
init_ttyfp ();
|
||||
|
||||
last_prompt_len = 0;
|
||||
tty_printf( "%s", prompt );
|
||||
buf = xmalloc((n=50));
|
||||
tty_printf ("%s", prompt);
|
||||
buf = xmalloc ((n=50));
|
||||
i = 0;
|
||||
|
||||
#ifdef USE_W32_CONSOLE
|
||||
if( hidden )
|
||||
if (hidden)
|
||||
SetConsoleMode(con.in, HID_INPMODE );
|
||||
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
DWORD nread;
|
||||
|
||||
if( !ReadConsoleA( con.in, cbuf, 1, &nread, NULL ) )
|
||||
log_fatal("ReadConsole failed: rc=%d", (int)GetLastError() );
|
||||
if( !nread )
|
||||
if (!ReadConsoleA( con.in, cbuf, 1, &nread, NULL))
|
||||
log_fatal ("ReadConsole failed: rc=%d", (int)GetLastError ());
|
||||
if (!nread)
|
||||
continue;
|
||||
if( *cbuf == '\n' )
|
||||
if (*cbuf == '\n')
|
||||
break;
|
||||
|
||||
if( !hidden )
|
||||
if (!hidden)
|
||||
last_prompt_len++;
|
||||
c = *cbuf;
|
||||
if( c == '\t' )
|
||||
if (c == '\t')
|
||||
c = ' ';
|
||||
else if( c > 0xa0 )
|
||||
; /* we don't allow 0xa0, as this is a protected blank which may
|
||||
* confuse the user */
|
||||
else if( iscntrl(c) )
|
||||
else if ( (c >= 0 && c <= 0x1f) || c == 0x7f)
|
||||
continue;
|
||||
if( !(i < n-1) ) {
|
||||
if (!(i < n-1))
|
||||
{
|
||||
n += 50;
|
||||
buf = xrealloc (buf, n);
|
||||
}
|
||||
buf[i++] = c;
|
||||
}
|
||||
|
||||
if( hidden )
|
||||
if (hidden)
|
||||
SetConsoleMode(con.in, DEF_INPMODE );
|
||||
|
||||
#elif defined(__riscos__) || defined(HAVE_W32CE_SYSTEM)
|
||||
do {
|
||||
do
|
||||
{
|
||||
#ifdef HAVE_W32CE_SYSTEM
|
||||
/* Using getchar is not a correct solution but for now it
|
||||
doesn't matter because we have no real console at all. We
|
||||
@ -473,97 +475,121 @@ do_get( const char *prompt, int hidden )
|
||||
#else
|
||||
c = riscos_getchar();
|
||||
#endif
|
||||
if (c == 0xa || c == 0xd) { /* Return || Enter */
|
||||
if (c == 0xa || c == 0xd) /* Return || Enter */
|
||||
{
|
||||
c = (int) '\n';
|
||||
} else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */
|
||||
if (i>0) {
|
||||
}
|
||||
else if (c == 0x8 || c == 0x7f) /* Backspace || Delete */
|
||||
{
|
||||
if (i>0)
|
||||
{
|
||||
i--;
|
||||
if (!hidden) {
|
||||
if (!hidden)
|
||||
{
|
||||
last_prompt_len--;
|
||||
fputc(8, ttyfp);
|
||||
fputc(32, ttyfp);
|
||||
fputc(8, ttyfp);
|
||||
fflush(ttyfp);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
fputc(7, ttyfp);
|
||||
fflush(ttyfp);
|
||||
}
|
||||
continue;
|
||||
} else if (c == (int) '\t') { /* Tab */
|
||||
}
|
||||
else if (c == (int) '\t') /* Tab */
|
||||
{
|
||||
c = ' ';
|
||||
} else if (c > 0xa0) {
|
||||
}
|
||||
else if (c > 0xa0)
|
||||
{
|
||||
; /* we don't allow 0xa0, as this is a protected blank which may
|
||||
* confuse the user */
|
||||
} else if (iscntrl(c)) {
|
||||
}
|
||||
else if (iscntrl(c))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(!(i < n-1)) {
|
||||
if (!(i < n-1))
|
||||
{
|
||||
n += 50;
|
||||
buf = xrealloc (buf, n);
|
||||
}
|
||||
buf[i++] = c;
|
||||
if (!hidden) {
|
||||
if (!hidden)
|
||||
{
|
||||
last_prompt_len++;
|
||||
fputc(c, ttyfp);
|
||||
fflush(ttyfp);
|
||||
}
|
||||
} while (c != '\n');
|
||||
}
|
||||
while (c != '\n');
|
||||
i = (i>0) ? i-1 : 0;
|
||||
|
||||
#else /* Other systems. */
|
||||
if( hidden ) {
|
||||
|
||||
if (hidden)
|
||||
{
|
||||
#ifdef HAVE_TCGETATTR
|
||||
struct termios term;
|
||||
|
||||
if( tcgetattr(fileno(ttyfp), &termsave) )
|
||||
log_fatal("tcgetattr() failed: %s\n", strerror(errno) );
|
||||
if (tcgetattr(fileno(ttyfp), &termsave))
|
||||
log_fatal("tcgetattr() failed: %s\n", strerror(errno));
|
||||
restore_termios = 1;
|
||||
term = termsave;
|
||||
term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||
if( tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
|
||||
log_fatal("tcsetattr() failed: %s\n", strerror(errno) );
|
||||
if (tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
|
||||
log_fatal("tcsetattr() failed: %s\n", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* fixme: How can we avoid that the \n is echoed w/o disabling
|
||||
* canonical mode - w/o this kill_prompt can't work */
|
||||
while( read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n' ) {
|
||||
if( !hidden )
|
||||
while (read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n')
|
||||
{
|
||||
if (!hidden)
|
||||
last_prompt_len++;
|
||||
c = *cbuf;
|
||||
if( c == CONTROL_D )
|
||||
log_info("control d found\n");
|
||||
if( c == '\t' )
|
||||
if (c == CONTROL_D)
|
||||
log_info ("Control-D detected\n");
|
||||
|
||||
if (c == '\t') /* Map tab to a space. */
|
||||
c = ' ';
|
||||
else if( c > 0xa0 )
|
||||
; /* we don't allow 0xa0, as this is a protected blank which may
|
||||
* confuse the user */
|
||||
else if( iscntrl(c) )
|
||||
continue;
|
||||
if( !(i < n-1) ) {
|
||||
else if ( (c >= 0 && c <= 0x1f) || c == 0x7f)
|
||||
continue; /* Skip all other ASCII control characters. */
|
||||
if (!(i < n-1))
|
||||
{
|
||||
n += 50;
|
||||
buf = xrealloc (buf, n );
|
||||
buf = xrealloc (buf, n);
|
||||
}
|
||||
buf[i++] = c;
|
||||
}
|
||||
if( *cbuf != '\n' ) {
|
||||
if (*cbuf != '\n')
|
||||
{
|
||||
buf[0] = CONTROL_D;
|
||||
i = 1;
|
||||
}
|
||||
|
||||
if( hidden ) {
|
||||
if (hidden)
|
||||
{
|
||||
#ifdef HAVE_TCGETATTR
|
||||
if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
|
||||
log_error("tcsetattr() failed: %s\n", strerror(errno) );
|
||||
if (tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave))
|
||||
log_error ("tcsetattr() failed: %s\n", strerror(errno));
|
||||
restore_termios = 0;
|
||||
#endif
|
||||
}
|
||||
#endif /* end unix version */
|
||||
|
||||
buf[i] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Note: This function never returns NULL. */
|
||||
char *
|
||||
tty_get( const char *prompt )
|
||||
{
|
||||
|
@ -226,14 +226,15 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (i != 32 && i != 40)
|
||||
if (i != 32 && i != 40 && i != 64)
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr. */
|
||||
goto out;
|
||||
}
|
||||
for (i=0,si=s; si < se; i++, si +=2)
|
||||
desc->u.fpr[i] = hextobyte(si);
|
||||
for (; i < 20; i++)
|
||||
desc->fprlen = i;
|
||||
for (; i < 32; i++)
|
||||
desc->u.fpr[i]= 0;
|
||||
mode = KEYDB_SEARCH_MODE_FPR;
|
||||
}
|
||||
@ -326,14 +327,17 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
|
||||
}
|
||||
desc->u.fpr[i] = c;
|
||||
}
|
||||
mode = KEYDB_SEARCH_MODE_FPR16;
|
||||
desc->fprlen = 16;
|
||||
for (; i < 32; i++)
|
||||
desc->u.fpr[i]= 0;
|
||||
mode = KEYDB_SEARCH_MODE_FPR;
|
||||
}
|
||||
else if ((hexlength == 40
|
||||
&& (s[hexlength] == 0
|
||||
|| (s[hexlength] == '!' && s[hexlength + 1] == 0)))
|
||||
|| (!hexprefix && hexlength == 41 && *s == '0'))
|
||||
{
|
||||
/* SHA1/RMD160 fingerprint. */
|
||||
/* SHA1 fingerprint. */
|
||||
int i;
|
||||
if (hexlength == 41)
|
||||
s++;
|
||||
@ -347,7 +351,32 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
|
||||
}
|
||||
desc->u.fpr[i] = c;
|
||||
}
|
||||
mode = KEYDB_SEARCH_MODE_FPR20;
|
||||
desc->fprlen = 20;
|
||||
for (; i < 32; i++)
|
||||
desc->u.fpr[i]= 0;
|
||||
mode = KEYDB_SEARCH_MODE_FPR;
|
||||
}
|
||||
else if ((hexlength == 64
|
||||
&& (s[hexlength] == 0
|
||||
|| (s[hexlength] == '!' && s[hexlength + 1] == 0)))
|
||||
|| (!hexprefix && hexlength == 65 && *s == '0'))
|
||||
{
|
||||
/* SHA256 fingerprint. */
|
||||
int i;
|
||||
if (hexlength == 65)
|
||||
s++;
|
||||
for (i=0; i < 32; i++, s+=2)
|
||||
{
|
||||
int c = hextobyte(s);
|
||||
if (c == -1)
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_INV_USER_ID);
|
||||
goto out;
|
||||
}
|
||||
desc->u.fpr[i] = c;
|
||||
}
|
||||
desc->fprlen = 32;
|
||||
mode = KEYDB_SEARCH_MODE_FPR;
|
||||
}
|
||||
else if (!hexprefix)
|
||||
{
|
||||
@ -367,15 +396,21 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
|
||||
desc->u.fpr[i] = c;
|
||||
}
|
||||
if (i == 20)
|
||||
mode = KEYDB_SEARCH_MODE_FPR20;
|
||||
{
|
||||
desc->fprlen = 20;
|
||||
mode = KEYDB_SEARCH_MODE_FPR;
|
||||
}
|
||||
for (; i < 32; i++)
|
||||
desc->u.fpr[i]= 0;
|
||||
}
|
||||
if (!mode)
|
||||
{
|
||||
/* Still not found. Now check for a space separated
|
||||
OpenPGP v4 fingerprint like:
|
||||
8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
|
||||
or
|
||||
8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
|
||||
* OpenPGP v4 fingerprint like:
|
||||
* 8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
|
||||
* or
|
||||
* 8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
|
||||
* FIXME: Support OpenPGP v5 fingerprint
|
||||
*/
|
||||
hexlength = strspn (s, " 0123456789abcdefABCDEF");
|
||||
if (s[hexlength] && s[hexlength] != ' ')
|
||||
@ -409,7 +444,12 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
|
||||
s += 2;
|
||||
}
|
||||
if (i == 20)
|
||||
mode = KEYDB_SEARCH_MODE_FPR20;
|
||||
{
|
||||
desc->fprlen = 20;
|
||||
mode = KEYDB_SEARCH_MODE_FPR;
|
||||
}
|
||||
for (; i < 32; i++)
|
||||
desc->u.fpr[i]= 0;
|
||||
}
|
||||
}
|
||||
if (!mode) /* Default to substring search. */
|
||||
|
@ -39,7 +39,10 @@
|
||||
* libgpg-error version. Define them here.
|
||||
* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
|
||||
*/
|
||||
|
||||
#if GPG_ERROR_VERSION_NUMBER < 0x012400 /* 1.36 */
|
||||
#define GPG_ERR_NO_AUTH 314
|
||||
#define GPG_ERR_BAD_AUTH 315
|
||||
#endif /*GPG_ERROR_VERSION_NUMBER*/
|
||||
|
||||
/* Hash function used with libksba. */
|
||||
#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
|
||||
@ -189,6 +192,7 @@ gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata,
|
||||
int get_pk_algo_from_key (gcry_sexp_t key);
|
||||
int get_pk_algo_from_canon_sexp (const unsigned char *keydata,
|
||||
size_t keydatalen);
|
||||
char *pubkey_algo_string (gcry_sexp_t s_pkey);
|
||||
|
||||
/*-- convert.c --*/
|
||||
int hex2bin (const char *string, void *buffer, size_t length);
|
||||
@ -201,7 +205,8 @@ char *hex2str_alloc (const char *hexstring, size_t *r_count);
|
||||
|
||||
/*-- percent.c --*/
|
||||
char *percent_plus_escape (const char *string);
|
||||
char *percent_data_escape (const void *data, size_t datalen);
|
||||
char *percent_data_escape (int plus, const char *prefix,
|
||||
const void *data, size_t datalen);
|
||||
char *percent_plus_unescape (const char *string, int nulrepl);
|
||||
char *percent_unescape (const char *string, int nulrepl);
|
||||
|
||||
@ -210,8 +215,11 @@ size_t percent_unescape_inplace (char *string, int nulrepl);
|
||||
|
||||
/*-- openpgp-oid.c --*/
|
||||
gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
|
||||
char *openpgp_oidbuf_to_str (const unsigned char *buf, size_t len);
|
||||
char *openpgp_oid_to_str (gcry_mpi_t a);
|
||||
int openpgp_oidbuf_is_ed25519 (const void *buf, size_t len);
|
||||
int openpgp_oid_is_ed25519 (gcry_mpi_t a);
|
||||
int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len);
|
||||
int openpgp_oid_is_cv25519 (gcry_mpi_t a);
|
||||
const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits);
|
||||
const char *openpgp_oid_to_curve (const char *oid, int canon);
|
||||
@ -258,6 +266,13 @@ void gnupg_module_name_flush_some (void);
|
||||
void gnupg_set_builddir (const char *newdir);
|
||||
|
||||
|
||||
/* A list of constants to identify protocols. This is used by tools
|
||||
* which need to distinguish between the different protocols
|
||||
* implemented by GnuPG. May be used as bit flags. */
|
||||
#define GNUPG_PROTOCOL_OPENPGP 1 /* The one and only (gpg). */
|
||||
#define GNUPG_PROTOCOL_CMS 2 /* The core of S/MIME (gpgsm) */
|
||||
#define GNUPG_PROTOCOL_SSH_AGENT 4 /* Out ssh-agent implementation */
|
||||
|
||||
|
||||
/*-- gpgrlhelp.c --*/
|
||||
void gnupg_rl_initialize (void);
|
||||
@ -299,6 +314,7 @@ void print_hexstring (FILE *fp, const void *buffer, size_t length,
|
||||
int reserved);
|
||||
char *try_make_printable_string (const void *p, size_t n, int delim);
|
||||
char *make_printable_string (const void *p, size_t n, int delim);
|
||||
char *decode_c_string (const char *src);
|
||||
|
||||
int is_file_compressed (const char *s, int *ret_rc);
|
||||
|
||||
|
35
configure.ac
35
configure.ac
@ -129,7 +129,10 @@ GNUPG_BUILD_PROGRAM(symcryptrun, no)
|
||||
# We use gpgtar to unpack test data, hence we always build it. If the
|
||||
# user opts out, we simply don't install it.
|
||||
GNUPG_BUILD_PROGRAM(gpgtar, yes)
|
||||
GNUPG_BUILD_PROGRAM(wks-tools, no)
|
||||
# We also install the gpg-wks-server tool by default but disable it
|
||||
# later for platforms where it can't be build.
|
||||
GNUPG_BUILD_PROGRAM(wks-tools, yes)
|
||||
|
||||
|
||||
AC_SUBST(PACKAGE)
|
||||
AC_SUBST(PACKAGE_GT)
|
||||
@ -507,6 +510,7 @@ AH_BOTTOM([
|
||||
#define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
|
||||
#define GNUPG_PUBLIC_KEYS_DIR "public-keys.d"
|
||||
#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
|
||||
#define GNUPG_CACHE_DIR "cache.d"
|
||||
|
||||
#define GNUPG_DEF_COPYRIGHT_LINE \
|
||||
"Copyright (C) 2018 Free Software Foundation, Inc."
|
||||
@ -623,7 +627,6 @@ AC_ARG_VAR(YAT2M, [tool to convert texi to man pages])
|
||||
AM_CONDITIONAL(HAVE_YAT2M, test -n "$ac_cv_path_YAT2M")
|
||||
AC_ISC_POSIX
|
||||
AC_SYS_LARGEFILE
|
||||
GNUPG_CHECK_USTAR
|
||||
|
||||
|
||||
# We need to compile and run a program on the build machine. A
|
||||
@ -682,6 +685,7 @@ case "${host}" in
|
||||
try_gettext="no"
|
||||
use_simple_gettext=yes
|
||||
mmap_needed=no
|
||||
build_wks_tools=no
|
||||
;;
|
||||
i?86-emx-os2 | i?86-*-os2*emx )
|
||||
# OS/2 with the EMX environment
|
||||
@ -689,6 +693,7 @@ case "${host}" in
|
||||
AC_DEFINE(HAVE_DRIVE_LETTERS)
|
||||
have_dosish_system=yes
|
||||
try_gettext="no"
|
||||
build_wks_tools=no
|
||||
;;
|
||||
|
||||
i?86-*-msdosdjgpp*)
|
||||
@ -697,6 +702,7 @@ case "${host}" in
|
||||
AC_DEFINE(HAVE_DRIVE_LETTERS)
|
||||
have_dosish_system=yes
|
||||
try_gettext="no"
|
||||
build_wks_tools=no
|
||||
;;
|
||||
|
||||
*-*-hpux*)
|
||||
@ -727,6 +733,7 @@ case "${host}" in
|
||||
# Android is fully utf-8 and we do not want to use iconv to
|
||||
# keeps things simple
|
||||
require_iconv=no
|
||||
build_wks_tools=no
|
||||
;;
|
||||
*-apple-darwin*)
|
||||
AC_DEFINE(_DARWIN_C_SOURCE, 900000L,
|
||||
@ -1361,6 +1368,7 @@ AC_CHECK_SIZEOF(unsigned short)
|
||||
AC_CHECK_SIZEOF(unsigned int)
|
||||
AC_CHECK_SIZEOF(unsigned long)
|
||||
AC_CHECK_SIZEOF(unsigned long long)
|
||||
AC_CHECK_SIZEOF(size_t)
|
||||
AC_HEADER_TIME
|
||||
AC_CHECK_SIZEOF(time_t,,[[
|
||||
#include <stdio.h>
|
||||
@ -1394,16 +1402,16 @@ AC_FUNC_FSEEKO
|
||||
AC_FUNC_VPRINTF
|
||||
AC_FUNC_FORK
|
||||
AC_CHECK_FUNCS([atexit canonicalize_file_name clock_gettime ctermid \
|
||||
fcntl flockfile fsync ftello ftruncate funlockfile \
|
||||
getaddrinfo getenv getpagesize getpwnam getpwuid \
|
||||
getrlimit getrusage gettimeofday gmtime_r \
|
||||
inet_ntop inet_pton isascii lstat \
|
||||
memicmp memmove memrchr mmap nl_langinfo pipe \
|
||||
raise rand setenv setlocale setrlimit sigaction \
|
||||
sigprocmask stat stpcpy strcasecmp strerror strftime \
|
||||
stricmp strlwr strncasecmp strpbrk strsep \
|
||||
strtol strtoul strtoull tcgetattr timegm times \
|
||||
ttyname unsetenv wait4 waitpid ])
|
||||
explicit_bzero fcntl flockfile fsync ftello \
|
||||
ftruncate funlockfile getaddrinfo getenv getpagesize \
|
||||
getpwnam getpwuid getrlimit getrusage gettimeofday \
|
||||
gmtime_r inet_ntop inet_pton isascii lstat memicmp \
|
||||
memmove memrchr mmap nl_langinfo pipe raise rand \
|
||||
setenv setlocale setrlimit sigaction sigprocmask \
|
||||
stat stpcpy strcasecmp strerror strftime stricmp \
|
||||
strlwr strncasecmp strpbrk strsep strtol strtoul \
|
||||
strtoull tcgetattr timegm times ttyname unsetenv \
|
||||
wait4 waitpid ])
|
||||
|
||||
# On some systems (e.g. Solaris) nanosleep requires linking to librl.
|
||||
# Given that we use nanosleep only as an optimization over a select
|
||||
@ -1482,7 +1490,7 @@ if test "$use_regex" = yes ; then
|
||||
use_regex=no
|
||||
else
|
||||
if test x"$cross_compiling" = xyes; then
|
||||
AC_MSG_WARN([cross compiling; assuming regexp libray is not broken])
|
||||
AC_MSG_WARN([cross compiling; assuming regexp library is not broken])
|
||||
else
|
||||
AC_CACHE_CHECK([whether your system's regexp library is broken],
|
||||
[gnupg_cv_regex_broken],
|
||||
@ -2046,7 +2054,6 @@ agent/Makefile
|
||||
scd/Makefile
|
||||
g13/Makefile
|
||||
dirmngr/Makefile
|
||||
tools/gpg-zip
|
||||
tools/Makefile
|
||||
doc/Makefile
|
||||
tests/Makefile
|
||||
|
@ -120,7 +120,7 @@ t_common_ldadd = $(libcommon) $(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) \
|
||||
$(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \
|
||||
$(DNSLIBS) $(LIBINTL) $(LIBICONV)
|
||||
|
||||
module_tests =
|
||||
module_tests = t-http-basic
|
||||
|
||||
if USE_LDAP
|
||||
module_tests += t-ldap-parse-uri
|
||||
@ -151,6 +151,15 @@ t_http_CFLAGS = -DWITHOUT_NPTH=1 $(USE_C99_CFLAGS) \
|
||||
t_http_LDADD = $(t_common_ldadd) \
|
||||
$(NTBTLS_LIBS) $(KSBA_LIBS) $(LIBGNUTLS_LIBS) $(DNSLIBS)
|
||||
|
||||
t_http_basic_SOURCES = $(t_common_src) t-http-basic.c http.c \
|
||||
dns-stuff.c http-common.c
|
||||
t_http_basic_CFLAGS = -DWITHOUT_NPTH=1 $(USE_C99_CFLAGS) \
|
||||
$(LIBGCRYPT_CFLAGS) $(NTBTLS_CFLAGS) $(LIBGNUTLS_CFLAGS) \
|
||||
$(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(KSBA_CFLAGS)
|
||||
t_http_basic_LDADD = $(t_common_ldadd) \
|
||||
$(NTBTLS_LIBS) $(KSBA_LIBS) $(LIBGNUTLS_LIBS) $(DNSLIBS)
|
||||
|
||||
|
||||
t_ldap_parse_uri_SOURCES = \
|
||||
t-ldap-parse-uri.c ldap-parse-uri.c ldap-parse-uri.h \
|
||||
http.c http-common.c dns-stuff.c \
|
||||
|
@ -85,7 +85,7 @@ int cdb_make_put(struct cdb_make *cdbmp,
|
||||
const void *key, cdbi_t klen,
|
||||
const void *val, cdbi_t vlen,
|
||||
int flag);
|
||||
#define CDB_PUT_ADD 0 /* add unconditionnaly, like cdb_make_add() */
|
||||
#define CDB_PUT_ADD 0 /* add unconditionally, like cdb_make_add() */
|
||||
#define CDB_PUT_REPLACE 1 /* replace: do not place to index OLD record */
|
||||
#define CDB_PUT_INSERT 2 /* add only if not already exists */
|
||||
#define CDB_PUT_WARN 3 /* add unconditionally but ret. 1 if exists */
|
||||
|
@ -19,7 +19,7 @@
|
||||
length, meaning that corresponding hash table is empty.
|
||||
|
||||
Right after toc section, data section follows without any
|
||||
alingment. It consists of series of records, each is a key length,
|
||||
alignment. It consists of series of records, each is a key length,
|
||||
value (data) length, key and value. Again, key and value length
|
||||
are 4-byte unsigned integers. Each next record follows previous
|
||||
without any special alignment.
|
||||
@ -52,7 +52,7 @@
|
||||
beginning of a table). When hash value in question is found in
|
||||
hash table, look to key of corresponding record, comparing it with
|
||||
key in question. If them of the same length and equals to each
|
||||
other, then record is found, overwise, repeat with next hash table
|
||||
other, then record is found, otherwise, repeat with next hash table
|
||||
slot. Note that there may be several records with the same key.
|
||||
*/
|
||||
|
||||
@ -245,7 +245,7 @@ cdb_find(struct cdb *cdbp, const void *key, cdbi_t klen)
|
||||
pos = cdb_unpack(htp); /* htab position */
|
||||
if (n > (cdbp->cdb_fsize >> 3) /* overflow of httodo ? */
|
||||
|| pos > cdbp->cdb_fsize /* htab start within file ? */
|
||||
|| httodo > cdbp->cdb_fsize - pos) /* entrie htab within file ? */
|
||||
|| httodo > cdbp->cdb_fsize - pos) /* htab entry within file ? */
|
||||
{
|
||||
gpg_err_set_errno (EPROTO);
|
||||
return -1;
|
||||
|
@ -1250,13 +1250,15 @@ crl_cache_deinit (void)
|
||||
}
|
||||
|
||||
|
||||
/* Delete the cache from disk. Return 0 on success.*/
|
||||
/* Delete the cache from disk and memory. Return 0 on success.*/
|
||||
int
|
||||
crl_cache_flush (void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
crl_cache_deinit ();
|
||||
rc = cleanup_cache_dir (0)? -1 : 0;
|
||||
crl_cache_init ();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -1782,7 +1784,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
|
||||
ksba_sexp_t keyid;
|
||||
|
||||
/* We need to look for the issuer only after having read
|
||||
all items. The issuer itselfs comes before the items
|
||||
all items. The issuer itself comes before the items
|
||||
but the optional authorityKeyIdentifier comes after the
|
||||
items. */
|
||||
err = ksba_crl_get_issuer (crl, &crlissuer);
|
||||
@ -1907,7 +1909,7 @@ get_crl_number (ksba_crl_t crl)
|
||||
|
||||
|
||||
/* Return the authorityKeyIdentifier or NULL if it is not available.
|
||||
The issuer name may consists of several parts - they are delimted by
|
||||
The issuer name may consists of several parts - they are delimited by
|
||||
0x01. */
|
||||
static char *
|
||||
get_auth_key_id (ksba_crl_t crl, char **serialno)
|
||||
|
@ -338,7 +338,7 @@ static int active_connections;
|
||||
* thread to run background network tasks. */
|
||||
static int network_activity_seen;
|
||||
|
||||
/* A list of filenames registred with --hkp-cacert. */
|
||||
/* A list of filenames registered with --hkp-cacert. */
|
||||
static strlist_t hkp_cacert_filenames;
|
||||
|
||||
|
||||
@ -411,7 +411,7 @@ my_strusage( int level )
|
||||
|
||||
/* Callback from libksba to hash a provided buffer. Our current
|
||||
implementation does only allow SHA-1 for hashing. This may be
|
||||
extended by mapping the name, testing for algorithm availibility
|
||||
extended by mapping the name, testing for algorithm availability
|
||||
and adjust the length checks accordingly. */
|
||||
static gpg_error_t
|
||||
my_ksba_hash_buffer (void *arg, const char *oid,
|
||||
@ -520,7 +520,7 @@ set_tor_mode (void)
|
||||
{
|
||||
if (dirmngr_use_tor ())
|
||||
{
|
||||
/* Enable Tor mode and when called again force a new curcuit
|
||||
/* Enable Tor mode and when called again force a new circuit
|
||||
* (e.g. on SIGHUP). */
|
||||
enable_dns_tormode (1);
|
||||
if (assuan_sock_set_flag (ASSUAN_INVALID_FD, "tor-mode", 1))
|
||||
@ -752,7 +752,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
||||
}
|
||||
|
||||
|
||||
/* This fucntion is called after option parsing to adjust some values
|
||||
/* This function is called after option parsing to adjust some values
|
||||
* and call option setup functions. */
|
||||
static void
|
||||
post_option_parsing (void)
|
||||
@ -763,7 +763,6 @@ post_option_parsing (void)
|
||||
opt.connect_quick_timeout = opt.connect_timeout;
|
||||
|
||||
set_debug ();
|
||||
set_tor_mode ();
|
||||
}
|
||||
|
||||
|
||||
@ -802,6 +801,7 @@ 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
|
||||
@ -877,7 +877,6 @@ main (int argc, char **argv)
|
||||
assuan_set_malloc_hooks (&malloc_hooks);
|
||||
assuan_set_assuan_log_prefix (log_get_prefix (NULL));
|
||||
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
|
||||
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
|
||||
assuan_sock_init ();
|
||||
setup_libassuan_logging (&opt.debug, dirmngr_assuan_log_monitor);
|
||||
|
||||
@ -1090,7 +1089,12 @@ main (int argc, char **argv)
|
||||
log_printf ("\n");
|
||||
}
|
||||
|
||||
/* Note that we do not run set_tor_mode in --gpgconf-list mode
|
||||
* because it will attempt to connect to the tor client and that can
|
||||
* be time consuming. */
|
||||
post_option_parsing ();
|
||||
if (cmd != aGPGConfTest && cmd != aGPGConfList)
|
||||
set_tor_mode ();
|
||||
|
||||
/* Get LDAP server list from file. */
|
||||
#if USE_LDAP
|
||||
@ -1143,6 +1147,7 @@ main (int argc, char **argv)
|
||||
thread_init ();
|
||||
cert_cache_init (hkp_cacert_filenames);
|
||||
crl_cache_init ();
|
||||
ks_hkp_init ();
|
||||
http_register_netactivity_cb (netactivity_action);
|
||||
start_command_handler (ASSUAN_INVALID_FD, 0);
|
||||
shutdown_reaper ();
|
||||
@ -1178,6 +1183,7 @@ main (int argc, char **argv)
|
||||
thread_init ();
|
||||
cert_cache_init (hkp_cacert_filenames);
|
||||
crl_cache_init ();
|
||||
ks_hkp_init ();
|
||||
http_register_netactivity_cb (netactivity_action);
|
||||
handle_connections (3);
|
||||
shutdown_reaper ();
|
||||
@ -1399,6 +1405,7 @@ main (int argc, char **argv)
|
||||
thread_init ();
|
||||
cert_cache_init (hkp_cacert_filenames);
|
||||
crl_cache_init ();
|
||||
ks_hkp_init ();
|
||||
http_register_netactivity_cb (netactivity_action);
|
||||
handle_connections (fd);
|
||||
shutdown_reaper ();
|
||||
@ -1421,6 +1428,7 @@ main (int argc, char **argv)
|
||||
thread_init ();
|
||||
cert_cache_init (hkp_cacert_filenames);
|
||||
crl_cache_init ();
|
||||
ks_hkp_init ();
|
||||
if (!argc)
|
||||
rc = crl_cache_load (&ctrlbuf, NULL);
|
||||
else
|
||||
@ -1444,6 +1452,7 @@ main (int argc, char **argv)
|
||||
thread_init ();
|
||||
cert_cache_init (hkp_cacert_filenames);
|
||||
crl_cache_init ();
|
||||
ks_hkp_init ();
|
||||
rc = crl_fetch (&ctrlbuf, argv[0], &reader);
|
||||
if (rc)
|
||||
log_error (_("fetching CRL from '%s' failed: %s\n"),
|
||||
@ -1859,6 +1868,7 @@ dirmngr_sighup_action (void)
|
||||
log_info (_("SIGHUP received - "
|
||||
"re-reading configuration and flushing caches\n"));
|
||||
reread_configuration ();
|
||||
set_tor_mode ();
|
||||
cert_cache_deinit (0);
|
||||
crl_cache_deinit ();
|
||||
cert_cache_init (hkp_cacert_filenames);
|
||||
|
@ -218,7 +218,7 @@ int dirmngr_use_tor (void);
|
||||
/*-- Various housekeeping functions. --*/
|
||||
void ks_hkp_housekeeping (time_t curtime);
|
||||
void ks_hkp_reload (void);
|
||||
|
||||
void ks_hkp_init (void);
|
||||
|
||||
/*-- server.c --*/
|
||||
ldap_server_t get_ldapservers_from_ctrl (ctrl_t ctrl);
|
||||
|
@ -417,9 +417,9 @@ set_timeout (my_opt_t myopt)
|
||||
sec_attr.nLength = sizeof sec_attr;
|
||||
sec_attr.bInheritHandle = FALSE;
|
||||
|
||||
/* Create a manual resetable timer. */
|
||||
/* Create a manual resettable timer. */
|
||||
timer = CreateWaitableTimer (NULL, TRUE, NULL);
|
||||
/* Intially set the timer. */
|
||||
/* Initially set the timer. */
|
||||
SetWaitableTimer (timer, &due_time, 0, NULL, NULL, 0);
|
||||
|
||||
if (CreateThread (&sec_attr, 0, alarm_thread, timer, 0, &tid))
|
||||
|
@ -151,7 +151,7 @@ static char tor_socks_password[20];
|
||||
|
||||
|
||||
#ifdef USE_LIBDNS
|
||||
/* Libdns gobal data. */
|
||||
/* Libdns global data. */
|
||||
struct libdns_s
|
||||
{
|
||||
struct dns_resolv_conf *resolv_conf;
|
||||
@ -701,6 +701,11 @@ libdns_res_open (ctrl_t ctrl, struct dns_resolver **r_res)
|
||||
gpg_error_t err;
|
||||
struct dns_resolver *res;
|
||||
int derr;
|
||||
struct dns_options opts = { 0 };
|
||||
|
||||
opts.socks_host = &libdns.socks_host;
|
||||
opts.socks_user = tor_socks_user;
|
||||
opts.socks_password = tor_socks_password;
|
||||
|
||||
*r_res = NULL;
|
||||
|
||||
@ -726,10 +731,7 @@ libdns_res_open (ctrl_t ctrl, struct dns_resolver **r_res)
|
||||
set_dns_timeout (0);
|
||||
|
||||
res = dns_res_open (libdns.resolv_conf, libdns.hosts, libdns.hints, NULL,
|
||||
dns_opts (.socks_host = &libdns.socks_host,
|
||||
.socks_user = tor_socks_user,
|
||||
.socks_password = tor_socks_password ),
|
||||
&derr);
|
||||
&opts, &derr);
|
||||
if (!res)
|
||||
return libdns_error_to_gpg_error (derr);
|
||||
|
||||
@ -1056,16 +1058,17 @@ resolve_name_standard (ctrl_t ctrl, const char *name, unsigned short port,
|
||||
|
||||
|
||||
/* This a wrapper around getaddrinfo with slightly different semantics.
|
||||
NAME is the name to resolve.
|
||||
PORT is the requested port or 0.
|
||||
WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
|
||||
WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
|
||||
|
||||
On success the result is stored in a linked list with the head
|
||||
stored at the address R_AI; the caller must call gpg_addrinfo_free
|
||||
on this. If R_CANONNAME is not NULL the official name of the host
|
||||
is stored there as a malloced string; if that name is not available
|
||||
NULL is stored. */
|
||||
* NAME is the name to resolve.
|
||||
* PORT is the requested port or 0.
|
||||
* WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
|
||||
* WANT_SOCKETTYPE is either 0 for any socket type
|
||||
* or SOCK_STREAM or SOCK_DGRAM.
|
||||
*
|
||||
* On success the result is stored in a linked list with the head
|
||||
* stored at the address R_AI; the caller must call free_dns_addrinfo
|
||||
* on this. If R_CANONNAME is not NULL the official name of the host
|
||||
* is stored there as a malloced string; if that name is not available
|
||||
* NULL is stored. */
|
||||
gpg_error_t
|
||||
resolve_dns_name (ctrl_t ctrl, const char *name, unsigned short port,
|
||||
int want_family, int want_socktype,
|
||||
@ -1167,7 +1170,7 @@ resolve_addr_libdns (ctrl_t ctrl,
|
||||
struct dns_rr_i rri;
|
||||
|
||||
memset (&rri, 0, sizeof rri);
|
||||
dns_rr_i_init (&rri, ans);
|
||||
dns_rr_i_init (&rri);
|
||||
rri.section = DNS_S_ALL & ~DNS_S_QD;
|
||||
rri.name = host;
|
||||
rri.type = DNS_T_PTR;
|
||||
@ -1458,7 +1461,7 @@ get_dns_cert_libdns (ctrl_t ctrl, const char *name, int want_certtype,
|
||||
goto leave;
|
||||
|
||||
memset (&rri, 0, sizeof rri);
|
||||
dns_rr_i_init (&rri, ans);
|
||||
dns_rr_i_init (&rri);
|
||||
rri.section = DNS_S_ALL & ~DNS_S_QD;
|
||||
rri.name = host;
|
||||
rri.type = qtype;
|
||||
@ -1888,7 +1891,7 @@ getsrv_libdns (ctrl_t ctrl,
|
||||
goto leave;
|
||||
|
||||
memset (&rri, 0, sizeof rri);
|
||||
dns_rr_i_init (&rri, ans);
|
||||
dns_rr_i_init (&rri);
|
||||
rri.section = DNS_S_ALL & ~DNS_S_QD;
|
||||
rri.name = host;
|
||||
rri.type = DNS_T_SRV;
|
||||
|
173
dirmngr/dns.c
173
dirmngr/dns.c
@ -77,6 +77,7 @@ typedef int socket_fd_t;
|
||||
#include <netdb.h> /* struct addrinfo */
|
||||
#endif
|
||||
|
||||
#include "gpgrt.h" /* For GGPRT_GCC_VERSION */
|
||||
#include "dns.h"
|
||||
|
||||
|
||||
@ -943,10 +944,11 @@ static int dns_sa_cmp(void *a, void *b) {
|
||||
#if _WIN32
|
||||
static int dns_inet_pton(int af, const void *src, void *dst) {
|
||||
union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
|
||||
int size_of_u = (int)sizeof u;
|
||||
|
||||
u.sin.sin_family = af;
|
||||
|
||||
if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
|
||||
if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &size_of_u))
|
||||
return -1;
|
||||
|
||||
switch (af) {
|
||||
@ -1124,6 +1126,7 @@ static inline _Bool dns_isgraph(unsigned char c) {
|
||||
|
||||
static int dns_poll(int fd, short events, int timeout) {
|
||||
fd_set rset, wset;
|
||||
struct timeval tv = { timeout, 0 };
|
||||
|
||||
if (!events)
|
||||
return 0;
|
||||
@ -1140,7 +1143,7 @@ static int dns_poll(int fd, short events, int timeout) {
|
||||
if (events & DNS_POLLOUT)
|
||||
FD_SET(fd, &wset);
|
||||
|
||||
select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
|
||||
select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &tv : NULL);
|
||||
|
||||
return 0;
|
||||
} /* dns_poll() */
|
||||
@ -1214,9 +1217,10 @@ static size_t dns_send_nopipe(int fd, const void *src, size_t len, int flags, dn
|
||||
|
||||
if (!sigismember(&pending, SIGPIPE)) {
|
||||
int saved = error;
|
||||
const struct timespec ts = { 0, 0 };
|
||||
|
||||
if (!count && error == EPIPE) {
|
||||
while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
|
||||
while (-1 == sigtimedwait(&piped, NULL, &ts) && errno == EINTR)
|
||||
;;
|
||||
}
|
||||
|
||||
@ -1832,7 +1836,7 @@ static void dns_p_free(struct dns_packet *P) {
|
||||
} /* dns_p_free() */
|
||||
|
||||
|
||||
/* convience routine to free any existing packet before storing new packet */
|
||||
/* convenience routine to free any existing packet before storing new packet */
|
||||
static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) {
|
||||
dns_p_free(*dst);
|
||||
|
||||
@ -2213,7 +2217,8 @@ static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
|
||||
|
||||
|
||||
void dns_p_dump(struct dns_packet *P, FILE *fp) {
|
||||
dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
|
||||
struct dns_rr_i _I = { 0 };
|
||||
dns_p_dump3(P, &_I, fp);
|
||||
} /* dns_p_dump() */
|
||||
|
||||
|
||||
@ -2792,8 +2797,7 @@ size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns
|
||||
{ error = ENAMETOOLONG; goto error; }
|
||||
|
||||
for (depth = 0; depth < 7; depth++) {
|
||||
dns_rr_i_init(memset(&i, 0, sizeof i), P);
|
||||
|
||||
memset(&i, 0, sizeof i);
|
||||
i.section = DNS_S_ALL & ~DNS_S_QD;
|
||||
i.name = host;
|
||||
i.type = DNS_T_CNAME;
|
||||
@ -3218,15 +3222,11 @@ int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, str
|
||||
} /* dns_rr_i_shuffle() */
|
||||
|
||||
|
||||
struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) {
|
||||
void dns_rr_i_init(struct dns_rr_i *i) {
|
||||
static const struct dns_rr_i i_initializer;
|
||||
|
||||
(void)P;
|
||||
|
||||
i->state = i_initializer.state;
|
||||
i->saved = i->state;
|
||||
|
||||
return i;
|
||||
} /* dns_rr_i_init() */
|
||||
|
||||
|
||||
@ -3262,6 +3262,7 @@ unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct
|
||||
|
||||
return count;
|
||||
error:
|
||||
if (error_)
|
||||
*error_ = error;
|
||||
|
||||
return count;
|
||||
@ -5274,7 +5275,8 @@ error:
|
||||
|
||||
|
||||
struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
|
||||
struct dns_packet *P = dns_p_new(512);
|
||||
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
|
||||
struct dns_packet *P = dns_p_init(&_P.p, 512);
|
||||
struct dns_packet *A = 0;
|
||||
struct dns_rr rr;
|
||||
struct dns_hosts_entry *ent;
|
||||
@ -6835,6 +6837,7 @@ unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, s
|
||||
|
||||
|
||||
struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
|
||||
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
|
||||
struct dns_packet *A, *P;
|
||||
struct dns_rr rr;
|
||||
char zone[DNS_D_MAXNAME + 1];
|
||||
@ -6843,8 +6846,11 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q
|
||||
struct sockaddr *sa;
|
||||
socklen_t slen;
|
||||
int error;
|
||||
struct dns_rr_i _I = { 0 };
|
||||
|
||||
if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
|
||||
_I.section = DNS_S_QUESTION;
|
||||
|
||||
if (!dns_rr_grep(&rr, 1, &_I, Q, &error))
|
||||
goto error;
|
||||
|
||||
if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
|
||||
@ -6852,7 +6858,7 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q
|
||||
else if (zlen >= sizeof zone)
|
||||
goto toolong;
|
||||
|
||||
P = dns_p_new(512);
|
||||
P = dns_p_init(&_P.p, 512);
|
||||
dns_header(P)->qr = 1;
|
||||
|
||||
if ((error = dns_rr_copy(P, &rr, Q)))
|
||||
@ -7110,7 +7116,8 @@ static int dns_socket(struct sockaddr *local, int type, int *error_) {
|
||||
|
||||
#if defined SO_NOSIGPIPE
|
||||
if (type != SOCK_DGRAM) {
|
||||
if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int)))
|
||||
const int v = 1;
|
||||
if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &v, sizeof (int)))
|
||||
goto soerr;
|
||||
}
|
||||
#endif
|
||||
@ -7486,11 +7493,12 @@ error:
|
||||
|
||||
static _Bool dns_so_tcp_keep(struct dns_socket *so) {
|
||||
struct sockaddr_storage remote;
|
||||
socklen_t l = sizeof remote;
|
||||
|
||||
if (so->tcp == -1)
|
||||
return 0;
|
||||
|
||||
if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote }))
|
||||
if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &l))
|
||||
return 0;
|
||||
|
||||
return 0 == dns_sa_cmp(&remote, &so->remote);
|
||||
@ -7521,9 +7529,13 @@ static unsigned char *dns_so_tcp_recv_buffer(struct dns_socket *so) {
|
||||
}
|
||||
|
||||
|
||||
#if defined __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warray-bounds"
|
||||
|
||||
#if GPGRT_GCC_VERSION >= 80000
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#elif defined __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Warray-bounds"
|
||||
#endif
|
||||
|
||||
static int dns_so_tcp_send(struct dns_socket *so) {
|
||||
@ -7589,8 +7601,10 @@ static int dns_so_tcp_recv(struct dns_socket *so) {
|
||||
return 0;
|
||||
} /* dns_so_tcp_recv() */
|
||||
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#if GPGRT_GCC_VERSION >= 80000
|
||||
# pragma GCC diagnostic pop
|
||||
#elif __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
@ -7634,7 +7648,7 @@ retry:
|
||||
goto udp_connect_retry;
|
||||
} else if (error == ECONNREFUSED)
|
||||
/* Error for previous socket operation may
|
||||
be reserverd asynchronously. */
|
||||
be reserverd(?) asynchronously. */
|
||||
goto udp_connect_retry;
|
||||
|
||||
if (error)
|
||||
@ -8449,7 +8463,8 @@ error:
|
||||
|
||||
|
||||
static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
|
||||
struct dns_packet *P = dns_p_new(512);
|
||||
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
|
||||
struct dns_packet *P = dns_p_init(&_P.p, 512);
|
||||
char qname[DNS_D_MAXNAME + 1];
|
||||
size_t qlen;
|
||||
enum dns_type qtype;
|
||||
@ -8521,12 +8536,22 @@ static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_r
|
||||
struct dns_ns ns;
|
||||
int cmp, error;
|
||||
|
||||
if (!(error = dns_ns_parse(&ns, a, P)))
|
||||
glued[0] = !!dns_rr_grep(&x, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
|
||||
if (!(error = dns_ns_parse(&ns, a, P))) {
|
||||
struct dns_rr_i _I = { 0 };
|
||||
|
||||
if (!(error = dns_ns_parse(&ns, b, P)))
|
||||
glued[1] = !!dns_rr_grep(&y, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
|
||||
_I.section = (DNS_S_ALL & ~DNS_S_QD);
|
||||
_I.name = ns.host;
|
||||
_I.type = DNS_T_A;
|
||||
glued[0] = !!dns_rr_grep(&x, 1, &_I, P, &error);
|
||||
}
|
||||
if (!(error = dns_ns_parse(&ns, b, P))) {
|
||||
struct dns_rr_i _I = { 0 };
|
||||
|
||||
_I.section = (DNS_S_ALL & ~DNS_S_QD);
|
||||
_I.name = ns.host;
|
||||
_I.type = DNS_T_A;
|
||||
glued[1] = !!dns_rr_grep(&y, 1, &_I, P, &error);
|
||||
}
|
||||
if ((cmp = glued[1] - glued[0])) {
|
||||
return cmp;
|
||||
} else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) {
|
||||
@ -8727,7 +8752,7 @@ exec:
|
||||
|
||||
F->state++; /* FALL THROUGH */
|
||||
case DNS_R_ITERATE:
|
||||
dns_rr_i_init(&F->hints_i, F->hints);
|
||||
dns_rr_i_init(&F->hints_i);
|
||||
|
||||
F->hints_i.section = DNS_S_AUTHORITY;
|
||||
F->hints_i.type = DNS_T_NS;
|
||||
@ -8746,7 +8771,7 @@ exec:
|
||||
dgoto(R->sp, DNS_R_SWITCH);
|
||||
}
|
||||
|
||||
dns_rr_i_init(&F->hints_j, F->hints);
|
||||
dns_rr_i_init(&F->hints_j);
|
||||
|
||||
/* Assume there are glue records */
|
||||
dgoto(R->sp, DNS_R_FOREACH_A);
|
||||
@ -8799,14 +8824,14 @@ exec:
|
||||
if (!dns_rr_i_count(&F->hints_j)) {
|
||||
/* Check if we have in fact servers
|
||||
with an IPv6 address. */
|
||||
dns_rr_i_init(&F->hints_j, F->hints);
|
||||
dns_rr_i_init(&F->hints_j);
|
||||
F->hints_j.name = u.ns.host;
|
||||
F->hints_j.type = DNS_T_AAAA;
|
||||
F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
|
||||
if (dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
|
||||
/* We do. Reinitialize
|
||||
iterator and handle it. */
|
||||
dns_rr_i_init(&F->hints_j, F->hints);
|
||||
dns_rr_i_init(&F->hints_j);
|
||||
dgoto(R->sp, DNS_R_FOREACH_AAAA);
|
||||
}
|
||||
|
||||
@ -8935,14 +8960,14 @@ exec:
|
||||
if (!dns_rr_i_count(&F->hints_j)) {
|
||||
/* Check if we have in fact servers
|
||||
with an IPv4 address. */
|
||||
dns_rr_i_init(&F->hints_j, F->hints);
|
||||
dns_rr_i_init(&F->hints_j);
|
||||
F->hints_j.name = u.ns.host;
|
||||
F->hints_j.type = DNS_T_A;
|
||||
F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
|
||||
if (dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
|
||||
/* We do. Reinitialize
|
||||
iterator and handle it. */
|
||||
dns_rr_i_init(&F->hints_j, F->hints);
|
||||
dns_rr_i_init(&F->hints_j);
|
||||
dgoto(R->sp, DNS_R_FOREACH_A);
|
||||
}
|
||||
|
||||
@ -9080,7 +9105,7 @@ exec:
|
||||
R->smart.section = DNS_S_AN;
|
||||
R->smart.type = R->qtype;
|
||||
|
||||
dns_rr_i_init(&R->smart, F->answer);
|
||||
dns_rr_i_init(&R->smart);
|
||||
|
||||
F->state++; /* FALL THROUGH */
|
||||
case DNS_R_SMART0_A:
|
||||
@ -9824,7 +9849,7 @@ exec:
|
||||
return error;
|
||||
|
||||
dns_strlcpy(ai->i_cname, ai->cname, sizeof ai->i_cname);
|
||||
dns_rr_i_init(&ai->i, ai->answer);
|
||||
dns_rr_i_init(&ai->i);
|
||||
ai->i.section = DNS_S_AN;
|
||||
ai->i.name = ai->i_cname;
|
||||
ai->i.type = dns_ai_qtype(ai);
|
||||
@ -9871,7 +9896,7 @@ exec:
|
||||
ai->state++; /* FALL THROUGH */
|
||||
case DNS_AI_S_ITERATE_G:
|
||||
dns_strlcpy(ai->g_cname, ai->cname, sizeof ai->g_cname);
|
||||
dns_rr_i_init(&ai->g, ai->glue);
|
||||
dns_rr_i_init(&ai->g);
|
||||
ai->g.section = DNS_S_ALL & ~DNS_S_QD;
|
||||
ai->g.name = ai->g_cname;
|
||||
ai->g.type = ai->af.qtype;
|
||||
@ -9890,8 +9915,14 @@ exec:
|
||||
|
||||
return dns_ai_setent(ent, &any, rr.type, ai);
|
||||
case DNS_AI_S_SUBMIT_G:
|
||||
{
|
||||
struct dns_rr_i _I = { 0 };
|
||||
|
||||
_I.section = DNS_S_QD;
|
||||
_I.name = ai->g.name;
|
||||
_I.type = ai->g.type;
|
||||
/* skip if already queried */
|
||||
if (dns_rr_grep(&rr, 1, dns_rr_i_new(ai->glue, .section = DNS_S_QD, .name = ai->g.name, .type = ai->g.type), ai->glue, &error))
|
||||
if (dns_rr_grep(&rr, 1, &_I, ai->glue, &error))
|
||||
dns_ai_goto(DNS_AI_S_FOREACH_I);
|
||||
/* skip if we recursed (CNAME chains should have been handled in the resolver) */
|
||||
if (++ai->g_depth > 1)
|
||||
@ -9900,7 +9931,8 @@ exec:
|
||||
if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
|
||||
return error;
|
||||
|
||||
ai->state++; /* FALL THROUGH */
|
||||
ai->state++;
|
||||
} /* FALL THROUGH */
|
||||
case DNS_AI_S_CHECK_G:
|
||||
if ((error = dns_res_check(ai->res)))
|
||||
return error;
|
||||
@ -10074,8 +10106,9 @@ static const struct {
|
||||
{ "AR", DNS_S_ADDITIONAL },
|
||||
};
|
||||
|
||||
const char *(dns_strsection)(enum dns_section section, void *_dst, size_t lim) {
|
||||
struct dns_buf dst = DNS_B_INTO(_dst, lim);
|
||||
const char *(dns_strsection)(enum dns_section section) {
|
||||
char _dst[DNS_STRMAXLEN + 1] = { 0 };
|
||||
struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst);
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < lengthof(dns_sections); i++) {
|
||||
@ -10123,8 +10156,9 @@ static const struct {
|
||||
{ "IN", DNS_C_IN },
|
||||
};
|
||||
|
||||
const char *(dns_strclass)(enum dns_class type, void *_dst, size_t lim) {
|
||||
struct dns_buf dst = DNS_B_INTO(_dst, lim);
|
||||
const char *(dns_strclass)(enum dns_class type) {
|
||||
char _dst[DNS_STRMAXLEN + 1] = { 0 };
|
||||
struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst);
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < lengthof(dns_classes); i++) {
|
||||
@ -10159,8 +10193,9 @@ enum dns_class dns_iclass(const char *name) {
|
||||
} /* dns_iclass() */
|
||||
|
||||
|
||||
const char *(dns_strtype)(enum dns_type type, void *_dst, size_t lim) {
|
||||
struct dns_buf dst = DNS_B_INTO(_dst, lim);
|
||||
const char *(dns_strtype)(enum dns_type type) {
|
||||
char _dst[DNS_STRMAXLEN + 1] = { 0 };
|
||||
struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst);
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < lengthof(dns_rrtypes); i++) {
|
||||
@ -10563,7 +10598,9 @@ static struct dns_trace *trace(const char *mode) {
|
||||
|
||||
|
||||
static void print_packet(struct dns_packet *P, FILE *fp) {
|
||||
dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
|
||||
struct dns_rr_i _I = { 0 };
|
||||
I.sort = MAIN.sort;
|
||||
dns_p_dump3(P, &I, fp);
|
||||
|
||||
if (MAIN.verbose > 2)
|
||||
hexdump(P->data, P->end, fp);
|
||||
@ -10571,8 +10608,10 @@ static void print_packet(struct dns_packet *P, FILE *fp) {
|
||||
|
||||
|
||||
static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
|
||||
struct dns_packet *P = dns_p_new(512);
|
||||
struct dns_packet *Q = dns_p_new(512);
|
||||
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
|
||||
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
|
||||
struct dns_packet *P = dns_p_init(&_P.p, 512);
|
||||
struct dns_packet *Q = dns_p_init(&_Q.p, 512);
|
||||
enum dns_section section;
|
||||
struct dns_rr rr;
|
||||
int error;
|
||||
@ -10612,10 +10651,16 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
|
||||
#if 0
|
||||
dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
|
||||
#else
|
||||
char _p[DNS_D_MAXNAME + 1] = { 0 };
|
||||
const char *dn = "ns8.yahoo.com";
|
||||
char *_name = dns_d_init(_p, sizeof _p, dn, strlen (dn), DNS_D_ANCHOR);
|
||||
struct dns_rr rrset[32];
|
||||
struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
|
||||
struct dns_rr_i _I = { 0 };
|
||||
struct dns_rr_i *rri = &I;
|
||||
unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
|
||||
|
||||
I.name = _name;
|
||||
I.sort = MAIN.sort;
|
||||
for (unsigned i = 0; i < rrcount; i++) {
|
||||
rr = rrset[i];
|
||||
#endif
|
||||
@ -10641,13 +10686,14 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
|
||||
|
||||
|
||||
static int parse_domain(int argc, char *argv[]) {
|
||||
char _p[DNS_D_MAXNAME + 1] = { 0 };
|
||||
char *dn;
|
||||
|
||||
dn = (argc > 1)? argv[1] : "f.l.google.com";
|
||||
|
||||
printf("[%s]\n", dn);
|
||||
|
||||
dn = dns_d_new(dn);
|
||||
dn = dns_d_init(_p, sizeof _p, dn, strlen (dn), DNS_D_ANCHOR);
|
||||
|
||||
do {
|
||||
puts(dn);
|
||||
@ -10772,7 +10818,8 @@ static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
|
||||
|
||||
|
||||
static int query_hosts(int argc, char *argv[]) {
|
||||
struct dns_packet *Q = dns_p_new(512);
|
||||
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
|
||||
struct dns_packet *Q = dns_p_init(&_Q.p, 512);
|
||||
struct dns_packet *A;
|
||||
char qname[DNS_D_MAXNAME + 1];
|
||||
size_t qlen;
|
||||
@ -10890,11 +10937,13 @@ static int dump_random(int argc, char *argv[]) {
|
||||
|
||||
|
||||
static int send_query(int argc, char *argv[]) {
|
||||
struct dns_packet *A, *Q = dns_p_new(512);
|
||||
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
|
||||
struct dns_packet *A, *Q = dns_p_init(&_Q.p, 512);
|
||||
char host[INET6_ADDRSTRLEN + 1];
|
||||
struct sockaddr_storage ss;
|
||||
struct dns_socket *so;
|
||||
int error, type;
|
||||
struct dns_options opts = { 0 };
|
||||
|
||||
memset(&ss, 0, sizeof ss);
|
||||
if (argc > 1) {
|
||||
@ -10929,7 +10978,7 @@ static int send_query(int argc, char *argv[]) {
|
||||
|
||||
fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
|
||||
|
||||
if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
|
||||
if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, &opts, &error)))
|
||||
panic("dns_so_open: %s", dns_strerror(error));
|
||||
|
||||
while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
|
||||
@ -10984,9 +11033,10 @@ static int show_hints(int argc, char *argv[]) {
|
||||
if (0 == strcmp(how, "plain")) {
|
||||
dns_hints_dump(hints, stdout);
|
||||
} else {
|
||||
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
|
||||
struct dns_packet *query, *answer;
|
||||
|
||||
query = dns_p_new(512);
|
||||
query = dns_p_init(&_P.p, 512);
|
||||
|
||||
if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
|
||||
panic("%s: %s", who, dns_strerror(error));
|
||||
@ -11012,6 +11062,11 @@ static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
|
||||
struct dns_packet *ans;
|
||||
const struct dns_stat *st;
|
||||
int error;
|
||||
struct dns_options opts = { 0 };
|
||||
|
||||
opts.socks_host = &MAIN.socks_host;
|
||||
opts.socks_user = MAIN.socks_user;
|
||||
opts.socks_password = MAIN.socks_password;
|
||||
|
||||
if (!MAIN.qname)
|
||||
MAIN.qname = "www.google.com";
|
||||
@ -11021,9 +11076,7 @@ static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
|
||||
resconf()->options.recurse = recurse;
|
||||
|
||||
if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(),
|
||||
dns_opts(.socks_host=&MAIN.socks_host,
|
||||
.socks_user=MAIN.socks_user,
|
||||
.socks_password=MAIN.socks_password), &error)))
|
||||
&opts, &error)))
|
||||
panic("%s: %s", MAIN.qname, dns_strerror(error));
|
||||
|
||||
dns_res_settrace(R, trace("w+b"));
|
||||
@ -11067,6 +11120,7 @@ static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
|
||||
struct addrinfo *ent;
|
||||
char pretty[512];
|
||||
int error;
|
||||
struct dns_options opts = { 0 };
|
||||
|
||||
if (!MAIN.qname)
|
||||
MAIN.qname = "www.google.com";
|
||||
@ -11074,7 +11128,7 @@ static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
|
||||
|
||||
resconf()->options.recurse = recurse;
|
||||
|
||||
if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
|
||||
if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), &opts, &error)))
|
||||
panic("%s: %s", MAIN.qname, dns_strerror(error));
|
||||
|
||||
if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
|
||||
@ -11145,7 +11199,8 @@ static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
|
||||
panic("127.0.0.1:5353: %s", dns_strerror(errno));
|
||||
|
||||
for (;;) {
|
||||
struct dns_packet *pkt = dns_p_new(512);
|
||||
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
|
||||
struct dns_packet *pkt = dns_p_init(&_P.p, 512);
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t slen = sizeof ss;
|
||||
ssize_t count;
|
||||
|
@ -132,19 +132,6 @@ DNS_PUBLIC int *dns_debug_p(void);
|
||||
/*
|
||||
* C O M P I L E R A N N O T A T I O N S
|
||||
*
|
||||
* GCC with -Wextra, and clang by default, complain about overrides in
|
||||
* initializer lists. Overriding previous member initializers is well
|
||||
* defined behavior in C. dns.c relies on this behavior to define default,
|
||||
* overrideable member values when instantiating configuration objects.
|
||||
*
|
||||
* dns_quietinit() guards a compound literal expression with pragmas to
|
||||
* silence these shrill warnings. This alleviates the burden of requiring
|
||||
* third-party projects to adjust their compiler flags.
|
||||
*
|
||||
* NOTE: If you take the address of the compound literal, take the address
|
||||
* of the transformed expression, otherwise the compound literal lifetime is
|
||||
* tied to the scope of the GCC statement expression.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#if defined __clang__
|
||||
@ -152,21 +139,15 @@ DNS_PUBLIC int *dns_debug_p(void);
|
||||
#define DNS_PRAGMA_QUIET _Pragma("clang diagnostic ignored \"-Winitializer-overrides\"")
|
||||
#define DNS_PRAGMA_POP _Pragma("clang diagnostic pop")
|
||||
|
||||
#define dns_quietinit(...) \
|
||||
DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__ DNS_PRAGMA_POP
|
||||
#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
|
||||
#define DNS_PRAGMA_PUSH _Pragma("GCC diagnostic push")
|
||||
#define DNS_PRAGMA_QUIET _Pragma("GCC diagnostic ignored \"-Woverride-init\"")
|
||||
#define DNS_PRAGMA_POP _Pragma("GCC diagnostic pop")
|
||||
|
||||
/* GCC parses the _Pragma operator less elegantly than clang. */
|
||||
#define dns_quietinit(...) \
|
||||
__extension__ ({ DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__; DNS_PRAGMA_POP })
|
||||
#else
|
||||
#define DNS_PRAGMA_PUSH
|
||||
#define DNS_PRAGMA_QUIET
|
||||
#define DNS_PRAGMA_POP
|
||||
#define dns_quietinit(...) __VA_ARGS__
|
||||
#endif
|
||||
|
||||
#if defined __GNUC__
|
||||
@ -291,25 +272,15 @@ enum dns_rcode {
|
||||
*/
|
||||
#define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */
|
||||
|
||||
DNS_PUBLIC const char *dns_strsection(enum dns_section, void *, size_t);
|
||||
#define dns_strsection3(a, b, c) \
|
||||
dns_strsection((a), (b), (c))
|
||||
#define dns_strsection1(a) dns_strsection((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
|
||||
#define dns_strsection(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strsection, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
|
||||
DNS_PUBLIC const char *dns_strsection(enum dns_section);
|
||||
|
||||
DNS_PUBLIC enum dns_section dns_isection(const char *);
|
||||
|
||||
DNS_PUBLIC const char *dns_strclass(enum dns_class, void *, size_t);
|
||||
#define dns_strclass3(a, b, c) dns_strclass((a), (b), (c))
|
||||
#define dns_strclass1(a) dns_strclass((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
|
||||
#define dns_strclass(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strclass, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
|
||||
DNS_PUBLIC const char *dns_strclass(enum dns_class);
|
||||
|
||||
DNS_PUBLIC enum dns_class dns_iclass(const char *);
|
||||
|
||||
DNS_PUBLIC const char *dns_strtype(enum dns_type, void *, size_t);
|
||||
#define dns_strtype3(a, b, c) dns_strtype((a), (b), (c))
|
||||
#define dns_strtype1(a) dns_strtype((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
|
||||
#define dns_strtype(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strtype, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
|
||||
DNS_PUBLIC const char *dns_strtype(enum dns_type);
|
||||
|
||||
DNS_PUBLIC enum dns_type dns_itype(const char *);
|
||||
|
||||
@ -422,9 +393,6 @@ struct dns_packet {
|
||||
|
||||
#define dns_p_sizeof(P) dns_p_calcsize((P)->end)
|
||||
|
||||
/** takes size of maximum desired payload */
|
||||
#define dns_p_new(n) (dns_p_init((struct dns_packet *)&(union { unsigned char b[dns_p_calcsize((n))]; struct dns_packet p; }){ { 0 } }, dns_p_calcsize((n))))
|
||||
|
||||
/** takes size of entire packet structure as allocated */
|
||||
DNS_PUBLIC struct dns_packet *dns_p_init(struct dns_packet *, size_t);
|
||||
|
||||
@ -464,11 +432,6 @@ DNS_PUBLIC int dns_p_study(struct dns_packet *);
|
||||
#define DNS_D_CLEAVE 2 /* cleave sub-domain */
|
||||
#define DNS_D_TRIM 4 /* remove superfluous dots */
|
||||
|
||||
#define dns_d_new3(a, b, f) dns_d_init(&(char[DNS_D_MAXNAME + 1]){ 0 }, DNS_D_MAXNAME + 1, (a), (b), (f))
|
||||
#define dns_d_new2(a, f) dns_d_new3((a), strlen((a)), (f))
|
||||
#define dns_d_new1(a) dns_d_new3((a), strlen((a)), DNS_D_ANCHOR)
|
||||
#define dns_d_new(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_d_new, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
|
||||
|
||||
DNS_PUBLIC char *dns_d_init(void *, size_t, const void *, size_t, int);
|
||||
|
||||
DNS_PUBLIC size_t dns_d_anchor(void *, size_t, const void *, size_t);
|
||||
@ -521,9 +484,6 @@ DNS_PUBLIC int dns_rr_cmp(struct dns_rr *, struct dns_packet *, struct dns_rr *,
|
||||
DNS_PUBLIC size_t dns_rr_print(void *, size_t, struct dns_rr *, struct dns_packet *, int *);
|
||||
|
||||
|
||||
#define dns_rr_i_new(P, ...) \
|
||||
dns_rr_i_init(&dns_quietinit((struct dns_rr_i){ 0, __VA_ARGS__ }), (P))
|
||||
|
||||
struct dns_rr_i {
|
||||
enum dns_section section;
|
||||
const void *name;
|
||||
@ -551,7 +511,7 @@ DNS_PUBLIC int dns_rr_i_order(struct dns_rr *, struct dns_rr *, struct dns_rr_i
|
||||
|
||||
DNS_PUBLIC int dns_rr_i_shuffle(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
|
||||
|
||||
DNS_PUBLIC struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *);
|
||||
DNS_PUBLIC void dns_rr_i_init(struct dns_rr_i *);
|
||||
|
||||
#define dns_rr_i_save(i) ((i)->saved = (i)->state)
|
||||
#define dns_rr_i_rewind(i) ((i)->state = (i)->saved)
|
||||
@ -560,7 +520,7 @@ DNS_PUBLIC struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *
|
||||
DNS_PUBLIC unsigned dns_rr_grep(struct dns_rr *, unsigned, struct dns_rr_i *, struct dns_packet *, int *);
|
||||
|
||||
#define dns_rr_foreach_(rr, P, ...) \
|
||||
for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = *dns_rr_i_new((P), __VA_ARGS__); dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), &(int){ 0 }); )
|
||||
for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = { __VA_ARGS__ }; dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), NULL); )
|
||||
|
||||
#define dns_rr_foreach(...) dns_rr_foreach_(__VA_ARGS__)
|
||||
|
||||
@ -1001,7 +961,6 @@ struct dns_hints_i {
|
||||
} state;
|
||||
}; /* struct dns_hints_i */
|
||||
|
||||
#define dns_hints_i_new(...) (&(struct dns_hints_i){ __VA_ARGS__ })
|
||||
|
||||
DNS_PUBLIC unsigned dns_hints_grep(struct sockaddr **, socklen_t *, unsigned, struct dns_hints_i *, struct dns_hints *);
|
||||
|
||||
@ -1053,9 +1012,6 @@ DNS_PUBLIC void dns_cache_close(struct dns_cache *);
|
||||
|
||||
#define DNS_OPTS_INITIALIZER_ { 0, 0 }, 0, 0
|
||||
#define DNS_OPTS_INITIALIZER { DNS_OPTS_INITIALIZER_ }
|
||||
#define DNS_OPTS_INIT(...) { DNS_OPTS_INITIALIZER_, __VA_ARGS__ }
|
||||
|
||||
#define dns_opts(...) (&dns_quietinit((struct dns_options)DNS_OPTS_INIT(__VA_ARGS__)))
|
||||
|
||||
struct dns_options {
|
||||
/*
|
||||
|
@ -119,7 +119,7 @@ domaininfo_print_stats (void)
|
||||
}
|
||||
|
||||
|
||||
/* Return true if DOMAIN definitely does not support WKD. Noet that
|
||||
/* Return true if DOMAIN definitely does not support WKD. Note that
|
||||
* DOMAIN is expected to be lowercase. */
|
||||
int
|
||||
domaininfo_is_wkd_not_supported (const char *domain)
|
||||
|
@ -55,7 +55,7 @@ gnupg_http_tls_verify_cb (void *opaque,
|
||||
log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC);
|
||||
log_assert (!ntbtls_check_context (tls));
|
||||
|
||||
/* Get the peer's certs fron ntbtls. */
|
||||
/* Get the peer's certs from ntbtls. */
|
||||
for (idx = 0;
|
||||
(cert = ntbtls_x509_get_peer_cert (tls, idx)); idx++)
|
||||
{
|
||||
|
226
dirmngr/http.c
226
dirmngr/http.c
@ -1350,6 +1350,8 @@ do_parse_uri (parsed_uri_t uri, int only_local_part,
|
||||
uri->v6lit = 0;
|
||||
uri->onion = 0;
|
||||
uri->explicit_port = 0;
|
||||
uri->off_host = 0;
|
||||
uri->off_path = 0;
|
||||
|
||||
/* A quick validity check. */
|
||||
if (strspn (p, VALID_URI_CHARS) != n)
|
||||
@ -1393,7 +1395,19 @@ do_parse_uri (parsed_uri_t uri, int only_local_part,
|
||||
{
|
||||
p += 2;
|
||||
if ((p2 = strchr (p, '/')))
|
||||
{
|
||||
if (p2 - uri->buffer > 10000)
|
||||
return GPG_ERR_BAD_URI;
|
||||
uri->off_path = p2 - uri->buffer;
|
||||
*p2++ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = (p - uri->buffer) + strlen (p);
|
||||
if (n > 10000)
|
||||
return GPG_ERR_BAD_URI;
|
||||
uri->off_path = n;
|
||||
}
|
||||
|
||||
/* Check for username/password encoding */
|
||||
if ((p3 = strchr (p, '@')))
|
||||
@ -1412,11 +1426,19 @@ do_parse_uri (parsed_uri_t uri, int only_local_part,
|
||||
*p3++ = '\0';
|
||||
/* worst case, uri->host should have length 0, points to \0 */
|
||||
uri->host = p + 1;
|
||||
if (p - uri->buffer > 10000)
|
||||
return GPG_ERR_BAD_URI;
|
||||
uri->off_host = (p + 1) - uri->buffer;
|
||||
uri->v6lit = 1;
|
||||
p = p3;
|
||||
}
|
||||
else
|
||||
{
|
||||
uri->host = p;
|
||||
if (p - uri->buffer > 10000)
|
||||
return GPG_ERR_BAD_URI;
|
||||
uri->off_host = p - uri->buffer;
|
||||
}
|
||||
|
||||
if ((p3 = strchr (p, ':')))
|
||||
{
|
||||
@ -3496,3 +3518,207 @@ uri_query_lookup (parsed_uri_t uri, const char *key)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if both URI point to the same host for the purpose of
|
||||
* redirection check. A is the original host and B the host given in
|
||||
* the Location header. As a temporary workaround a fixed list of
|
||||
* exceptions is also consulted. */
|
||||
static int
|
||||
same_host_p (parsed_uri_t a, parsed_uri_t b)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const char *from; /* NULL uses the last entry from the table. */
|
||||
const char *to;
|
||||
} allow[] =
|
||||
{
|
||||
{ "protonmail.com", "api.protonmail.com" },
|
||||
{ NULL, "api.protonmail.ch" },
|
||||
{ "protonmail.ch", "api.protonmail.com" },
|
||||
{ NULL, "api.protonmail.ch" }
|
||||
};
|
||||
int i;
|
||||
const char *from;
|
||||
|
||||
if (!a->host || !b->host)
|
||||
return 0;
|
||||
|
||||
if (!ascii_strcasecmp (a->host, b->host))
|
||||
return 1;
|
||||
|
||||
from = NULL;
|
||||
for (i=0; i < DIM (allow); i++)
|
||||
{
|
||||
if (allow[i].from)
|
||||
from = allow[i].from;
|
||||
if (!from)
|
||||
continue;
|
||||
if (!ascii_strcasecmp (from, a->host)
|
||||
&& !ascii_strcasecmp (allow[i].to, b->host))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Prepare a new URL for a HTTP redirect. INFO has flags controlling
|
||||
* the operation, STATUS_CODE is used for diagnostics, LOCATION is the
|
||||
* value of the "Location" header, and R_URL reveives the new URL on
|
||||
* success or NULL or error. Note that INFO->ORIG_URL is
|
||||
* required. */
|
||||
gpg_error_t
|
||||
http_prepare_redirect (http_redir_info_t *info, unsigned int status_code,
|
||||
const char *location, char **r_url)
|
||||
{
|
||||
gpg_error_t err;
|
||||
parsed_uri_t locuri;
|
||||
parsed_uri_t origuri;
|
||||
char *newurl;
|
||||
char *p;
|
||||
|
||||
*r_url = NULL;
|
||||
|
||||
if (!info || !info->orig_url)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
|
||||
if (!info->silent)
|
||||
log_info (_("URL '%s' redirected to '%s' (%u)\n"),
|
||||
info->orig_url, location? location:"[none]", status_code);
|
||||
|
||||
if (!info->redirects_left)
|
||||
{
|
||||
if (!info->silent)
|
||||
log_error (_("too many redirections\n"));
|
||||
return gpg_error (GPG_ERR_NO_DATA);
|
||||
}
|
||||
info->redirects_left--;
|
||||
|
||||
if (!location || !*location)
|
||||
return gpg_error (GPG_ERR_NO_DATA);
|
||||
|
||||
err = http_parse_uri (&locuri, location, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Make sure that an onion address only redirects to another
|
||||
* onion address, or that a https address only redirects to a
|
||||
* https address. */
|
||||
if (info->orig_onion && !locuri->onion)
|
||||
{
|
||||
http_release_parsed_uri (locuri);
|
||||
return gpg_error (GPG_ERR_FORBIDDEN);
|
||||
}
|
||||
if (!info->allow_downgrade && info->orig_https && !locuri->use_tls)
|
||||
{
|
||||
http_release_parsed_uri (locuri);
|
||||
return gpg_error (GPG_ERR_FORBIDDEN);
|
||||
}
|
||||
|
||||
if (info->trust_location)
|
||||
{
|
||||
/* We trust the Location - return it verbatim. */
|
||||
http_release_parsed_uri (locuri);
|
||||
newurl = xtrystrdup (location);
|
||||
if (!newurl)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
http_release_parsed_uri (locuri);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else if ((err = http_parse_uri (&origuri, info->orig_url, 0)))
|
||||
{
|
||||
http_release_parsed_uri (locuri);
|
||||
return err;
|
||||
}
|
||||
else if (same_host_p (origuri, locuri))
|
||||
{
|
||||
/* The host is the same or on an exception list and thus we can
|
||||
* take the location verbatim. */
|
||||
http_release_parsed_uri (origuri);
|
||||
http_release_parsed_uri (locuri);
|
||||
newurl = xtrystrdup (location);
|
||||
if (!newurl)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
http_release_parsed_uri (locuri);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We take only the host and port from the URL given in the
|
||||
* Location. This limits the effects of redirection attacks by
|
||||
* rogue hosts returning an URL to servers in the client's own
|
||||
* network. We don't even include the userinfo because they
|
||||
* should be considered similar to the path and query parts.
|
||||
*/
|
||||
if (!(locuri->off_path - locuri->off_host))
|
||||
{
|
||||
http_release_parsed_uri (origuri);
|
||||
http_release_parsed_uri (locuri);
|
||||
return gpg_error (GPG_ERR_BAD_URI);
|
||||
}
|
||||
if (!(origuri->off_path - origuri->off_host))
|
||||
{
|
||||
http_release_parsed_uri (origuri);
|
||||
http_release_parsed_uri (locuri);
|
||||
return gpg_error (GPG_ERR_BAD_URI);
|
||||
}
|
||||
|
||||
newurl = xtrymalloc (strlen (origuri->original)
|
||||
+ (locuri->off_path - locuri->off_host) + 1);
|
||||
if (!newurl)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
http_release_parsed_uri (origuri);
|
||||
http_release_parsed_uri (locuri);
|
||||
return err;
|
||||
}
|
||||
/* Build new URL from
|
||||
* uriguri: scheme userinfo ---- ---- path rest
|
||||
* locuri: ------ -------- host port ---- ----
|
||||
*/
|
||||
p = newurl;
|
||||
memcpy (p, origuri->original, origuri->off_host);
|
||||
p += origuri->off_host;
|
||||
memcpy (p, locuri->original + locuri->off_host,
|
||||
(locuri->off_path - locuri->off_host));
|
||||
p += locuri->off_path - locuri->off_host;
|
||||
strcpy (p, origuri->original + origuri->off_path);
|
||||
|
||||
http_release_parsed_uri (origuri);
|
||||
http_release_parsed_uri (locuri);
|
||||
if (!info->silent)
|
||||
log_info (_("redirection changed to '%s'\n"), newurl);
|
||||
}
|
||||
|
||||
*r_url = newurl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return string describing the http STATUS. Returns an empty string
|
||||
* for an unknown status. */
|
||||
const char *
|
||||
http_status2string (unsigned int status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case 500: return "Internal Server Error";
|
||||
case 501: return "Not Implemented";
|
||||
case 502: return "Bad Gateway";
|
||||
case 503: return "Service Unavailable";
|
||||
case 504: return "Gateway Timeout";
|
||||
case 505: return "HTTP version Not Supported";
|
||||
case 506: return "Variant Also Negation";
|
||||
case 507: return "Insufficient Storage";
|
||||
case 508: return "Loop Detected";
|
||||
case 510: return "Not Extended";
|
||||
case 511: return "Network Authentication Required";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
@ -58,6 +58,8 @@ struct parsed_uri_s
|
||||
char *auth; /* username/password for basic auth. */
|
||||
char *host; /* Host (converted to lowercase). */
|
||||
unsigned short port; /* Port (always set if the host is set). */
|
||||
unsigned short off_host; /* Offset to the HOST respective PATH parts */
|
||||
unsigned short off_path; /* in the original URI buffer. */
|
||||
char *path; /* Path. */
|
||||
uri_tuple_t params; /* ";xxxxx" */
|
||||
uri_tuple_t query; /* "?xxx=yyy" */
|
||||
@ -100,6 +102,21 @@ typedef struct http_session_s *http_session_t;
|
||||
struct http_context_s;
|
||||
typedef struct http_context_s *http_t;
|
||||
|
||||
/* An object used to track redirection infos. */
|
||||
struct http_redir_info_s
|
||||
{
|
||||
unsigned int redirects_left; /* Number of still possible redirects. */
|
||||
const char *orig_url; /* The original requested URL. */
|
||||
unsigned int orig_onion:1; /* Original request was an onion address. */
|
||||
unsigned int orig_https:1; /* Original request was a http address. */
|
||||
unsigned int silent:1; /* No diagnostics. */
|
||||
unsigned int allow_downgrade:1;/* Allow a downgrade from https to http. */
|
||||
unsigned int trust_location:1; /* Trust the received Location header. */
|
||||
};
|
||||
typedef struct http_redir_info_s http_redir_info_t;
|
||||
|
||||
|
||||
|
||||
/* A TLS verify callback function. */
|
||||
typedef gpg_error_t (*http_verify_cb_t) (void *opaque,
|
||||
http_t http,
|
||||
@ -176,5 +193,11 @@ gpg_error_t http_verify_server_credentials (http_session_t sess);
|
||||
char *http_escape_string (const char *string, const char *specials);
|
||||
char *http_escape_data (const void *data, size_t datalen, const char *specials);
|
||||
|
||||
gpg_error_t http_prepare_redirect (http_redir_info_t *info,
|
||||
unsigned int status_code,
|
||||
const char *location, char **r_url);
|
||||
|
||||
const char *http_status2string (unsigned int status);
|
||||
|
||||
|
||||
#endif /*GNUPG_COMMON_HTTP_H*/
|
||||
|
@ -88,7 +88,7 @@ ks_action_help (ctrl_t ctrl, const char *url)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Call all engines to give them a chance to print a help sting. */
|
||||
/* Call all engines to give them a chance to print a help string. */
|
||||
err = ks_hkp_help (ctrl, parsed_uri);
|
||||
if (!err)
|
||||
err = ks_http_help (ctrl, parsed_uri);
|
||||
|
@ -35,6 +35,7 @@
|
||||
# include <netdb.h>
|
||||
#endif /*!HAVE_W32_SYSTEM*/
|
||||
|
||||
#include <npth.h>
|
||||
#include "dirmngr.h"
|
||||
#include "misc.h"
|
||||
#include "../common/userids.h"
|
||||
@ -108,6 +109,8 @@ struct hostinfo_s
|
||||
resolved from a pool name and its allocated size.*/
|
||||
static hostinfo_t *hosttable;
|
||||
static int hosttable_size;
|
||||
/* A mutex used to serialize access to the hosttable. */
|
||||
static npth_mutex_t hosttable_lock;
|
||||
|
||||
/* The number of host slots we initially allocate for HOSTTABLE. */
|
||||
#define INITIAL_HOSTTABLE_SIZE 50
|
||||
@ -756,9 +759,15 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
|
||||
if (!name || !*name || !strcmp (name, "localhost"))
|
||||
return 0;
|
||||
|
||||
if (npth_mutex_lock (&hosttable_lock))
|
||||
log_fatal ("failed to acquire mutex\n");
|
||||
|
||||
idx = find_hostinfo (name);
|
||||
if (idx == -1)
|
||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
hi = hosttable[idx];
|
||||
if (alive && hi->dead)
|
||||
@ -817,6 +826,10 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
if (npth_mutex_unlock (&hosttable_lock))
|
||||
log_fatal ("failed to release mutex\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -837,7 +850,9 @@ ks_hkp_print_hosttable (ctrl_t ctrl)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* FIXME: We need a lock for the hosttable. */
|
||||
if (npth_mutex_lock (&hosttable_lock))
|
||||
log_fatal ("failed to acquire mutex\n");
|
||||
|
||||
curtime = gnupg_get_time ();
|
||||
for (idx=0; idx < hosttable_size; idx++)
|
||||
if ((hi=hosttable[idx]))
|
||||
@ -930,12 +945,12 @@ ks_hkp_print_hosttable (ctrl_t ctrl)
|
||||
diedstr? ")":"" );
|
||||
xfree (died);
|
||||
if (err)
|
||||
return err;
|
||||
goto leave;
|
||||
|
||||
if (hi->cname)
|
||||
err = ks_printf_help (ctrl, " . %s", hi->cname);
|
||||
if (err)
|
||||
return err;
|
||||
goto leave;
|
||||
|
||||
if (hi->pool)
|
||||
{
|
||||
@ -950,14 +965,21 @@ ks_hkp_print_hosttable (ctrl_t ctrl)
|
||||
put_membuf( &mb, "", 1);
|
||||
p = get_membuf (&mb, NULL);
|
||||
if (!p)
|
||||
return gpg_error_from_syserror ();
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
err = ks_print_help (ctrl, p);
|
||||
xfree (p);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
if (npth_mutex_unlock (&hosttable_lock))
|
||||
log_fatal ("failed to release mutex\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1026,9 +1048,16 @@ make_host_part (ctrl_t ctrl,
|
||||
protocol = KS_PROTOCOL_HKP;
|
||||
}
|
||||
|
||||
if (npth_mutex_lock (&hosttable_lock))
|
||||
log_fatal ("failed to acquire mutex\n");
|
||||
|
||||
portstr[0] = 0;
|
||||
err = map_host (ctrl, host, srvtag, force_reselect, protocol,
|
||||
&hostname, portstr, r_httpflags, r_httphost);
|
||||
|
||||
if (npth_mutex_unlock (&hosttable_lock))
|
||||
log_fatal ("failed to release mutex\n");
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -1102,6 +1131,9 @@ ks_hkp_housekeeping (time_t curtime)
|
||||
int idx;
|
||||
hostinfo_t hi;
|
||||
|
||||
if (npth_mutex_lock (&hosttable_lock))
|
||||
log_fatal ("failed to acquire mutex\n");
|
||||
|
||||
for (idx=0; idx < hosttable_size; idx++)
|
||||
{
|
||||
hi = hosttable[idx];
|
||||
@ -1118,6 +1150,9 @@ ks_hkp_housekeeping (time_t curtime)
|
||||
log_info ("resurrected host '%s'", hi->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (npth_mutex_unlock (&hosttable_lock))
|
||||
log_fatal ("failed to release mutex\n");
|
||||
}
|
||||
|
||||
|
||||
@ -1129,6 +1164,9 @@ ks_hkp_reload (void)
|
||||
int idx, count;
|
||||
hostinfo_t hi;
|
||||
|
||||
if (npth_mutex_lock (&hosttable_lock))
|
||||
log_fatal ("failed to acquire mutex\n");
|
||||
|
||||
for (idx=count=0; idx < hosttable_size; idx++)
|
||||
{
|
||||
hi = hosttable[idx];
|
||||
@ -1142,6 +1180,9 @@ ks_hkp_reload (void)
|
||||
}
|
||||
if (count)
|
||||
log_info ("number of resurrected hosts: %d", count);
|
||||
|
||||
if (npth_mutex_unlock (&hosttable_lock))
|
||||
log_fatal ("failed to release mutex\n");
|
||||
}
|
||||
|
||||
|
||||
@ -1160,18 +1201,21 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
|
||||
gpg_error_t err;
|
||||
http_session_t session = NULL;
|
||||
http_t http = NULL;
|
||||
int redirects_left = MAX_REDIRECTS;
|
||||
http_redir_info_t redirinfo = { MAX_REDIRECTS };
|
||||
estream_t fp = NULL;
|
||||
char *request_buffer = NULL;
|
||||
parsed_uri_t uri = NULL;
|
||||
int is_onion;
|
||||
|
||||
*r_fp = NULL;
|
||||
|
||||
err = http_parse_uri (&uri, request, 0);
|
||||
if (err)
|
||||
goto leave;
|
||||
is_onion = uri->onion;
|
||||
redirinfo.orig_url = request;
|
||||
redirinfo.orig_onion = uri->onion;
|
||||
redirinfo.allow_downgrade = 1;
|
||||
/* FIXME: I am not sure whey we allow a downgrade for hkp requests.
|
||||
* Needs at least an explanation here.. */
|
||||
|
||||
err = http_session_new (&session, httphost,
|
||||
((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0)
|
||||
@ -1252,45 +1296,18 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
|
||||
case 302:
|
||||
case 307:
|
||||
{
|
||||
const char *s = http_get_header (http, "Location");
|
||||
|
||||
log_info (_("URL '%s' redirected to '%s' (%u)\n"),
|
||||
request, s?s:"[none]", http_get_status_code (http));
|
||||
if (s && *s && redirects_left-- )
|
||||
{
|
||||
if (is_onion)
|
||||
{
|
||||
/* Make sure that an onion address only redirects to
|
||||
* another onion address. */
|
||||
http_release_parsed_uri (uri);
|
||||
uri = NULL;
|
||||
err = http_parse_uri (&uri, s, 0);
|
||||
xfree (request_buffer);
|
||||
err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
|
||||
http_get_header (http, "Location"),
|
||||
&request_buffer);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if (! uri->onion)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
xfree (request_buffer);
|
||||
request_buffer = xtrystrdup (s);
|
||||
if (request_buffer)
|
||||
{
|
||||
request = request_buffer;
|
||||
http_close (http, 0);
|
||||
http = NULL;
|
||||
}
|
||||
goto once_more;
|
||||
}
|
||||
err = gpg_error_from_syserror ();
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_NO_DATA);
|
||||
log_error (_("too many redirections\n"));
|
||||
}
|
||||
goto leave;
|
||||
|
||||
case 501:
|
||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
@ -1335,12 +1352,12 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
|
||||
down to zero. */
|
||||
static int
|
||||
handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
|
||||
unsigned int *tries_left)
|
||||
unsigned int http_status, unsigned int *tries_left)
|
||||
{
|
||||
int retry = 0;
|
||||
|
||||
/* Fixme: Should we disable all hosts of a protocol family if a
|
||||
* request for an address of that familiy returned ENETDOWN? */
|
||||
* request for an address of that family returned ENETDOWN? */
|
||||
|
||||
switch (gpg_err_code (err))
|
||||
{
|
||||
@ -1378,6 +1395,27 @@ handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
|
||||
}
|
||||
break;
|
||||
|
||||
case GPG_ERR_NO_DATA:
|
||||
{
|
||||
switch (http_status)
|
||||
{
|
||||
case 502: /* Bad Gateway */
|
||||
log_info ("marking host dead due to a %u (%s)\n",
|
||||
http_status, http_status2string (http_status));
|
||||
if (mark_host_dead (request) && *tries_left)
|
||||
retry = 1;
|
||||
break;
|
||||
|
||||
case 503: /* Service Unavailable */
|
||||
case 504: /* Gateway Timeout */
|
||||
log_info ("selecting a different host due to a %u (%s)",
|
||||
http_status, http_status2string (http_status));
|
||||
retry = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1399,13 +1437,14 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
|
||||
{
|
||||
gpg_error_t err;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
char fprbuf[2+40+1];
|
||||
char fprbuf[2+64+1];
|
||||
char *hostport = NULL;
|
||||
char *request = NULL;
|
||||
estream_t fp = NULL;
|
||||
int reselect;
|
||||
unsigned int httpflags;
|
||||
char *httphost = NULL;
|
||||
unsigned int http_status;
|
||||
unsigned int tries = SEND_REQUEST_RETRIES;
|
||||
|
||||
*r_fp = NULL;
|
||||
@ -1417,6 +1456,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
|
||||
err = classify_user_id (pattern, &desc, 1);
|
||||
if (err)
|
||||
return err;
|
||||
log_assert (desc.fprlen <= 64);
|
||||
switch (desc.mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_EXACT:
|
||||
@ -1434,17 +1474,10 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
|
||||
(ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
|
||||
pattern = fprbuf;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR16:
|
||||
fprbuf[0] = '0';
|
||||
fprbuf[1] = 'x';
|
||||
bin2hex (desc.u.fpr, 16, fprbuf+2);
|
||||
pattern = fprbuf;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
fprbuf[0] = '0';
|
||||
fprbuf[1] = 'x';
|
||||
bin2hex (desc.u.fpr, 20, fprbuf+2);
|
||||
bin2hex (desc.u.fpr, desc.fprlen, fprbuf+2);
|
||||
pattern = fprbuf;
|
||||
break;
|
||||
default:
|
||||
@ -1487,14 +1520,20 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
|
||||
|
||||
/* Send the request. */
|
||||
err = send_request (ctrl, request, hostport, httphost, httpflags,
|
||||
NULL, NULL, &fp, r_http_status);
|
||||
if (handle_send_request_error (ctrl, err, request, &tries))
|
||||
NULL, NULL, &fp, &http_status);
|
||||
if (handle_send_request_error (ctrl, err, request, http_status, &tries))
|
||||
{
|
||||
reselect = 1;
|
||||
goto again;
|
||||
}
|
||||
if (r_http_status)
|
||||
*r_http_status = http_status;
|
||||
if (err)
|
||||
{
|
||||
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
|
||||
dirmngr_status (ctrl, "SOURCE", hostport, NULL);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
|
||||
if (err)
|
||||
@ -1541,7 +1580,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
|
||||
{
|
||||
gpg_error_t err;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
char kidbuf[2+40+1];
|
||||
char kidbuf[2+64+1];
|
||||
const char *exactname = NULL;
|
||||
char *searchkey = NULL;
|
||||
char *hostport = NULL;
|
||||
@ -1550,6 +1589,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
|
||||
int reselect;
|
||||
char *httphost = NULL;
|
||||
unsigned int httpflags;
|
||||
unsigned int http_status;
|
||||
unsigned int tries = SEND_REQUEST_RETRIES;
|
||||
|
||||
*r_fp = NULL;
|
||||
@ -1561,6 +1601,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
|
||||
err = classify_user_id (keyspec, &desc, 1);
|
||||
if (err)
|
||||
return err;
|
||||
log_assert (desc.fprlen <= 64);
|
||||
switch (desc.mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_SHORT_KID:
|
||||
@ -1570,21 +1611,21 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
|
||||
snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
|
||||
(ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
/* This is a v4 fingerprint. */
|
||||
if (desc.fprlen < 20)
|
||||
{
|
||||
log_error ("HKP keyservers do not support v3 fingerprints\n");
|
||||
return gpg_error (GPG_ERR_INV_USER_ID);
|
||||
}
|
||||
kidbuf[0] = '0';
|
||||
kidbuf[1] = 'x';
|
||||
bin2hex (desc.u.fpr, 20, kidbuf+2);
|
||||
bin2hex (desc.u.fpr, desc.fprlen, kidbuf+2);
|
||||
break;
|
||||
|
||||
case KEYDB_SEARCH_MODE_EXACT:
|
||||
exactname = desc.u.name;
|
||||
break;
|
||||
|
||||
case KEYDB_SEARCH_MODE_FPR16:
|
||||
log_error ("HKP keyservers do not support v3 fingerprints\n");
|
||||
/* fall through */
|
||||
default:
|
||||
return gpg_error (GPG_ERR_INV_USER_ID);
|
||||
}
|
||||
@ -1622,14 +1663,18 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
|
||||
|
||||
/* Send the request. */
|
||||
err = send_request (ctrl, request, hostport, httphost, httpflags,
|
||||
NULL, NULL, &fp, NULL);
|
||||
if (handle_send_request_error (ctrl, err, request, &tries))
|
||||
NULL, NULL, &fp, &http_status);
|
||||
if (handle_send_request_error (ctrl, err, request, http_status, &tries))
|
||||
{
|
||||
reselect = 1;
|
||||
goto again;
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
|
||||
dirmngr_status (ctrl, "SOURCE", hostport, NULL);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
|
||||
if (err)
|
||||
@ -1693,6 +1738,7 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
|
||||
int reselect;
|
||||
char *httphost = NULL;
|
||||
unsigned int httpflags;
|
||||
unsigned int http_status;
|
||||
unsigned int tries = SEND_REQUEST_RETRIES;
|
||||
|
||||
parm.datastring = NULL;
|
||||
@ -1731,8 +1777,8 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
|
||||
|
||||
/* Send the request. */
|
||||
err = send_request (ctrl, request, hostport, httphost, 0,
|
||||
put_post_cb, &parm, &fp, NULL);
|
||||
if (handle_send_request_error (ctrl, err, request, &tries))
|
||||
put_post_cb, &parm, &fp, &http_status);
|
||||
if (handle_send_request_error (ctrl, err, request, http_status, &tries))
|
||||
{
|
||||
reselect = 1;
|
||||
goto again;
|
||||
@ -1749,3 +1795,13 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
|
||||
xfree (httphost);
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
ks_hkp_init (void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = npth_mutex_init (&hosttable_lock, NULL);
|
||||
if (err)
|
||||
log_fatal ("error initializing mutex: %s\n", strerror (err));
|
||||
}
|
||||
|
@ -74,17 +74,18 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
|
||||
http_session_t session = NULL;
|
||||
unsigned int session_flags;
|
||||
http_t http = NULL;
|
||||
int redirects_left = MAX_REDIRECTS;
|
||||
http_redir_info_t redirinfo = { MAX_REDIRECTS };
|
||||
estream_t fp = NULL;
|
||||
char *request_buffer = NULL;
|
||||
parsed_uri_t uri = NULL;
|
||||
int is_onion, is_https;
|
||||
|
||||
err = http_parse_uri (&uri, url, 0);
|
||||
if (err)
|
||||
goto leave;
|
||||
is_onion = uri->onion;
|
||||
is_https = uri->use_tls;
|
||||
redirinfo.orig_url = url;
|
||||
redirinfo.orig_onion = uri->onion;
|
||||
redirinfo.orig_https = uri->use_tls;
|
||||
redirinfo.allow_downgrade = !!(flags & KS_HTTP_FETCH_ALLOW_DOWNGRADE);
|
||||
|
||||
/* By default we only use the system provided certificates with this
|
||||
* fetch command. */
|
||||
@ -158,53 +159,20 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
|
||||
case 302:
|
||||
case 307:
|
||||
{
|
||||
const char *s = http_get_header (http, "Location");
|
||||
|
||||
log_info (_("URL '%s' redirected to '%s' (%u)\n"),
|
||||
url, s?s:"[none]", http_get_status_code (http));
|
||||
if (s && *s && redirects_left-- )
|
||||
{
|
||||
if (is_onion || is_https)
|
||||
{
|
||||
/* Make sure that an onion address only redirects to
|
||||
* another onion address, or that a https address
|
||||
* only redirects to a https address. */
|
||||
http_release_parsed_uri (uri);
|
||||
uri = NULL;
|
||||
err = http_parse_uri (&uri, s, 0);
|
||||
xfree (request_buffer);
|
||||
err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
|
||||
http_get_header (http, "Location"),
|
||||
&request_buffer);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if (is_onion && !uri->onion)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||
goto leave;
|
||||
}
|
||||
if (!(flags & KS_HTTP_FETCH_ALLOW_DOWNGRADE)
|
||||
&& is_https && !uri->use_tls)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
xfree (request_buffer);
|
||||
request_buffer = xtrystrdup (s);
|
||||
if (request_buffer)
|
||||
{
|
||||
url = request_buffer;
|
||||
http_close (http, 0);
|
||||
http = NULL;
|
||||
http_session_release (session);
|
||||
session = NULL;
|
||||
}
|
||||
goto once_more;
|
||||
}
|
||||
err = gpg_error_from_syserror ();
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_NO_DATA);
|
||||
log_error (_("too many redirections\n"));
|
||||
}
|
||||
goto leave;
|
||||
|
||||
default:
|
||||
log_error (_("error accessing '%s': http status %u\n"),
|
||||
|
@ -376,8 +376,6 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact)
|
||||
(ulong) desc.u.kid[0], (ulong) desc.u.kid[1]);
|
||||
break;
|
||||
|
||||
case KEYDB_SEARCH_MODE_FPR16:
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
case KEYDB_SEARCH_MODE_ISSUER:
|
||||
case KEYDB_SEARCH_MODE_ISSUER_SN:
|
||||
@ -1694,25 +1692,15 @@ extract_attributes (LDAPMod ***modlist, char *line)
|
||||
|
||||
if (is_pub || is_sub)
|
||||
{
|
||||
char *size = fields[2];
|
||||
int val = atoi (size);
|
||||
size = NULL;
|
||||
|
||||
if (val > 0)
|
||||
{
|
||||
/* We zero pad this on the left to make PGP happy. */
|
||||
char padded[6];
|
||||
int val;
|
||||
|
||||
val = atoi (fields[2]);
|
||||
if (val < 99999 && val > 0)
|
||||
{
|
||||
/* We zero pad this on the left to make PGP happy. */
|
||||
snprintf (padded, sizeof padded, "%05u", val);
|
||||
size = padded;
|
||||
}
|
||||
}
|
||||
|
||||
if (size)
|
||||
{
|
||||
if (is_pub || is_sub)
|
||||
modlist_add (modlist, "pgpKeySize", size);
|
||||
modlist_add (modlist, "pgpKeySize", padded);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1736,11 +1724,8 @@ extract_attributes (LDAPMod ***modlist, char *line)
|
||||
}
|
||||
|
||||
if (algo)
|
||||
{
|
||||
if (is_pub)
|
||||
modlist_add (modlist, "pgpKeyType", algo);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_pub || is_sub || is_sig)
|
||||
{
|
||||
|
@ -388,7 +388,7 @@ parse_one_pattern (const char *pattern)
|
||||
}
|
||||
|
||||
/* Take the string STRING and escape it according to the URL rules.
|
||||
Retun a newly allocated string. */
|
||||
Return a newly allocated string. */
|
||||
static char *
|
||||
escape4url (const char *string)
|
||||
{
|
||||
|
@ -515,7 +515,7 @@ host_and_port_from_url (const char *url, int *port)
|
||||
if ((p = strchr (buf, '/')))
|
||||
*p++ = 0;
|
||||
strlwr (buf);
|
||||
if ((p = strchr (p, ':')))
|
||||
if ((p = strchr (buf, ':')))
|
||||
{
|
||||
*p++ = 0;
|
||||
*port = atoi (p);
|
||||
@ -637,7 +637,7 @@ armor_data (char **r_string, const void *data, size_t datalen)
|
||||
}
|
||||
|
||||
|
||||
/* Copy all data from IN to OUT. OUT may be NULL to use this fucntion
|
||||
/* Copy all data from IN to OUT. OUT may be NULL to use this function
|
||||
* as a dummy reader. */
|
||||
gpg_error_t
|
||||
copy_stream (estream_t in, estream_t out)
|
||||
|
@ -343,7 +343,7 @@ validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert,
|
||||
|
||||
Note, that in theory we could simply ask the client via an
|
||||
inquire to validate a certificate but this might involve
|
||||
calling DirMngr again recursivly - we can't do that as of now
|
||||
calling DirMngr again recursively - we can't do that as of now
|
||||
(neither DirMngr nor gpgsm have the ability for concurrent
|
||||
access to DirMngr. */
|
||||
|
||||
@ -391,7 +391,7 @@ check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
|
||||
}
|
||||
|
||||
|
||||
/* Check the signature of an OCSP repsonse. OCSP is the context,
|
||||
/* Check the signature of an OCSP response. OCSP is the context,
|
||||
S_SIG the signature value and MD the handle of the hash we used for
|
||||
the response. This function automagically finds the correct public
|
||||
key. If SIGNER_FPR_LIST is not NULL, the default OCSP reponder has been
|
||||
@ -653,6 +653,33 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* It is sometimes useful to know the responder ID. */
|
||||
if (opt.verbose)
|
||||
{
|
||||
char *resp_name;
|
||||
ksba_sexp_t resp_keyid;
|
||||
|
||||
err = ksba_ocsp_get_responder_id (ocsp, &resp_name, &resp_keyid);
|
||||
if (err)
|
||||
log_info (_("error getting responder ID: %s\n"), gpg_strerror (err));
|
||||
else
|
||||
{
|
||||
log_info ("responder id: ");
|
||||
if (resp_name)
|
||||
log_printf ("'/%s' ", resp_name);
|
||||
if (resp_keyid)
|
||||
{
|
||||
log_printf ("{");
|
||||
dump_serial (resp_keyid);
|
||||
log_printf ("} ");
|
||||
}
|
||||
log_printf ("\n");
|
||||
}
|
||||
ksba_free (resp_name);
|
||||
ksba_free (resp_keyid);
|
||||
err = 0;
|
||||
}
|
||||
|
||||
/* We got a useful answer, check that the answer has a valid signature. */
|
||||
sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
|
||||
if (!sigval || !*produced_at)
|
||||
@ -761,7 +788,7 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
|
||||
err = gpg_error (GPG_ERR_TIME_CONFLICT);
|
||||
}
|
||||
|
||||
/* Check that we are not beyound NEXT_UPDATE (plus some extra time). */
|
||||
/* Check that we are not beyond NEXT_UPDATE (plus some extra time). */
|
||||
if (*next_update)
|
||||
{
|
||||
gnupg_copy_time (tmp_time, next_update);
|
||||
|
@ -731,7 +731,7 @@ cmd_dns_cert (assuan_context_t ctx, char *line)
|
||||
/* We lowercase ascii characters but the DANE I-D does not allow
|
||||
this. FIXME: Check after the release of the RFC whether to
|
||||
change this. */
|
||||
mbox = mailbox_from_userid (line);
|
||||
mbox = mailbox_from_userid (line, 0);
|
||||
if (!mbox || !(domain = strchr (mbox, '@')))
|
||||
{
|
||||
err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
|
||||
@ -837,8 +837,11 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
|
||||
gpg_error_t err = 0;
|
||||
char *mbox = NULL;
|
||||
char *domainbuf = NULL;
|
||||
char *domain; /* Points to mbox or domainbuf. */
|
||||
char *domain_orig;/* Points to mbox. */
|
||||
char *domain; /* Points to mbox or domainbuf. This is used to
|
||||
* connect to the host. */
|
||||
char *domain_orig;/* Points to mbox. This is the used for the
|
||||
* query; i.e. the domain part of the
|
||||
* addrspec. */
|
||||
char sha1buf[20];
|
||||
char *uri = NULL;
|
||||
char *encodedhash = NULL;
|
||||
@ -847,6 +850,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
|
||||
int is_wkd_query; /* True if this is a real WKD query. */
|
||||
int no_log = 0;
|
||||
char portstr[20] = { 0 };
|
||||
int subdomain_mode = 0;
|
||||
|
||||
opt_submission_addr = has_option (line, "--submission-address");
|
||||
opt_policy_flags = has_option (line, "--policy-flags");
|
||||
@ -855,7 +859,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
|
||||
line = skip_options (line);
|
||||
is_wkd_query = !(opt_policy_flags || opt_submission_addr);
|
||||
|
||||
mbox = mailbox_from_userid (line);
|
||||
mbox = mailbox_from_userid (line, 0);
|
||||
if (!mbox || !(domain = strchr (mbox, '@')))
|
||||
{
|
||||
err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
|
||||
@ -864,7 +868,8 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
|
||||
*domain++ = 0;
|
||||
domain_orig = domain;
|
||||
|
||||
/* First check whether we already know that the domain does not
|
||||
|
||||
/* Let's check whether we already know that the domain does not
|
||||
* support WKD. */
|
||||
if (is_wkd_query)
|
||||
{
|
||||
@ -875,8 +880,41 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for SRV records. */
|
||||
if (1)
|
||||
|
||||
/* First try the new "openpgp" subdomain. We check that the domain
|
||||
* is valid because it is later used as an unescaped filename part
|
||||
* of the URI. */
|
||||
if (is_valid_domain_name (domain_orig))
|
||||
{
|
||||
dns_addrinfo_t aibuf;
|
||||
|
||||
domainbuf = strconcat ( "openpgpkey.", domain_orig, NULL);
|
||||
if (!domainbuf)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* FIXME: We should put a cache into dns-stuff because the same
|
||||
* query (with a different port and socket type, though) will be
|
||||
* done later by http function. */
|
||||
err = resolve_dns_name (ctrl, domainbuf, 0, 0, 0, &aibuf, NULL);
|
||||
if (err)
|
||||
{
|
||||
err = 0;
|
||||
xfree (domainbuf);
|
||||
domainbuf = NULL;
|
||||
}
|
||||
else /* Got a subdomain. */
|
||||
{
|
||||
free_dns_addrinfo (aibuf);
|
||||
subdomain_mode = 1;
|
||||
domain = domainbuf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for SRV records unless we have a subdomain. */
|
||||
if (!subdomain_mode)
|
||||
{
|
||||
struct srventry *srvs;
|
||||
unsigned int srvscount;
|
||||
@ -931,6 +969,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
|
||||
xfree (srvs);
|
||||
}
|
||||
|
||||
/* Prepare the hash of the local part. */
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, mbox, strlen (mbox));
|
||||
encodedhash = zb32_encode (sha1buf, 8*20);
|
||||
if (!encodedhash)
|
||||
@ -944,7 +983,10 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
|
||||
uri = strconcat ("https://",
|
||||
domain,
|
||||
portstr,
|
||||
"/.well-known/openpgpkey/submission-address",
|
||||
"/.well-known/openpgpkey/",
|
||||
subdomain_mode? domain_orig : "",
|
||||
subdomain_mode? "/" : "",
|
||||
"submission-address",
|
||||
NULL);
|
||||
}
|
||||
else if (opt_policy_flags)
|
||||
@ -952,17 +994,31 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
|
||||
uri = strconcat ("https://",
|
||||
domain,
|
||||
portstr,
|
||||
"/.well-known/openpgpkey/policy",
|
||||
"/.well-known/openpgpkey/",
|
||||
subdomain_mode? domain_orig : "",
|
||||
subdomain_mode? "/" : "",
|
||||
"policy",
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *escapedmbox;
|
||||
|
||||
escapedmbox = http_escape_string (mbox, "%;?&=");
|
||||
if (escapedmbox)
|
||||
{
|
||||
uri = strconcat ("https://",
|
||||
domain,
|
||||
portstr,
|
||||
"/.well-known/openpgpkey/hu/",
|
||||
"/.well-known/openpgpkey/",
|
||||
subdomain_mode? domain_orig : "",
|
||||
subdomain_mode? "/" : "",
|
||||
"hu/",
|
||||
encodedhash,
|
||||
"?l=",
|
||||
escapedmbox,
|
||||
NULL);
|
||||
xfree (escapedmbox);
|
||||
no_log = 1;
|
||||
if (uri)
|
||||
{
|
||||
@ -972,6 +1028,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!uri)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
@ -2680,6 +2737,20 @@ cmd_reloaddirmngr (assuan_context_t ctx, char *line)
|
||||
}
|
||||
|
||||
|
||||
static const char hlp_flushcrls[] =
|
||||
"FLUSHCRLS\n"
|
||||
"\n"
|
||||
"Remove all cached CRLs from memory and\n"
|
||||
"the file system.";
|
||||
static gpg_error_t
|
||||
cmd_flushcrls (assuan_context_t ctx, char *line)
|
||||
{
|
||||
(void)line;
|
||||
|
||||
return leave_cmd (ctx, crl_cache_flush () ? GPG_ERR_GENERAL : 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Tell the assuan library about our commands. */
|
||||
static int
|
||||
@ -2710,6 +2781,7 @@ register_commands (assuan_context_t ctx)
|
||||
{ "LOADSWDB", cmd_loadswdb, hlp_loadswdb },
|
||||
{ "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
|
||||
{ "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr },
|
||||
{ "FLUSHCRLS", cmd_flushcrls, hlp_flushcrls },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
int i, j, rc;
|
||||
|
199
dirmngr/t-http-basic.c
Normal file
199
dirmngr/t-http-basic.c
Normal file
@ -0,0 +1,199 @@
|
||||
/* t-http-basic.c - Basic regression tests for http.c
|
||||
* Copyright (C) 2018 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <https://gnu.org/licenses/>.
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../common/util.h"
|
||||
#include "t-support.h"
|
||||
#include "http.h"
|
||||
|
||||
#define PGM "t-http-basic"
|
||||
|
||||
|
||||
static void
|
||||
test_http_prepare_redirect (void)
|
||||
{
|
||||
static struct {
|
||||
const char *url;
|
||||
const char *location;
|
||||
const char *expect_url;
|
||||
gpg_error_t expect_err;
|
||||
} tests[] = {
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
NULL,
|
||||
"",
|
||||
GPG_ERR_NO_DATA
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"",
|
||||
"",
|
||||
GPG_ERR_NO_DATA
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"foo//bla",
|
||||
"",
|
||||
GPG_ERR_BAD_URI
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://foo.gnupg.org:8080/.not-so-well-known/openpgpkey/hu/12345678",
|
||||
"http://foo.gnupg.org:8080/.well-known/openpgpkey/hu/12345678",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http:///.no-so-well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
GPG_ERR_BAD_URI
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org:8080/.not-so-well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org:8080/.not-so-well-known/openpgpkey/hu/12345678",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org:8/.not-so-well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org:8/.not-so-well-known/openpgpkey/hu/12345678",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org:/.no-so-well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org:/.no-so-well-known/openpgpkey/hu/12345678",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org/",
|
||||
"http://gnupg.org/",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.net",
|
||||
"http://gnupg.net/.well-known/openpgpkey/hu/12345678",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org",
|
||||
"http://gnupg.org",
|
||||
"http://gnupg.org",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org",
|
||||
"http://foo.gnupg.org",
|
||||
"http://foo.gnupg.org",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/",
|
||||
"http://foo.gnupg.org",
|
||||
"http://foo.gnupg.org/",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org",
|
||||
"http://foo.gnupg.org/",
|
||||
"http://foo.gnupg.org",
|
||||
0
|
||||
},
|
||||
{
|
||||
"http://gnupg.org/.well-known/openpgpkey/hu/12345678",
|
||||
"http://gnupg.org/something-else",
|
||||
"http://gnupg.org/something-else",
|
||||
0
|
||||
},
|
||||
};
|
||||
int tidx;
|
||||
http_redir_info_t ri;
|
||||
gpg_error_t err;
|
||||
char *newurl;
|
||||
|
||||
err = http_prepare_redirect (NULL, 301, tests[0].location, &newurl);
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_ARG)
|
||||
fail (0);
|
||||
memset (&ri, 0, sizeof ri);
|
||||
err = http_prepare_redirect (&ri, 301, tests[0].location, &newurl);
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_ARG)
|
||||
fail (0);
|
||||
memset (&ri, 0, sizeof ri);
|
||||
ri.silent = 1;
|
||||
ri.orig_url = "http://example.org";
|
||||
err = http_prepare_redirect (&ri, 301, tests[0].location, &newurl);
|
||||
if (gpg_err_code (err) != GPG_ERR_NO_DATA)
|
||||
fail (0);
|
||||
|
||||
for (tidx = 0; tidx < DIM (tests); tidx++)
|
||||
{
|
||||
memset (&ri, 0, sizeof ri);
|
||||
ri.silent = 1;
|
||||
ri.redirects_left = 1;
|
||||
ri.orig_url = tests[tidx].url;
|
||||
|
||||
err = http_prepare_redirect (&ri, 301, tests[tidx].location, &newurl);
|
||||
if (err && newurl)
|
||||
fail (tidx);
|
||||
if (err && gpg_err_code (err) != tests[tidx].expect_err)
|
||||
fail (tidx);
|
||||
if (err)
|
||||
continue;
|
||||
if (!newurl)
|
||||
fail (tidx);
|
||||
if (strcmp (tests[tidx].expect_url, newurl))
|
||||
{
|
||||
fprintf (stderr, "want: '%s'\n", tests[tidx].expect_url);
|
||||
fprintf (stderr, "got : '%s'\n", newurl);
|
||||
fail (tidx);
|
||||
}
|
||||
|
||||
xfree (newurl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
test_http_prepare_redirect ();
|
||||
|
||||
return 0;
|
||||
}
|
@ -137,7 +137,7 @@ my_http_tls_verify_cb (void *opaque,
|
||||
(void)session;
|
||||
(void)http_flags;
|
||||
|
||||
/* Get the peer's certs fron ntbtls. */
|
||||
/* Get the peer's certs from ntbtls. */
|
||||
for (idx = 0;
|
||||
(cert = ntbtls_x509_get_peer_cert (tls_context, idx)); idx++)
|
||||
{
|
||||
@ -394,9 +394,9 @@ main (int argc, char **argv)
|
||||
else
|
||||
{
|
||||
printf ("Auth : %s\n", uri->auth? uri->auth:"[none]");
|
||||
printf ("Host : %s\n", uri->host);
|
||||
printf ("Host : %s (off=%hu)\n", uri->host, uri->off_host);
|
||||
printf ("Port : %u\n", uri->port);
|
||||
printf ("Path : %s\n", uri->path);
|
||||
printf ("Path : %s (off=%hu)\n", uri->path, uri->off_path);
|
||||
for (r = uri->params; r; r = r->next)
|
||||
{
|
||||
printf ("Params: %s", r->name);
|
||||
|
@ -116,7 +116,7 @@ workqueue_add_task (wqtask_t func, const char *args, unsigned int session_id,
|
||||
|
||||
|
||||
/* Run the task described by ITEM. ITEM must have been detached from
|
||||
* the workqueue; its ownership is transferred to this fucntion. */
|
||||
* the workqueue; its ownership is transferred to this function. */
|
||||
static void
|
||||
run_a_task (ctrl_t ctrl, wqitem_t item)
|
||||
{
|
||||
|
12
doc/DETAILS
12
doc/DETAILS
@ -59,7 +59,7 @@ described here.
|
||||
- uat :: User attribute (same as user id except for field 10).
|
||||
- sig :: Signature
|
||||
- rev :: Revocation signature
|
||||
- rvs :: Recocation signature (standalone) [since 2.2.9]
|
||||
- rvs :: Revocation signature (standalone) [since 2.2.9]
|
||||
- fpr :: Fingerprint (fingerprint is in field 10)
|
||||
- pkd :: Public key data [*]
|
||||
- grp :: Keygrip
|
||||
@ -126,7 +126,7 @@ described here.
|
||||
*** Field 4 - Public key algorithm
|
||||
|
||||
The values here are those from the OpenPGP specs or if they are
|
||||
greather than 255 the algorithm ids as used by Libgcrypt.
|
||||
greater than 255 the algorithm ids as used by Libgcrypt.
|
||||
|
||||
*** Field 5 - KeyID
|
||||
|
||||
@ -544,7 +544,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
|
||||
*** DECRYPTION_KEY <fpr> <fpr2> <otrust>
|
||||
This line is emitted when a public key decryption succeeded in
|
||||
providing a session key. <fpr> is the hexified fingerprint of the
|
||||
actual key used for descryption. <fpr2> is the fingerprint of the
|
||||
actual key used for decryption. <fpr2> is the fingerprint of the
|
||||
primary key. <otrust> is the letter with the ownertrust; this is
|
||||
in general a 'u' which stands for ultimately trusted.
|
||||
*** DECRYPTION_INFO <mdc_method> <sym_algo> [<aead_algo>]
|
||||
@ -700,7 +700,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
|
||||
|
||||
- 0 :: No specific reason given
|
||||
- 1 :: Not Found
|
||||
- 2 :: Ambigious specification
|
||||
- 2 :: Ambiguous specification
|
||||
- 3 :: Wrong key usage
|
||||
- 4 :: Key revoked
|
||||
- 5 :: Key expired
|
||||
@ -1016,7 +1016,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
|
||||
- 2 :: bad PIN
|
||||
|
||||
*** SC_OP_SUCCESS
|
||||
A smart card operaion succeeded. This status is only printed for
|
||||
A smart card operation succeeded. This status is only printed for
|
||||
certain operation and is mostly useful to check whether a PIN
|
||||
change really worked.
|
||||
|
||||
@ -1073,7 +1073,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
|
||||
Deleting a key failed. Reason codes are:
|
||||
- 1 :: No such key
|
||||
- 2 :: Must delete secret key first
|
||||
- 3 :: Ambigious specification
|
||||
- 3 :: Ambiguous specification
|
||||
- 4 :: Key is stored on a smartcard.
|
||||
|
||||
*** PROGRESS <what> <char> <cur> <total> [<units>]
|
||||
|
@ -150,7 +150,7 @@ Note that such a comment will be removed if the git commit option
|
||||
if ( 42 == foo )
|
||||
#+end_src
|
||||
this is harder to read and modern compilers are pretty good in
|
||||
detecing accidential assignments. It is also suggested not to
|
||||
detecing accidental assignments. It is also suggested not to
|
||||
compare to 0 or NULL but to test the value direct or with a '!';
|
||||
this makes it easier to see that a boolean test is done.
|
||||
- We use our own printf style functions like =es_printf=, and
|
||||
@ -342,7 +342,7 @@ Note that such a comment will be removed if the git commit option
|
||||
- g10/main.h :: Prototypes and some constants
|
||||
- g10/mainproc.c :: Message processing
|
||||
- g10/armor.c :: Ascii armor filter
|
||||
- g10/mdfilter.c :: Filter to calculate hashs
|
||||
- g10/mdfilter.c :: Filter to calculate hashes
|
||||
- g10/textfilter.c :: Filter to handle CR/LF and trailing white space
|
||||
- g10/cipher.c :: En-/Decryption filter
|
||||
- g10/misc.c :: Utility functions
|
||||
@ -395,7 +395,7 @@ The *secure versions allocate memory in the secure memory. That is,
|
||||
swapping out of this memory is avoided and is gets overwritten on
|
||||
free. Use this for passphrases, session keys and other sensitive
|
||||
material. This memory set aside for secure memory is linited to a few
|
||||
k. In general the function don't print a memeory message and
|
||||
k. In general the function don't print a memory message and
|
||||
terminate the process if there is not enough memory available. The
|
||||
"try" versions of the functions return NULL instead.
|
||||
|
||||
|
@ -69,7 +69,7 @@ nobase_dist_doc_DATA = FAQ DETAILS HACKING DCO TRANSLATE OpenPGP KEYSERVER \
|
||||
gnupg_TEXINFOS = \
|
||||
gpg.texi gpgsm.texi gpg-agent.texi scdaemon.texi instguide.texi \
|
||||
tools.texi debugging.texi glossary.texi contrib.texi gpl.texi \
|
||||
sysnotes.texi dirmngr.texi wks.texi \
|
||||
sysnotes.texi dirmngr.texi wks.texi gpg-card.texi \
|
||||
gnupg-module-overview.svg \
|
||||
gnupg-card-architecture.fig \
|
||||
howtos.texi howto-create-a-server-cert.texi
|
||||
@ -89,12 +89,13 @@ YAT2M_OPTIONS = -I $(srcdir) \
|
||||
--release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard 2.2"
|
||||
|
||||
myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \
|
||||
dirmngr.texi scdaemon.texi tools.texi wks.texi
|
||||
dirmngr.texi scdaemon.texi tools.texi wks.texi \
|
||||
gpg-card.texi
|
||||
myman_pages = gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 \
|
||||
watchgnupg.1 gpgconf.1 addgnupghome.8 gpg-preset-passphrase.1 \
|
||||
gpg-connect-agent.1 gpgparsemail.1 symcryptrun.1 gpgtar.1 \
|
||||
applygnupgdefaults.8 gpg-wks-client.1 gpg-wks-server.1 \
|
||||
dirmngr-client.1
|
||||
dirmngr-client.1 gpg-card.1
|
||||
if USE_GPG2_HACK
|
||||
myman_pages += gpg2.1 gpgv2.1
|
||||
else
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
Add an infor page for watchgnupg.
|
||||
Add an info page for watchgnupg.
|
||||
|
||||
> * How to mark a CA certificate as trusted.
|
||||
|
||||
@ -57,7 +57,7 @@ or
|
||||
|
||||
In general you should first import the root certificates and then down
|
||||
to the end user certificate. You may put all into one file and gpgsm
|
||||
will do the right thing in this case independend of the order.
|
||||
will do the right thing in this case independent of the order.
|
||||
|
||||
While verifying a signature, all included certificates are
|
||||
automagically imported.
|
||||
@ -82,7 +82,7 @@ you get an output like:
|
||||
uid:::::::::CN=Werner Koch,OU=test,O=g10 Code,C=de::
|
||||
uid:::::::::<wk@g10code.de>::
|
||||
|
||||
This should be familar to advanced gpg-users; see doc/DETAILS in gpg
|
||||
This should be familiar to advanced gpg-users; see doc/DETAILS in gpg
|
||||
1.3 (CVS HEAD) for a description of the records. The value in the
|
||||
"grp" tagged record is the so called keygrip and you should find a
|
||||
file ~/.gnupg/private-keys-v1.d/C92DB9CFD588ADE846BE3AC4E7A2E1B11A4A2ADB.key
|
||||
|
@ -1096,7 +1096,7 @@ as a binary blob.
|
||||
@c In the end the same fucntionality is used, albeit hidden by a couple
|
||||
@c of indirection and argument and result code mangling. It furthere
|
||||
@c ingetrages OCSP checking depending on options are the way it is
|
||||
@c called. GPGSM still uses this command but might eventuall switch over
|
||||
@c called. GPGSM still uses this command but might eventually switch over
|
||||
@c to CHECKCRL and CHECKOCSP so that ISVALID can be retired.
|
||||
@c
|
||||
@c
|
||||
|
@ -1096,7 +1096,7 @@ update this FAQ in the next month. See the section "Changes" for recent updates
|
||||
As of 1.0.3, keys generated with gpg are created with preferences to
|
||||
TWOFISH (and AES since 1.0.4) and that also means that they have the
|
||||
capability to use the new MDC encryption method. This will go into
|
||||
OpenPGP soon, and is also suppoted by PGP 7. This new method avoids
|
||||
OpenPGP soon, and is also supported by PGP 7. This new method avoids
|
||||
a (not so new) attack on all email encryption systems.
|
||||
|
||||
This in turn means that pre-1.0.3 gpg binaries have problems with
|
||||
|
@ -142,15 +142,16 @@ the administration and the architecture.
|
||||
* Specify a User ID:: How to Specify a User Id.
|
||||
* Trust Values:: How GnuPG displays trust values.
|
||||
|
||||
* Helper Tools:: Description of small helper tools
|
||||
* Web Key Service:: Tools for the Web Key Service
|
||||
* Smart Card Tool:: Tool to administrate smart cards.
|
||||
* Helper Tools:: Description of small helper tools.
|
||||
* Web Key Service:: Tools for the Web Key Service.
|
||||
|
||||
* Howtos:: How to do certain things.
|
||||
* System Notes:: Notes pertaining to certain OSes.
|
||||
* Debugging:: How to solve problems
|
||||
* Debugging:: How to solve problems.
|
||||
|
||||
* Copying:: GNU General Public License says
|
||||
how you can copy and share GnuPG
|
||||
how you can copy and share GnuPG.
|
||||
* Contributors:: People who have contributed to GnuPG.
|
||||
|
||||
* Glossary:: Short description of terms used.
|
||||
@ -186,6 +187,7 @@ the administration and the architecture.
|
||||
@cindex trust values
|
||||
@include trust-values.texi
|
||||
|
||||
@include gpg-card.texi
|
||||
@include tools.texi
|
||||
@include wks.texi
|
||||
|
||||
@ -237,5 +239,3 @@ the administration and the architecture.
|
||||
|
||||
|
||||
@bye
|
||||
|
||||
|
||||
|
@ -585,16 +585,19 @@ local gpg-agent and use its private keys. This enables decrypting or
|
||||
signing data on a remote machine without exposing the private keys to the
|
||||
remote machine.
|
||||
|
||||
@anchor{option --enable-extended-key-format}
|
||||
@item --enable-extended-key-format
|
||||
@itemx --disable-extended-key-format
|
||||
@opindex enable-extended-key-format
|
||||
This option creates keys in the extended private key format. Changing
|
||||
the passphrase of a key will also convert the key to that new format.
|
||||
Using this option makes the private keys unreadable for gpg-agent
|
||||
versions before 2.1.12. The advantage of the extended private key
|
||||
format is that it is text based and can carry additional meta data.
|
||||
Note that this option also changes the key protection format to use
|
||||
OCB mode.
|
||||
@opindex disable-extended-key-format
|
||||
Since version 2.3 keys are created in the extended private key format.
|
||||
Changing the passphrase of a key will also convert the key to that new
|
||||
format. This new key format is supported since GnuPG version 2.1.12
|
||||
and thus there should be no need to disable it. The disable option
|
||||
allows to revert to the old behavior for new keys; be aware that keys
|
||||
are never migrated back to the old format. However if the enable
|
||||
option has been used the disable option won't have an effect. The
|
||||
advantage of the extended private key format is that it is text based
|
||||
and can carry additional meta data.
|
||||
|
||||
@anchor{option --enable-ssh-support}
|
||||
@item --enable-ssh-support
|
||||
@ -669,12 +672,19 @@ For an heavy loaded gpg-agent with many concurrent connection this
|
||||
option avoids sign or decrypt errors due to out of secure memory error
|
||||
returns.
|
||||
|
||||
@item --s2k-calibration @var{milliseconds}
|
||||
@opindex s2k-calibration
|
||||
Change the default calibration time to @var{milliseconds}. The given
|
||||
value is capped at 60 seconds; a value of 0 resets to the compiled-in
|
||||
default. This option is re-read on a SIGHUP (or @code{gpgconf
|
||||
--reload gpg-agent}) and the S2K count is then re-calibrated.
|
||||
|
||||
@item --s2k-count @var{n}
|
||||
@opindex s2k-count
|
||||
Specify the iteration count used to protect the passphrase. This
|
||||
option can be used to override the auto-calibration done by default.
|
||||
The auto-calibration computes a count which requires 100ms to mangle
|
||||
a given passphrase.
|
||||
The auto-calibration computes a count which requires by default 100ms
|
||||
to mangle a given passphrase. See also @option{--s2k-calibration}.
|
||||
|
||||
To view the actually used iteration count and the milliseconds
|
||||
required for an S2K operation use:
|
||||
|
517
doc/gpg-card.texi
Normal file
517
doc/gpg-card.texi
Normal file
@ -0,0 +1,517 @@
|
||||
@c card-tool.texi - man page for gpg-card-tool
|
||||
@c Copyright (C) 2019 g10 Code GmbH
|
||||
@c This is part of the GnuPG manual.
|
||||
@c For copying conditions, see the file GnuPG.texi.
|
||||
|
||||
@include defs.inc
|
||||
|
||||
@node Smart Card Tool
|
||||
@chapter Smart Card Tool
|
||||
|
||||
GnuPG comes with tool to administrate smart cards and USB tokens. This
|
||||
tool is an extension of the @option{--edit-key} command available with
|
||||
@command{gpg}.
|
||||
|
||||
@menu
|
||||
* gpg-card:: Administrate smart cards.
|
||||
@end menu
|
||||
|
||||
@c
|
||||
@c GPG-CARD-TOOL
|
||||
@c
|
||||
@manpage gpg-card.1
|
||||
@node gpg-card
|
||||
@section Administrate smart cards.
|
||||
@ifset manverb
|
||||
.B gpg-card
|
||||
\- Administrate Smart Cards
|
||||
@end ifset
|
||||
|
||||
@mansect synopsis
|
||||
@ifset manverb
|
||||
.B gpg-card
|
||||
.RI [ options ]
|
||||
.br
|
||||
.B gpg-card
|
||||
.RI [ options ]
|
||||
.I command
|
||||
.RI {
|
||||
.B --
|
||||
.I command
|
||||
.RI }
|
||||
@end ifset
|
||||
|
||||
@mansect description
|
||||
The @command{gpg-card} is used to administrate smart cards and USB
|
||||
tokens. It provides a superset of features from @command{gpg
|
||||
--card-edit} an can be considered a frontend to @command{scdaemon}
|
||||
which is a daemon started by @command{gpg-agent} to handle smart
|
||||
cards.
|
||||
|
||||
If @command{gpg-card} is invoked without commands an interactive
|
||||
mode is used.
|
||||
|
||||
If @command{gpg-card} is invoked with one or more commands the
|
||||
same commands as available in the interactive mode are run from the
|
||||
command line. These commands need to be delimited with a double-dash.
|
||||
If a double-dash or a shell specific character is required as part of
|
||||
a command the entire command needs to be put in quotes. If one of
|
||||
those commands returns an error the remaining commands are mot anymore
|
||||
run unless the command was prefixed with a single dash.
|
||||
|
||||
A list of commands is available by using the command @code{help} and a
|
||||
detailed description of each command is printed by using @code{help
|
||||
COMMAND}.
|
||||
|
||||
See the NOTES sections for instructions pertaining to specific cards
|
||||
or card applications.
|
||||
|
||||
@mansect options
|
||||
@noindent
|
||||
@command{gpg-card} understands these options:
|
||||
|
||||
@table @gnupgtabopt
|
||||
|
||||
@item --with-colons
|
||||
@opindex with-colons
|
||||
This option has currently no effect.
|
||||
|
||||
@item --status-fd @var{n}
|
||||
@opindex status-fd
|
||||
Write special status strings to the file descriptor @var{n}. This
|
||||
program returns only the status messages SUCCESS or FAILURE which are
|
||||
helpful when the caller uses a double fork approach and can't easily
|
||||
get the return code of the process.
|
||||
|
||||
@item --verbose
|
||||
@opindex verbose
|
||||
Enable extra informational output.
|
||||
|
||||
@item --quiet
|
||||
@opindex quiet
|
||||
Disable almost all informational output.
|
||||
|
||||
@item --version
|
||||
@opindex version
|
||||
Print version of the program and exit.
|
||||
|
||||
@item --help
|
||||
@opindex help
|
||||
Display a brief help page and exit.
|
||||
|
||||
@item --no-autostart
|
||||
@opindex no-autostart
|
||||
Do not start the gpg-agent if it has not yet been started and its
|
||||
service is required. This option is mostly useful on machines where
|
||||
the connection to gpg-agent has been redirected to another machines.
|
||||
|
||||
@item --agent-program @var{file}
|
||||
@opindex agent-program
|
||||
Specify the agent program to be started if none is running. The
|
||||
default value is determined by running @command{gpgconf} with the
|
||||
option @option{--list-dirs}.
|
||||
|
||||
@item --gpg-program @var{file}
|
||||
@opindex gpg-program
|
||||
Specify a non-default gpg binary to be used by certain commands.
|
||||
|
||||
@item --gpgsm-program @var{file}
|
||||
@opindex gpgsm-program
|
||||
Specify a non-default gpgsm binary to be used by certain commands.
|
||||
|
||||
@end table
|
||||
|
||||
@mansect notes (OpenPGP)
|
||||
The support for OpenPGP cards in @command{gpg-card} is not yet
|
||||
complete. For missing features, please continue to use @code{gpg
|
||||
--card-edit}.
|
||||
|
||||
@mansect notes (PIV)
|
||||
@noindent
|
||||
GnuPG has support for PIV cards (``Personal Identity Verification''
|
||||
as specified by NIST Special Publication 800-73-4). This section
|
||||
describes how to initialize (personalize) a fresh Yubikey token
|
||||
featuring the PIV application (requires Yubikey-5). We assume that
|
||||
the credentials have not yet been changed and thus are:
|
||||
@table @asis
|
||||
@item Authentication key
|
||||
This is a 24 byte key described by the hex string
|
||||
@code{010203040506070801020304050607080102030405060708}.
|
||||
@item PIV Application PIN
|
||||
This is the string @code{123456}.
|
||||
@item PIN Unblocking Key
|
||||
This is the string @code{12345678}.
|
||||
@end table
|
||||
See the example section on how to change these defaults. For
|
||||
production use it is important to use secure values for them. Note that
|
||||
the Authentication Key is not queried via the usual Pinentry dialog
|
||||
but needs to be entered manually or read from a file. The use of a
|
||||
dedicated machine to personalize tokens is strongly suggested.
|
||||
|
||||
To see what is on the card, the command @code{list} can be given. We
|
||||
will use the interactive mode in the following (the string
|
||||
@emph{gpg/card>} is the prompt). An example output for a fresh card
|
||||
is:
|
||||
|
||||
@example
|
||||
gpg/card> list
|
||||
Reader ...........: 1050:0407:X:0
|
||||
Card type ........: yubikey
|
||||
Card firmware ....: 5.1.2
|
||||
Serial number ....: D2760001240102010006090746250000
|
||||
Application type .: OpenPGP
|
||||
Version ..........: 2.1
|
||||
[...]
|
||||
@end example
|
||||
|
||||
It can be seen by the ``Application type'' line that GnuPG selected the
|
||||
OpenPGP application of the Yubikey. This is because GnuPG assigns the
|
||||
highest priority to the OpenPGP application. To use the PIV
|
||||
application of the Yubikey, the OpenPGP application needs to be
|
||||
disabled:
|
||||
|
||||
@example
|
||||
gpg/card> yubikey disable all opgp
|
||||
gpg/card> yubikey list
|
||||
Application USB NFC
|
||||
-----------------------
|
||||
OTP yes yes
|
||||
U2F yes yes
|
||||
OPGP no no
|
||||
PIV yes no
|
||||
OATH yes yes
|
||||
FIDO2 yes yes
|
||||
gpg/card> reset
|
||||
@end example
|
||||
|
||||
The @code{reset} is required so that the GnuPG system rereads the
|
||||
card. Note that disabled applications keep all their data and can at
|
||||
any time be re-enabled (see @emph{help yubikey}). Now a @emph{list}
|
||||
command shows this:
|
||||
|
||||
@example
|
||||
gpg/card> list
|
||||
Reader ...........: 1050:0407:X:0
|
||||
Card type ........: yubikey
|
||||
Card firmware ....: 5.1.2
|
||||
Serial number ....: FF020001008A77C1
|
||||
Application type .: PIV
|
||||
Version ..........: 1.0
|
||||
Displayed s/n ....: yk-9074625
|
||||
PIN usage policy .: app-pin
|
||||
PIN retry counter : - 3 -
|
||||
PIV authentication: [none]
|
||||
keyref .....: PIV.9A
|
||||
Card authenticat. : [none]
|
||||
keyref .....: PIV.9E
|
||||
Digital signature : [none]
|
||||
keyref .....: PIV.9C
|
||||
Key management ...: [none]
|
||||
keyref .....: PIV.9D
|
||||
@end example
|
||||
|
||||
Note that the ``Displayed s/sn'' is printed on the token and also
|
||||
shown in Pinentry prompts asking for the PIN. The four standard key
|
||||
slots are always shown, if other key slots are initialized they are
|
||||
shown as well. The @emph{PIV authentication} key (internal reference
|
||||
@emph{PIV.9A}) is used to authenticate the card and the card holder.
|
||||
The use of the associated private key is protected by the Application
|
||||
PIN which needs to be provided once and the key can the be used until
|
||||
the card is reset or removed from the reader or USB port. GnuPG uses
|
||||
this key with its @emph{Secure Shell} support. The @emph{Card
|
||||
authentication} key (@emph{PIV.9E}) is also known as the CAK and used
|
||||
to support physical access applications. The private key is not
|
||||
protected by a PIN and can thus immediately be used. The @emph{Digital
|
||||
signature} key (@emph{PIV.9C}) is used to digitally sign documents.
|
||||
The use of the associated private key is protected by the Application
|
||||
PIN which needs to be provided for each signing operation. The
|
||||
@emph{Key management} key (@emph{PIV.9D}) is used for encryption. The
|
||||
use of the associated private key is protected by the Application PIN
|
||||
which needs to be provided only once so that decryption operations can
|
||||
then be done until the card is reset or removed from the reader or USB
|
||||
port.
|
||||
|
||||
We now generate tree of the four keys. Note that GnuPG does currently
|
||||
not use the the @emph{Card authentication} key but because it is
|
||||
mandatory by the specs we create it anyway. Key generation requires
|
||||
that we authenticate to the card. This can be done either on the
|
||||
command line (which would reveal the key):
|
||||
|
||||
@example
|
||||
gpg/card> auth 010203040506070801020304050607080102030405060708
|
||||
@end example
|
||||
|
||||
or by reading the key from a file. That file needs to consist of one
|
||||
LF terminated line with the hex encoded key (as above):
|
||||
|
||||
@example
|
||||
gpg/card> auth < myauth.key
|
||||
@end example
|
||||
|
||||
As usual @samp{help auth} gives help for this command. An error
|
||||
message is printed if a non-matching key is used. The authentication
|
||||
is valid until a reset of the card or until the card is removed from
|
||||
the reader or the USB port. Note that that in non-interactive mode
|
||||
the @samp{<} needs to be quoted so that the shell does not interpret
|
||||
it as a its own redirection symbol.
|
||||
|
||||
@noindent
|
||||
Here are the actual commands to generate the keys:
|
||||
|
||||
@example
|
||||
gpg/card> generate --algo=nistp384 PIV.9A
|
||||
PIV card no. yk-9074625 detected
|
||||
gpg/card> generate --algo=nistp256 PIV.9E
|
||||
PIV card no. yk-9074625 detected
|
||||
gpg/card> generate --algo=rsa2048 PIV.9C
|
||||
PIV card no. yk-9074625 detected
|
||||
@end example
|
||||
|
||||
If a key has already been created for one of the slots an error will
|
||||
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
|
||||
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:
|
||||
|
||||
@example
|
||||
gpg/card> list
|
||||
Reader ...........: 1050:0407:X:0
|
||||
Card type ........: yubikey
|
||||
Card firmware ....: 5.1.2
|
||||
Serial number ....: FF020001008A77C1
|
||||
Application type .: PIV
|
||||
Version ..........: 1.0
|
||||
Displayed s/n ....: yk-9074625
|
||||
PIN usage policy .: app-pin
|
||||
PIN retry counter : - 3 -
|
||||
PIV authentication: 213D1825FDE0F8240CB4E4229F01AF90AC658C2E
|
||||
keyref .....: PIV.9A (auth)
|
||||
algorithm ..: nistp384
|
||||
Card authenticat. : 7A53E6CFFE7220A0E646B4632EE29E5A7104499C
|
||||
keyref .....: PIV.9E (auth)
|
||||
algorithm ..: nistp256
|
||||
Digital signature : 32A6C6FAFCB8421878608AAB452D5470DD3223ED
|
||||
keyref .....: PIV.9C (sign,cert)
|
||||
algorithm ..: rsa2048
|
||||
Key management ...: [none]
|
||||
keyref .....: PIV.9D
|
||||
@end example
|
||||
|
||||
The primary information for each key is the @emph{keygrip}, a 40 byte
|
||||
hex-string identifying the key. This keygrip is a unique identifier
|
||||
for the specific parameters of a key. It is used by
|
||||
@command{gpg-agent} and other parts of GnuPG to associate a private
|
||||
key to its protocol specific certificate format (X.509, OpenPGP, or
|
||||
SecureShell). Below the keygrip the key reference along with the key
|
||||
usage capabilities are show. Finally the algorithm is printed in the
|
||||
format used by @command {gpg}. At that point no other information is
|
||||
shown because for these new keys gpg won't be able to find matching
|
||||
certificates.
|
||||
|
||||
Although we could have created the @emph{Key management} key also with
|
||||
the generate command, we will create that key off-card so that a
|
||||
backup exists. To accomplish this a key needs to be created with
|
||||
either @command{gpg} or @command{gpgsm} or imported in one of these
|
||||
tools. In our example we create a self-signed X.509 certificate (exit
|
||||
the gpg-card tool, first):
|
||||
|
||||
@example
|
||||
$ gpgsm --gen-key -o encr.crt
|
||||
(1) RSA
|
||||
(2) Existing key
|
||||
(3) Existing key from card
|
||||
Your selection? 1
|
||||
What keysize do you want? (3072) 2048
|
||||
Requested keysize is 2048 bits
|
||||
Possible actions for a RSA key:
|
||||
(1) sign, encrypt
|
||||
(2) sign
|
||||
(3) encrypt
|
||||
Your selection? 3
|
||||
Enter the X.509 subject name: CN=Encryption key for yk-9074625,O=example,C=DE
|
||||
Enter email addresses (end with an empty line):
|
||||
> otto@@example.net
|
||||
>
|
||||
Enter DNS names (optional; end with an empty line):
|
||||
>
|
||||
Enter URIs (optional; end with an empty line):
|
||||
>
|
||||
Create self-signed certificate? (y/N) y
|
||||
These parameters are used:
|
||||
Key-Type: RSA
|
||||
Key-Length: 2048
|
||||
Key-Usage: encrypt
|
||||
Serial: random
|
||||
Name-DN: CN=Encryption key for yk-9074625,O=example,C=DE
|
||||
Name-Email: otto@@example.net
|
||||
|
||||
Proceed with creation? (y/N)
|
||||
Now creating self-signed certificate. This may take a while ...
|
||||
gpgsm: about to sign the certificate for key: &34798AAFE0A7565088101CC4AE31C5C8C74461CB
|
||||
gpgsm: certificate created
|
||||
Ready.
|
||||
$ gpgsm --import encr.crt
|
||||
gpgsm: certificate imported
|
||||
gpgsm: total number processed: 1
|
||||
gpgsm: imported: 1
|
||||
@end example
|
||||
|
||||
Note the last steps which imported the created certificate. If you
|
||||
you instead created a certificate signing request (CSR) instead of a
|
||||
self-signed certificate and sent this off to a CA you would do the
|
||||
same import step with the certificate received from the CA. Take note
|
||||
of the keygrip (prefixed with an ampersand) as shown during the
|
||||
certificate creation or listed it again using @samp{gpgsm
|
||||
--with-keygrip -k otto@@example.net}. Now to move the key and
|
||||
certificate to the card start @command{gpg-card} again and enter:
|
||||
|
||||
@example
|
||||
gpg/card> writekey PIV.9D 34798AAFE0A7565088101CC4AE31C5C8C74461CB
|
||||
gpg/card> writecert PIV.9D < encr.crt
|
||||
@end example
|
||||
|
||||
If you entered a passphrase to protect the private key, you will be
|
||||
asked for it via the Pinentry prompt. On success the key and the
|
||||
certificate has been written to the card and a @code{list} command
|
||||
shows:
|
||||
|
||||
@example
|
||||
[...]
|
||||
Key management ...: 34798AAFE0A7565088101CC4AE31C5C8C74461CB
|
||||
keyref .....: PIV.9D (encr)
|
||||
algorithm ..: rsa2048
|
||||
used for ...: X.509
|
||||
user id ..: CN=Encryption key for yk-9074625,O=example,C=DE
|
||||
user id ..: <otto@@example.net>
|
||||
@end example
|
||||
|
||||
In case the same key (identified by the keygrip) has been used for
|
||||
several certificates you will see several ``used for'' parts. With
|
||||
this the encryption key is now fully functional and can be used to
|
||||
decrypt messages encrypted to this certificate. @sc{Take care:} the
|
||||
original key is still stored on-disk and should be moved to a backup
|
||||
medium. This can simply be done by copying the file
|
||||
@file{34798AAFE0A7565088101CC4AE31C5C8C74461CB.key} from the directory
|
||||
@file{~/.gnupg/private-keys-v1.d/} to the backup medium and deleting
|
||||
the file at its original place.
|
||||
|
||||
The final example is to create a self-signed certificate for digital
|
||||
signatures. Leave @command{gpg-card} using @code{quit} or by pressing
|
||||
Control-D and use gpgsm:
|
||||
|
||||
@example
|
||||
$ gpgsm --learn
|
||||
$ gpgsm --gen-key -o sign.crt
|
||||
Please select what kind of key you want:
|
||||
(1) RSA
|
||||
(2) Existing key
|
||||
(3) Existing key from card
|
||||
Your selection? 3
|
||||
Serial number of the card: FF020001008A77C1
|
||||
Available keys:
|
||||
(1) 213D1825FDE0F8240CB4E4229F01AF90AC658C2E PIV.9A nistp384
|
||||
(2) 7A53E6CFFE7220A0E646B4632EE29E5A7104499C PIV.9E nistp256
|
||||
(3) 32A6C6FAFCB8421878608AAB452D5470DD3223ED PIV.9C rsa2048
|
||||
(4) 34798AAFE0A7565088101CC4AE31C5C8C74461CB PIV.9D rsa2048
|
||||
Your selection? 3
|
||||
Possible actions for a RSA key:
|
||||
(1) sign, encrypt
|
||||
(2) sign
|
||||
(3) encrypt
|
||||
Your selection? 2
|
||||
Enter the X.509 subject name: CN=Signing key for yk-9074625,O=example,C=DE
|
||||
Enter email addresses (end with an empty line):
|
||||
> otto@@example.net
|
||||
>
|
||||
Enter DNS names (optional; end with an empty line):
|
||||
>
|
||||
Enter URIs (optional; end with an empty line):
|
||||
>
|
||||
Create self-signed certificate? (y/N)
|
||||
These parameters are used:
|
||||
Key-Type: card:PIV.9C
|
||||
Key-Length: 1024
|
||||
Key-Usage: sign
|
||||
Serial: random
|
||||
Name-DN: CN=Signing key for yk-9074625,O=example,C=DE
|
||||
Name-Email: otto@@example.net
|
||||
|
||||
Proceed with creation? (y/N) y
|
||||
Now creating self-signed certificate. This may take a while ...
|
||||
gpgsm: about to sign the certificate for key: &32A6C6FAFCB8421878608AAB452D5470DD3223ED
|
||||
gpgsm: certificate created
|
||||
Ready.
|
||||
$ gpgsm --import sign.crt
|
||||
gpgsm: certificate imported
|
||||
gpgsm: total number processed: 1
|
||||
gpgsm: imported: 1
|
||||
@end example
|
||||
|
||||
The use of @samp{gpgsm --learn} is currently necessary so that
|
||||
gpg-agent knows what keys are available on the card. The need for
|
||||
this command will eventually be removed. The remaining commands are
|
||||
similar to the creation of an on-disk key. However, here we select
|
||||
the @samp{Digital signature} key. During the creation process you
|
||||
will be asked for the Application PIN of the card. The final step is
|
||||
to write the certificate to the card using @command{gpg-card}:
|
||||
|
||||
@example
|
||||
gpg/card> writecert PIV.9C < sign.crt
|
||||
@end example
|
||||
|
||||
By running list again we will see the fully initialized card:
|
||||
|
||||
@example
|
||||
Reader ...........: 1050:0407:X:0
|
||||
Card type ........: yubikey
|
||||
Card firmware ....: 5.1.2
|
||||
Serial number ....: FF020001008A77C1
|
||||
Application type .: PIV
|
||||
Version ..........: 1.0
|
||||
Displayed s/n ....: yk-9074625
|
||||
PIN usage policy .: app-pin
|
||||
PIN retry counter : - [verified] -
|
||||
PIV authentication: 213D1825FDE0F8240CB4E4229F01AF90AC658C2E
|
||||
keyref .....: PIV.9A (auth)
|
||||
algorithm ..: nistp384
|
||||
Card authenticat. : 7A53E6CFFE7220A0E646B4632EE29E5A7104499C
|
||||
keyref .....: PIV.9E (auth)
|
||||
algorithm ..: nistp256
|
||||
Digital signature : 32A6C6FAFCB8421878608AAB452D5470DD3223ED
|
||||
keyref .....: PIV.9C (sign,cert)
|
||||
algorithm ..: rsa2048
|
||||
used for ...: X.509
|
||||
user id ..: CN=Signing key for yk-9074625,O=example,C=DE
|
||||
user id ..: <otto@@example.net>
|
||||
Key management ...: 34798AAFE0A7565088101CC4AE31C5C8C74461CB
|
||||
keyref .....: PIV.9D (encr)
|
||||
algorithm ..: rsa2048
|
||||
used for ...: X.509
|
||||
user id ..: CN=Encryption key for yk-9074625,O=example,C=DE
|
||||
user id ..: <otto@@example.net>
|
||||
@end example
|
||||
|
||||
It is now possible to sign and to encrypt with this card using gpgsm
|
||||
and to use the @samp{PIV authentication} key with ssh:
|
||||
|
||||
@example
|
||||
$ ssh-add -l
|
||||
384 SHA256:0qnJ0Y0ehWxKcx2frLfEljf6GCdlO55OZed5HqGHsaU cardno:yk-9074625 (ECDSA)
|
||||
@end example
|
||||
|
||||
As usual use ssh-add with the uppercase @samp{-L} to list the public
|
||||
ssh key. To use the certificates with Thunderbird or Mozilla, please
|
||||
consult the Scute manual for details.
|
||||
|
||||
|
||||
|
||||
@c @mansect examples
|
||||
|
||||
@mansect see also
|
||||
@ifset isman
|
||||
@command{scdaemon}(1)
|
||||
@end ifset
|
65
doc/gpg.texi
65
doc/gpg.texi
@ -624,9 +624,9 @@ fingerprint (preferred) or their keyid.
|
||||
@end table
|
||||
|
||||
|
||||
@c *******************************************
|
||||
@c ******* KEY MANGEMENT COMMANDS **********
|
||||
@c *******************************************
|
||||
@c ********************************************
|
||||
@c ******* KEY MANAGEMENT COMMANDS **********
|
||||
@c ********************************************
|
||||
@node OpenPGP Key Management
|
||||
@subsection How to manage your keys
|
||||
|
||||
@ -1328,6 +1328,10 @@ give the opposite meaning. The options are:
|
||||
meaningful when using @option{--with-colons} along with
|
||||
@option{--check-signatures}.
|
||||
|
||||
@item show-only-fpr-mbox
|
||||
@opindex list-options:show-only-fpr-mbox
|
||||
For each valid user-id which also has a valid mail address print
|
||||
only the fingerprint and the mail address.
|
||||
@end table
|
||||
|
||||
@item --verify-options @var{parameters}
|
||||
@ -1724,7 +1728,8 @@ Set what trust model GnuPG should follow. The models are:
|
||||
@opindex trust-model:auto
|
||||
Select the trust model depending on whatever the internal trust
|
||||
database says. This is the default model if such a database already
|
||||
exists.
|
||||
exists. Note that a tofu trust model is not considered here and
|
||||
must be enabled explicitly.
|
||||
@end table
|
||||
|
||||
@item --auto-key-locate @var{mechanisms}
|
||||
@ -1782,7 +1787,9 @@ list. The default is "local,wkd".
|
||||
|
||||
@item clear
|
||||
Clear all defined mechanisms. This is useful to override
|
||||
mechanisms given in a config file.
|
||||
mechanisms given in a config file. Note that a @code{nodefault} in
|
||||
@var{mechanisms} will also be cleared unless it is given after the
|
||||
@code{clear}.
|
||||
|
||||
@end table
|
||||
|
||||
@ -1888,32 +1895,12 @@ are available for all keyserver types, some common options are:
|
||||
retrieving keys by subkey id.
|
||||
|
||||
@item timeout
|
||||
Tell the keyserver helper program how long (in seconds) to try and
|
||||
perform a keyserver action before giving up. Note that performing
|
||||
multiple actions at the same time uses this timeout value per action.
|
||||
For example, when retrieving multiple keys via @option{--receive-keys}, the
|
||||
timeout applies separately to each key retrieval, and not to the
|
||||
@option{--receive-keys} command as a whole. Defaults to 30 seconds.
|
||||
|
||||
@item http-proxy=@var{value}
|
||||
This option is deprecated.
|
||||
Set the proxy to use for HTTP and HKP keyservers.
|
||||
This overrides any proxy defined in @file{dirmngr.conf}.
|
||||
|
||||
@item verbose
|
||||
This option has no more function since GnuPG 2.1. Use the
|
||||
@code{dirmngr} configuration options instead.
|
||||
|
||||
@item debug
|
||||
This option has no more function since GnuPG 2.1. Use the
|
||||
@code{dirmngr} configuration options instead.
|
||||
|
||||
@item check-cert
|
||||
This option has no more function since GnuPG 2.1. Use the
|
||||
@code{dirmngr} configuration options instead.
|
||||
|
||||
@itemx http-proxy=@var{value}
|
||||
@itemx verbose
|
||||
@itemx debug
|
||||
@itemx check-cert
|
||||
@item ca-cert-file
|
||||
This option has no more function since GnuPG 2.1. Use the
|
||||
These options have no more function since GnuPG 2.1. Use the
|
||||
@code{dirmngr} configuration options instead.
|
||||
|
||||
@end table
|
||||
@ -2342,6 +2329,11 @@ opposite meaning. The options are:
|
||||
on the keyring. This option is the same as running the @option{--edit-key}
|
||||
command "clean" after import. Defaults to no.
|
||||
|
||||
@item import-drop-uids
|
||||
Do not import any user ids or their binding signatures. This option
|
||||
can be used to update only the subkeys or other non-user id related
|
||||
information.
|
||||
|
||||
@item repair-keys. After import, fix various problems with the
|
||||
keys. For example, this reorders signatures, and strips duplicate
|
||||
signatures. Defaults to yes.
|
||||
@ -2506,6 +2498,11 @@ opposite meaning. The options are:
|
||||
running the @option{--edit-key} command "minimize" before export except
|
||||
that the local copy of the key is not modified. Defaults to no.
|
||||
|
||||
@item export-drop-uids
|
||||
Do no export any user id or attribute packets or their associates
|
||||
signatures. Note that due to missing user ids the resulting output is
|
||||
not strictly RFC-4880 compliant.
|
||||
|
||||
@item export-pka
|
||||
Instead of outputting the key material output PKA records suitable
|
||||
to put into DNS zone files. An ORIGIN line is printed before each
|
||||
@ -2612,7 +2609,7 @@ These options are obsolete and have no effect since GnuPG 2.1.
|
||||
@item --force-aead
|
||||
@opindex force-aead
|
||||
Force the use of AEAD encryption over MDC encryption. AEAD is a
|
||||
modern and faster way to do authenticated encrytion than the old MDC
|
||||
modern and faster way to do authenticated encryption than the old MDC
|
||||
method. See also options @option{--aead-algo} and
|
||||
@option{--chunk-size}.
|
||||
|
||||
@ -2768,7 +2765,7 @@ This option is obsolete; it is handled as an alias for @option{--pgp7}
|
||||
|
||||
@item --pgp7
|
||||
@opindex pgp7
|
||||
Set up all options to be as PGP 7 compliant as possible. This allowd
|
||||
Set up all options to be as PGP 7 compliant as possible. This allowed
|
||||
the ciphers IDEA, 3DES, CAST5,AES128, AES192, AES256, and TWOFISH.,
|
||||
the hashes MD5, SHA1 and RIPEMD160, and the compression algorithms
|
||||
none and ZIP. This option implies @option{--escape-from-lines} and
|
||||
@ -3040,7 +3037,7 @@ same thing.
|
||||
@opindex aead-algo
|
||||
Specify that the AEAD algorithm @var{name} is to be used. This is
|
||||
useful for symmetric encryption where no key preference are available
|
||||
to select the AEAD algorithm. Runing @command{@gpgname} with option
|
||||
to select the AEAD algorithm. Running @command{@gpgname} with option
|
||||
@option{--version} shows the available AEAD algorithms. In general,
|
||||
you do not want to use this option as it allows you to violate the
|
||||
OpenPGP standard. The option @option{--personal-aead-preferences} is
|
||||
@ -3313,7 +3310,7 @@ command has the same effect as using @option{--list-keys} with
|
||||
@option{--with-sig-list}. Note that in contrast to
|
||||
@option{--check-signatures} the key signatures are not verified. This
|
||||
command can be used to create a list of signing keys missing in the
|
||||
lcoal keyring; for example:
|
||||
local keyring; for example:
|
||||
|
||||
@example
|
||||
gpg --list-sigs --with-colons USERID | \
|
||||
|
@ -59,13 +59,14 @@ no configuration files and only a few options are implemented.
|
||||
That does also mean that it does not check for expired or revoked
|
||||
keys.
|
||||
|
||||
By default a keyring named @file{trustedkeys.kbx} is used; if that
|
||||
does not exist a keyring named @file{trustedkeys.gpg} is used. The
|
||||
default keyring is assumed to be in the home directory of GnuPG,
|
||||
either the default home directory or the one set by an option or an
|
||||
environment variable. The option @code{--keyring} may be used to
|
||||
specify a different keyring or even multiple keyrings.
|
||||
|
||||
If no @code{--keyring} option is given, @code{gpgv} looks for a
|
||||
``default'' keyring named @file{trustedkeys.kbx} (preferred) or
|
||||
@file{trustedkeys.gpg} in the home directory of GnuPG, either the
|
||||
default home directory or the one set by the @code{--homedir} option
|
||||
or the @code{GNUPGHOME} environment variable. If any @code{--keyring}
|
||||
option is used, @code{gpgv} will not look for the default keyring. The
|
||||
@code{--keyring} option may be used multiple times and all specified
|
||||
keyrings will be used together.
|
||||
|
||||
@noindent
|
||||
@mansect options
|
||||
|
@ -135,7 +135,7 @@ RFC-2253 encoded DN of the issuer. See note above.
|
||||
@item By keygrip.
|
||||
This is indicated by an ampersand followed by the 40 hex digits of a
|
||||
keygrip. @command{gpgsm} prints the keygrip when using the command
|
||||
@option{--dump-cert}. It does not yet work for OpenPGP keys.
|
||||
@option{--dump-cert}.
|
||||
|
||||
@cartouche
|
||||
@example
|
||||
@ -171,6 +171,3 @@ Using the RFC-2253 format of DNs has the drawback that it is not
|
||||
possible to map them back to the original encoding, however we don't
|
||||
have to do this because our key database stores this encoding as meta
|
||||
data.
|
||||
|
||||
|
||||
|
||||
|
@ -1561,7 +1561,7 @@ string @code{true} or @code{yes}. The evaluation is done by passing
|
||||
/subst
|
||||
/let i 3
|
||||
/while $i
|
||||
/echo loop couter is $i
|
||||
/echo loop counter is $i
|
||||
/let i $@{- $i 1@}
|
||||
/end
|
||||
@end smallexample
|
||||
@ -1962,7 +1962,7 @@ Extract all files from an encrypted archive.
|
||||
|
||||
@item --sign
|
||||
@itemx -s
|
||||
Make a signed archive from the given files and directories. Thsi can
|
||||
Make a signed archive from the given files and directories. This can
|
||||
be combined with option @option{--encrypt} to create a signed and then
|
||||
encrypted archive.
|
||||
|
||||
@ -2014,10 +2014,11 @@ Do not actually output the extracted files.
|
||||
@item --directory @var{dir}
|
||||
@itemx -C @var{dir}
|
||||
@opindex directory
|
||||
Extract the files into the directory @var{dir}. The
|
||||
default is to take the directory name from
|
||||
the input filename. If no input filename is known a directory named
|
||||
@file{GPGARCH} is used.
|
||||
Extract the files into the directory @var{dir}. The default is to
|
||||
take the directory name from the input filename. If no input filename
|
||||
is known a directory named @file{GPGARCH} is used. For tarball
|
||||
creation, switch to directory @var{dir} before performing any
|
||||
operations.
|
||||
|
||||
@item --files-from @var{file}
|
||||
@itemx -T @var{file}
|
||||
@ -2031,7 +2032,7 @@ linefeed to separate file names.
|
||||
|
||||
@item --openpgp
|
||||
@opindex openpgp
|
||||
This option has no effect becuase OpenPGP encryption and signing is
|
||||
This option has no effect because OpenPGP encryption and signing is
|
||||
the default.
|
||||
|
||||
@item --cms
|
||||
|
96
doc/wks.texi
96
doc/wks.texi
@ -61,11 +61,12 @@ Service provider. This is usuallay done to upload a key into a Web
|
||||
Key Directory.
|
||||
|
||||
With the @option{--supported} command the caller can test whether a
|
||||
site supports the Web Key Service. The argument is an arbitray
|
||||
site supports the Web Key Service. The argument is an arbitrary
|
||||
address in the to be tested domain. For example
|
||||
@file{foo@@example.net}. The command returns success if the Web Key
|
||||
Service is supported. The operation is silent; to get diagnostic
|
||||
output use the option @option{--verbose}.
|
||||
output use the option @option{--verbose}. See option
|
||||
@option{--with-colons} for a variant of this command.
|
||||
|
||||
With the @option{--check} command the caller can test whether a key
|
||||
exists for a supplied mail address. The command returns success if a
|
||||
@ -89,6 +90,17 @@ decrypted MIME message. The result of these commands are another mail
|
||||
which can be send in the same way as the mail created with
|
||||
@option{--create}.
|
||||
|
||||
The command @option{--install-key} manually installs a key into a
|
||||
local directory (see option @option{-C}) reflecting the structure of a
|
||||
WKD. The arguments are a file with the keyblock and the user-id to
|
||||
install. If the first argument resembles a fingerprint the key is
|
||||
taken from the current keyring; to force the use of a file, prefix the
|
||||
first argument with "./". If no arguments are given the parameters
|
||||
are read from stdin; the expected format are lines with the
|
||||
fingerprint and the mailbox separated by a space. The command
|
||||
@option{--remove-key} removes a key from that directory, its only
|
||||
argument is a user-id.
|
||||
|
||||
@command{gpg-wks-client} is not commonly invoked directly and thus it
|
||||
is not installed in the bin directory. Here is an example how it can
|
||||
be invoked manually to check for a Web Key Directory entry for
|
||||
@ -109,6 +121,44 @@ $(gpgconf --list-dirs libexecdir)/gpg-wks-client --check foo@@example.net
|
||||
Directly send created mails using the @command{sendmail} command.
|
||||
Requires installation of that command.
|
||||
|
||||
@item --with-colons
|
||||
@opindex with-colons
|
||||
This option has currently only an effect on the @option{--supported}
|
||||
command. If it is used all arguments on the command line are taken
|
||||
as domain names and tested for WKD support. The output format is one
|
||||
line per domain with colon delimited fields. The currently specified
|
||||
fields are (future versions may specify additional fields):
|
||||
|
||||
@table @asis
|
||||
|
||||
@item 1 - domain
|
||||
This is the domain name. Although quoting is not required for valid
|
||||
domain names this field is specified to be quoted in standard C
|
||||
manner.
|
||||
|
||||
@item 2 - WKD
|
||||
If the value is true the domain supports the Web Key Directory.
|
||||
|
||||
@item 3 - WKS
|
||||
If the value is true the domain supports the Web Key Service
|
||||
protocol to upload keys to the directory.
|
||||
|
||||
@item 4 - error-code
|
||||
This may contain an gpg-error code to describe certain
|
||||
failures. Use @samp{gpg-error CODE} to explain the code.
|
||||
|
||||
@item 5 - protocol-version
|
||||
The minimum protocol version supported by the server.
|
||||
|
||||
@item 6 - auth-submit
|
||||
The auth-submit flag from the policy file of the server.
|
||||
|
||||
@item 7 - mailbox-only
|
||||
The mailbox-only flag from the policy file of the server.
|
||||
@end table
|
||||
|
||||
|
||||
|
||||
@item --output @var{file}
|
||||
@itemx -o
|
||||
@opindex output
|
||||
@ -122,6 +172,13 @@ This program returns only the status messages SUCCESS or FAILURE which
|
||||
are helpful when the caller uses a double fork approach and can't
|
||||
easily get the return code of the process.
|
||||
|
||||
@item -C @var{dir}
|
||||
@itemx --directory @var{dir}
|
||||
@opindex directory
|
||||
Use @var{dir} as top level directory for the commands
|
||||
@option{--install-key} and @option{--remove-key}. The default is
|
||||
@file{openpgpkey}.
|
||||
|
||||
@item --verbose
|
||||
@opindex verbose
|
||||
Enable extra informational output.
|
||||
@ -206,7 +263,7 @@ mail is processed. Commonly this command is used with the option
|
||||
@option{--send} to directly send the crerated mails back. See below
|
||||
for an installation example.
|
||||
|
||||
The command @option{--cron} is used for regualr cleanup tasks. For
|
||||
The command @option{--cron} is used for regular cleanup tasks. For
|
||||
example non-confirmed requested should be removed after their expire
|
||||
time. It is best to run this command once a day from a cronjob.
|
||||
|
||||
@ -215,9 +272,9 @@ Further it creates missing directories for the configuration and
|
||||
prints warnings pertaining to problems in the configuration.
|
||||
|
||||
The command @option{--check-key} (or just @option{--check}) checks
|
||||
whether a key with the given user-id is installed. The process return
|
||||
success in this case; to also print a diagnostic, use option
|
||||
@option{-v}. If the key is not installed a diagnostics is printed and
|
||||
whether a key with the given user-id is installed. The process returns
|
||||
success in this case; to also print a diagnostic use the option
|
||||
@option{-v}. If the key is not installed a diagnostic is printed and
|
||||
the process returns failure; to suppress the diagnostic, use option
|
||||
@option{-q}. More than one user-id can be given; see also option
|
||||
@option{with-file}.
|
||||
@ -226,7 +283,9 @@ The command @option{--install-key} manually installs a key into the
|
||||
WKD. The arguments are a file with the keyblock and the user-id to
|
||||
install. If the first argument resembles a fingerprint the key is
|
||||
taken from the current keyring; to force the use of a file, prefix the
|
||||
first argument with "./".
|
||||
first argument with "./". If no arguments are given the parameters
|
||||
are read from stdin; the expected format are lines with the
|
||||
fingerprint and the mailbox separated by a space.
|
||||
|
||||
The command @option{--remove-key} uninstalls a key from the WKD. The
|
||||
process returns success in this case; to also print a diagnostic, use
|
||||
@ -243,6 +302,12 @@ The command @option{--revoke-key} is not yet functional.
|
||||
|
||||
@table @gnupgtabopt
|
||||
|
||||
@item -C @var{dir}
|
||||
@itemx --directory @var{dir}
|
||||
@opindex directory
|
||||
Use @var{dir} as top level directory for domains. The default is
|
||||
@file{/var/lib/gnupg/wks}.
|
||||
|
||||
@item --from @var{mailaddr}
|
||||
@opindex from
|
||||
Use @var{mailaddr} as the default sender address.
|
||||
@ -256,21 +321,22 @@ Add the mail header "@var{name}: @var{value}" to all outgoing mails.
|
||||
Directly send created mails using the @command{sendmail} command.
|
||||
Requires installation of that command.
|
||||
|
||||
@item --output @var{file}
|
||||
@itemx -o
|
||||
@item -o @var{file}
|
||||
@itemx --output @var{file}
|
||||
@opindex output
|
||||
Write the created mail also to @var{file}. Note that the value
|
||||
@code{-} for @var{file} would write it to stdout.
|
||||
|
||||
@item --with-dir
|
||||
@opindex with-dir
|
||||
Also print the directory name for each domain listed by command
|
||||
@option{--list-domains}.
|
||||
When used with the command @option{--list-domains} print for each
|
||||
installed domain the domain name and its directory name.
|
||||
|
||||
@item --with-file
|
||||
@opindex with-file
|
||||
With command @option{--check-key} print for each user-id, the address,
|
||||
'i' for installed key or 'n' for not installed key, and the filename.
|
||||
When used with the command @option{--check-key} print for each user-id,
|
||||
the address, 'i' for installed key or 'n' for not installed key, and
|
||||
the filename.
|
||||
|
||||
@item --verbose
|
||||
@opindex verbose
|
||||
@ -316,7 +382,7 @@ Finally run
|
||||
$ gpg-wks-server --list-domains
|
||||
@end example
|
||||
|
||||
to create the required sub-directories with the permission set
|
||||
to create the required sub-directories with the permissions set
|
||||
correctly. For each domain a submission address needs to be
|
||||
configured. All service mails are directed to that address. It can
|
||||
be the same address for all configured domains, for example:
|
||||
@ -326,7 +392,7 @@ be the same address for all configured domains, for example:
|
||||
$ echo key-submission@@example.net >submission-address
|
||||
@end example
|
||||
|
||||
The protocol requires that the key to be published is sent with an
|
||||
The protocol requires that the key to be published is send with an
|
||||
encrypted mail to the service. Thus you need to create a key for
|
||||
the submission address:
|
||||
|
||||
|
@ -55,7 +55,7 @@
|
||||
.B whateever you want
|
||||
@end ifset
|
||||
|
||||
alternativly a special comment may be used:
|
||||
alternatively a special comment may be used:
|
||||
|
||||
@c man:.B whatever you want
|
||||
|
||||
@ -704,7 +704,7 @@ write_th (FILE *fp)
|
||||
|
||||
|
||||
/* Process the texinfo command COMMAND (without the leading @) and
|
||||
write output if needed to FP. REST is the remainer of the line
|
||||
write output if needed to FP. REST is the remainder of the line
|
||||
which should either point to an opening brace or to a white space.
|
||||
The function returns the number of characters already processed
|
||||
from REST. LEN is the usable length of REST. TABLE_LEVEL is used to
|
||||
@ -1197,7 +1197,7 @@ parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
|
||||
if (*p == '@' && !strncmp (p+1, "item", 4))
|
||||
item_indent = p - line; /* Set a new indent level. */
|
||||
else if (p - line < item_indent)
|
||||
item_indent = 0; /* Switch off indention. */
|
||||
item_indent = 0; /* Switch off indentation. */
|
||||
|
||||
if (item_indent)
|
||||
{
|
||||
|
629
g10/armor.c
629
g10/armor.c
@ -1,4 +1,4 @@
|
||||
/* armor.c - Armor flter
|
||||
/* armor.c - Armor filter
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||||
* 2007 Free Software Foundation, Inc.
|
||||
*
|
||||
@ -37,17 +37,10 @@
|
||||
|
||||
#define MAX_LINELEN 20000
|
||||
|
||||
#define CRCINIT 0xB704CE
|
||||
#define CRCPOLY 0X864CFB
|
||||
#define CRCUPDATE(a,c) do { \
|
||||
a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \
|
||||
a &= 0x00ffffff; \
|
||||
} while(0)
|
||||
static u32 crc_table[256];
|
||||
static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
static const byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
static byte asctobin[256]; /* runtime initialized */
|
||||
static u32 asctobin[4][256]; /* runtime initialized */
|
||||
static int is_initialized;
|
||||
|
||||
|
||||
@ -121,9 +114,22 @@ armor_filter_context_t *
|
||||
new_armor_context (void)
|
||||
{
|
||||
armor_filter_context_t *afx;
|
||||
gpg_error_t err;
|
||||
|
||||
afx = xcalloc (1, sizeof *afx);
|
||||
if (afx)
|
||||
{
|
||||
err = gcry_md_open (&afx->crc_md, GCRY_MD_CRC24_RFC2440, 0);
|
||||
if (err != 0)
|
||||
{
|
||||
log_error ("gcry_md_open failed for GCRY_MD_CRC24_RFC2440: %s",
|
||||
gpg_strerror (err));
|
||||
xfree (afx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
afx->refcount = 1;
|
||||
}
|
||||
|
||||
return afx;
|
||||
}
|
||||
@ -138,6 +144,7 @@ release_armor_context (armor_filter_context_t *afx)
|
||||
log_assert (afx->refcount);
|
||||
if ( --afx->refcount )
|
||||
return;
|
||||
gcry_md_close (afx->crc_md);
|
||||
xfree (afx);
|
||||
}
|
||||
|
||||
@ -161,35 +168,42 @@ push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf)
|
||||
static void
|
||||
initialize(void)
|
||||
{
|
||||
int i, j;
|
||||
u32 t;
|
||||
byte *s;
|
||||
u32 i;
|
||||
const byte *s;
|
||||
|
||||
/* init the crc lookup table */
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* build the helptable for radix64 to bin conversion */
|
||||
for(i=0; i < 256; i++ )
|
||||
asctobin[i] = 255; /* used to detect invalid characters */
|
||||
/* Build the helptable for radix64 to bin conversion. Value 0xffffffff is
|
||||
used to detect invalid characters. */
|
||||
memset (asctobin, 0xff, sizeof(asctobin));
|
||||
for(s=bintoasc,i=0; *s; s++,i++ )
|
||||
asctobin[*s] = i;
|
||||
{
|
||||
asctobin[0][*s] = i << (0 * 6);
|
||||
asctobin[1][*s] = i << (1 * 6);
|
||||
asctobin[2][*s] = i << (2 * 6);
|
||||
asctobin[3][*s] = i << (3 * 6);
|
||||
}
|
||||
|
||||
is_initialized=1;
|
||||
}
|
||||
|
||||
|
||||
static inline u32
|
||||
get_afx_crc (armor_filter_context_t *afx)
|
||||
{
|
||||
const byte *crc_buf;
|
||||
u32 crc;
|
||||
|
||||
crc_buf = gcry_md_read (afx->crc_md, GCRY_MD_CRC24_RFC2440);
|
||||
|
||||
crc = crc_buf[0];
|
||||
crc <<= 8;
|
||||
crc |= crc_buf[1];
|
||||
crc <<= 8;
|
||||
crc |= crc_buf[2];
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check whether this is an armored file. See also
|
||||
* parse-packet.c for details on this code.
|
||||
@ -592,7 +606,7 @@ check_input( armor_filter_context_t *afx, IOBUF a )
|
||||
afx->faked = 1;
|
||||
else {
|
||||
afx->inp_checked = 1;
|
||||
afx->crc = CRCINIT;
|
||||
gcry_md_reset (afx->crc_md);
|
||||
afx->idx = 0;
|
||||
afx->radbuf[0] = 0;
|
||||
}
|
||||
@ -768,7 +782,7 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
|
||||
}
|
||||
}
|
||||
afx->inp_checked = 1;
|
||||
afx->crc = CRCINIT;
|
||||
gcry_md_reset (afx->crc_md);
|
||||
afx->idx = 0;
|
||||
afx->radbuf[0] = 0;
|
||||
}
|
||||
@ -793,14 +807,14 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
|
||||
byte *buf, size_t size )
|
||||
{
|
||||
byte val;
|
||||
int c=0, c2; /*init c because gcc is not clever enough for the continue*/
|
||||
int c;
|
||||
u32 binc;
|
||||
int checkcrc=0;
|
||||
int rc = 0;
|
||||
size_t n = 0;
|
||||
int idx, i, onlypad=0;
|
||||
u32 crc;
|
||||
int idx, onlypad=0;
|
||||
int skip_fast = 0;
|
||||
|
||||
crc = afx->crc;
|
||||
idx = afx->idx;
|
||||
val = afx->radbuf[0];
|
||||
for( n=0; n < size; ) {
|
||||
@ -820,6 +834,122 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
|
||||
}
|
||||
|
||||
again:
|
||||
binc = asctobin[0][c];
|
||||
|
||||
if( binc != 0xffffffffUL )
|
||||
{
|
||||
if( idx == 0 && skip_fast == 0
|
||||
&& afx->buffer_pos + (16 - 1) < afx->buffer_len
|
||||
&& n + 12 < size)
|
||||
{
|
||||
/* Fast path for radix64 to binary conversion. */
|
||||
u32 b0,b1,b2,b3;
|
||||
|
||||
/* Speculatively load 15 more input bytes. */
|
||||
b0 = binc << (3 * 6);
|
||||
b0 |= asctobin[2][afx->buffer[afx->buffer_pos + 0]];
|
||||
b0 |= asctobin[1][afx->buffer[afx->buffer_pos + 1]];
|
||||
b0 |= asctobin[0][afx->buffer[afx->buffer_pos + 2]];
|
||||
b1 = asctobin[3][afx->buffer[afx->buffer_pos + 3]];
|
||||
b1 |= asctobin[2][afx->buffer[afx->buffer_pos + 4]];
|
||||
b1 |= asctobin[1][afx->buffer[afx->buffer_pos + 5]];
|
||||
b1 |= asctobin[0][afx->buffer[afx->buffer_pos + 6]];
|
||||
b2 = asctobin[3][afx->buffer[afx->buffer_pos + 7]];
|
||||
b2 |= asctobin[2][afx->buffer[afx->buffer_pos + 8]];
|
||||
b2 |= asctobin[1][afx->buffer[afx->buffer_pos + 9]];
|
||||
b2 |= asctobin[0][afx->buffer[afx->buffer_pos + 10]];
|
||||
b3 = asctobin[3][afx->buffer[afx->buffer_pos + 11]];
|
||||
b3 |= asctobin[2][afx->buffer[afx->buffer_pos + 12]];
|
||||
b3 |= asctobin[1][afx->buffer[afx->buffer_pos + 13]];
|
||||
b3 |= asctobin[0][afx->buffer[afx->buffer_pos + 14]];
|
||||
|
||||
/* Check if any of the input bytes were invalid. */
|
||||
if( (b0 | b1 | b2 | b3) != 0xffffffffUL )
|
||||
{
|
||||
/* All 16 bytes are valid. */
|
||||
buf[n + 0] = b0 >> (2 * 8);
|
||||
buf[n + 1] = b0 >> (1 * 8);
|
||||
buf[n + 2] = b0 >> (0 * 8);
|
||||
buf[n + 3] = b1 >> (2 * 8);
|
||||
buf[n + 4] = b1 >> (1 * 8);
|
||||
buf[n + 5] = b1 >> (0 * 8);
|
||||
buf[n + 6] = b2 >> (2 * 8);
|
||||
buf[n + 7] = b2 >> (1 * 8);
|
||||
buf[n + 8] = b2 >> (0 * 8);
|
||||
buf[n + 9] = b3 >> (2 * 8);
|
||||
buf[n + 10] = b3 >> (1 * 8);
|
||||
buf[n + 11] = b3 >> (0 * 8);
|
||||
afx->buffer_pos += 16 - 1;
|
||||
n += 12;
|
||||
continue;
|
||||
}
|
||||
else if( b0 == 0xffffffffUL )
|
||||
{
|
||||
/* byte[1..3] have invalid character(s). Switch to slow
|
||||
path. */
|
||||
skip_fast = 1;
|
||||
}
|
||||
else if( b1 == 0xffffffffUL )
|
||||
{
|
||||
/* byte[4..7] have invalid character(s), first 4 bytes are
|
||||
valid. */
|
||||
buf[n + 0] = b0 >> (2 * 8);
|
||||
buf[n + 1] = b0 >> (1 * 8);
|
||||
buf[n + 2] = b0 >> (0 * 8);
|
||||
afx->buffer_pos += 4 - 1;
|
||||
n += 3;
|
||||
skip_fast = 1;
|
||||
continue;
|
||||
}
|
||||
else if( b2 == 0xffffffffUL )
|
||||
{
|
||||
/* byte[8..11] have invalid character(s), first 8 bytes are
|
||||
valid. */
|
||||
buf[n + 0] = b0 >> (2 * 8);
|
||||
buf[n + 1] = b0 >> (1 * 8);
|
||||
buf[n + 2] = b0 >> (0 * 8);
|
||||
buf[n + 3] = b1 >> (2 * 8);
|
||||
buf[n + 4] = b1 >> (1 * 8);
|
||||
buf[n + 5] = b1 >> (0 * 8);
|
||||
afx->buffer_pos += 8 - 1;
|
||||
n += 6;
|
||||
skip_fast = 1;
|
||||
continue;
|
||||
}
|
||||
else /*if( b3 == 0xffffffffUL )*/
|
||||
{
|
||||
/* byte[12..15] have invalid character(s), first 12 bytes
|
||||
are valid. */
|
||||
buf[n + 0] = b0 >> (2 * 8);
|
||||
buf[n + 1] = b0 >> (1 * 8);
|
||||
buf[n + 2] = b0 >> (0 * 8);
|
||||
buf[n + 3] = b1 >> (2 * 8);
|
||||
buf[n + 4] = b1 >> (1 * 8);
|
||||
buf[n + 5] = b1 >> (0 * 8);
|
||||
buf[n + 6] = b2 >> (2 * 8);
|
||||
buf[n + 7] = b2 >> (1 * 8);
|
||||
buf[n + 8] = b2 >> (0 * 8);
|
||||
afx->buffer_pos += 12 - 1;
|
||||
n += 9;
|
||||
skip_fast = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch(idx)
|
||||
{
|
||||
case 0: val = binc << 2; break;
|
||||
case 1: val |= (binc>>4)&3; buf[n++]=val;val=(binc<<4)&0xf0;break;
|
||||
case 2: val |= (binc>>2)&15; buf[n++]=val;val=(binc<<6)&0xc0;break;
|
||||
case 3: val |= binc&0x3f; buf[n++] = val; break;
|
||||
}
|
||||
idx = (idx+1) % 4;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
skip_fast = 0;
|
||||
|
||||
if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
|
||||
continue;
|
||||
else if( c == '=' ) { /* pad character: stop */
|
||||
@ -850,10 +980,10 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
|
||||
if (afx->buffer_pos + 6 < afx->buffer_len
|
||||
&& afx->buffer[afx->buffer_pos + 0] == '3'
|
||||
&& afx->buffer[afx->buffer_pos + 1] == 'D'
|
||||
&& asctobin[afx->buffer[afx->buffer_pos + 2]] != 255
|
||||
&& asctobin[afx->buffer[afx->buffer_pos + 3]] != 255
|
||||
&& asctobin[afx->buffer[afx->buffer_pos + 4]] != 255
|
||||
&& asctobin[afx->buffer[afx->buffer_pos + 5]] != 255
|
||||
&& asctobin[0][afx->buffer[afx->buffer_pos + 2]] != 0xffffffffUL
|
||||
&& asctobin[0][afx->buffer[afx->buffer_pos + 3]] != 0xffffffffUL
|
||||
&& asctobin[0][afx->buffer[afx->buffer_pos + 4]] != 0xffffffffUL
|
||||
&& asctobin[0][afx->buffer[afx->buffer_pos + 5]] != 0xffffffffUL
|
||||
&& afx->buffer[afx->buffer_pos + 6] == '\n')
|
||||
{
|
||||
afx->buffer_pos += 2;
|
||||
@ -868,27 +998,20 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
|
||||
checkcrc++;
|
||||
break;
|
||||
}
|
||||
else if( (c = asctobin[(c2=c)]) == 255 ) {
|
||||
log_error(_("invalid radix64 character %02X skipped\n"), c2);
|
||||
else {
|
||||
log_error(_("invalid radix64 character %02X skipped\n"), c);
|
||||
continue;
|
||||
}
|
||||
switch(idx) {
|
||||
case 0: val = c << 2; break;
|
||||
case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break;
|
||||
case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break;
|
||||
case 3: val |= c&0x3f; buf[n++] = val; break;
|
||||
}
|
||||
idx = (idx+1) % 4;
|
||||
}
|
||||
|
||||
for(i=0; i < n; i++ )
|
||||
crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
|
||||
crc &= 0x00ffffff;
|
||||
afx->crc = crc;
|
||||
afx->idx = idx;
|
||||
afx->radbuf[0] = val;
|
||||
|
||||
if( n )
|
||||
gcry_md_write (afx->crc_md, buf, n);
|
||||
|
||||
if( checkcrc ) {
|
||||
gcry_md_final (afx->crc_md);
|
||||
afx->any_data = 1;
|
||||
afx->inp_checked=0;
|
||||
afx->faked = 0;
|
||||
@ -911,19 +1034,19 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if( c == -1 )
|
||||
if( !afx->buffer_len )
|
||||
log_error(_("premature eof (no CRC)\n"));
|
||||
else {
|
||||
u32 mycrc = 0;
|
||||
idx = 0;
|
||||
do {
|
||||
if( (c = asctobin[c]) == 255 )
|
||||
if( (binc = asctobin[0][c]) == 0xffffffffUL )
|
||||
break;
|
||||
switch(idx) {
|
||||
case 0: val = c << 2; break;
|
||||
case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break;
|
||||
case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break;
|
||||
case 3: val |= c&0x3f; mycrc |= val; break;
|
||||
case 0: val = binc << 2; break;
|
||||
case 1: val |= (binc>>4)&3; mycrc |= val << 16;val=(binc<<4)&0xf0;break;
|
||||
case 2: val |= (binc>>2)&15; mycrc |= val << 8;val=(binc<<6)&0xc0;break;
|
||||
case 3: val |= binc&0x3f; mycrc |= val; break;
|
||||
}
|
||||
for(;;) {
|
||||
if( afx->buffer_pos < afx->buffer_len )
|
||||
@ -945,7 +1068,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
|
||||
if( !afx->buffer_len )
|
||||
break; /* eof */
|
||||
} while( ++idx < 4 );
|
||||
if( c == -1 ) {
|
||||
if( !afx->buffer_len ) {
|
||||
log_info(_("premature eof (in CRC)\n"));
|
||||
rc = invalid_crc();
|
||||
}
|
||||
@ -957,9 +1080,9 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
|
||||
log_info(_("malformed CRC\n"));
|
||||
rc = invalid_crc();
|
||||
}
|
||||
else if( mycrc != afx->crc ) {
|
||||
else if( mycrc != get_afx_crc (afx) ) {
|
||||
log_info (_("CRC error; %06lX - %06lX\n"),
|
||||
(ulong)afx->crc, (ulong)mycrc);
|
||||
(ulong)get_afx_crc (afx), (ulong)mycrc);
|
||||
rc = invalid_crc();
|
||||
}
|
||||
else {
|
||||
@ -997,6 +1120,121 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
armor_output_buf_as_radix64 (armor_filter_context_t *afx, IOBUF a,
|
||||
byte *buf, size_t size)
|
||||
{
|
||||
byte radbuf[sizeof (afx->radbuf)];
|
||||
byte outbuf[64 + sizeof (afx->eol)];
|
||||
unsigned int eollen = strlen (afx->eol);
|
||||
u32 in, in2;
|
||||
int idx, idx2;
|
||||
int i;
|
||||
|
||||
idx = afx->idx;
|
||||
idx2 = afx->idx2;
|
||||
memcpy (radbuf, afx->radbuf, sizeof (afx->radbuf));
|
||||
|
||||
if (size && (idx || idx2))
|
||||
{
|
||||
/* preload eol to outbuf buffer */
|
||||
memcpy (outbuf + 4, afx->eol, sizeof (afx->eol));
|
||||
|
||||
for (; size && (idx || idx2); buf++, size--)
|
||||
{
|
||||
radbuf[idx++] = *buf;
|
||||
if (idx > 2)
|
||||
{
|
||||
idx = 0;
|
||||
in = (u32)radbuf[0] << (2 * 8);
|
||||
in |= (u32)radbuf[1] << (1 * 8);
|
||||
in |= (u32)radbuf[2] << (0 * 8);
|
||||
outbuf[0] = bintoasc[(in >> 18) & 077];
|
||||
outbuf[1] = bintoasc[(in >> 12) & 077];
|
||||
outbuf[2] = bintoasc[(in >> 6) & 077];
|
||||
outbuf[3] = bintoasc[(in >> 0) & 077];
|
||||
if (++idx2 >= (64/4))
|
||||
{ /* pgp doesn't like 72 here */
|
||||
idx2=0;
|
||||
iobuf_write (a, outbuf, 4 + eollen);
|
||||
}
|
||||
else
|
||||
{
|
||||
iobuf_write (a, outbuf, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (size >= (64/4)*3)
|
||||
{
|
||||
/* preload eol to outbuf buffer */
|
||||
memcpy (outbuf + 64, afx->eol, sizeof(afx->eol));
|
||||
|
||||
do
|
||||
{
|
||||
/* idx and idx2 == 0 */
|
||||
|
||||
for (i = 0; i < (64/8); i++)
|
||||
{
|
||||
in = (u32)buf[0] << (2 * 8);
|
||||
in |= (u32)buf[1] << (1 * 8);
|
||||
in |= (u32)buf[2] << (0 * 8);
|
||||
in2 = (u32)buf[3] << (2 * 8);
|
||||
in2 |= (u32)buf[4] << (1 * 8);
|
||||
in2 |= (u32)buf[5] << (0 * 8);
|
||||
outbuf[i*8+0] = bintoasc[(in >> 18) & 077];
|
||||
outbuf[i*8+1] = bintoasc[(in >> 12) & 077];
|
||||
outbuf[i*8+2] = bintoasc[(in >> 6) & 077];
|
||||
outbuf[i*8+3] = bintoasc[(in >> 0) & 077];
|
||||
outbuf[i*8+4] = bintoasc[(in2 >> 18) & 077];
|
||||
outbuf[i*8+5] = bintoasc[(in2 >> 12) & 077];
|
||||
outbuf[i*8+6] = bintoasc[(in2 >> 6) & 077];
|
||||
outbuf[i*8+7] = bintoasc[(in2 >> 0) & 077];
|
||||
buf+=6;
|
||||
size-=6;
|
||||
}
|
||||
|
||||
/* pgp doesn't like 72 here */
|
||||
iobuf_write (a, outbuf, 64 + eollen);
|
||||
}
|
||||
while (size >= (64/4)*3);
|
||||
|
||||
/* restore eol for tail handling */
|
||||
if (size)
|
||||
memcpy (outbuf + 4, afx->eol, sizeof (afx->eol));
|
||||
}
|
||||
|
||||
for (; size; buf++, size--)
|
||||
{
|
||||
radbuf[idx++] = *buf;
|
||||
if (idx > 2)
|
||||
{
|
||||
idx = 0;
|
||||
in = (u32)radbuf[0] << (2 * 8);
|
||||
in |= (u32)radbuf[1] << (1 * 8);
|
||||
in |= (u32)radbuf[2] << (0 * 8);
|
||||
outbuf[0] = bintoasc[(in >> 18) & 077];
|
||||
outbuf[1] = bintoasc[(in >> 12) & 077];
|
||||
outbuf[2] = bintoasc[(in >> 6) & 077];
|
||||
outbuf[3] = bintoasc[(in >> 0) & 077];
|
||||
if (++idx2 >= (64/4))
|
||||
{ /* pgp doesn't like 72 here */
|
||||
idx2=0;
|
||||
iobuf_write (a, outbuf, 4 + eollen);
|
||||
}
|
||||
else
|
||||
{
|
||||
iobuf_write (a, outbuf, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (afx->radbuf, radbuf, sizeof (afx->radbuf));
|
||||
afx->idx = idx;
|
||||
afx->idx2 = idx2;
|
||||
}
|
||||
|
||||
/****************
|
||||
* This filter is used to handle the armor stuff
|
||||
*/
|
||||
@ -1006,7 +1244,7 @@ armor_filter( void *opaque, int control,
|
||||
{
|
||||
size_t size = *ret_len;
|
||||
armor_filter_context_t *afx = opaque;
|
||||
int rc=0, i, c;
|
||||
int rc=0, c;
|
||||
byte radbuf[3];
|
||||
int idx, idx2;
|
||||
size_t n=0;
|
||||
@ -1188,43 +1426,13 @@ armor_filter( void *opaque, int control,
|
||||
afx->status++;
|
||||
afx->idx = 0;
|
||||
afx->idx2 = 0;
|
||||
afx->crc = CRCINIT;
|
||||
gcry_md_reset (afx->crc_md);
|
||||
}
|
||||
|
||||
if( size ) {
|
||||
gcry_md_write (afx->crc_md, buf, size);
|
||||
armor_output_buf_as_radix64 (afx, a, buf, size);
|
||||
}
|
||||
crc = afx->crc;
|
||||
idx = afx->idx;
|
||||
idx2 = afx->idx2;
|
||||
for(i=0; i < idx; i++ )
|
||||
radbuf[i] = afx->radbuf[i];
|
||||
|
||||
for(i=0; i < size; i++ )
|
||||
crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
|
||||
crc &= 0x00ffffff;
|
||||
|
||||
for( ; size; buf++, size-- ) {
|
||||
radbuf[idx++] = *buf;
|
||||
if( idx > 2 ) {
|
||||
idx = 0;
|
||||
c = bintoasc[(*radbuf >> 2) & 077];
|
||||
iobuf_put(a, c);
|
||||
c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
|
||||
iobuf_put(a, c);
|
||||
c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
|
||||
iobuf_put(a, c);
|
||||
c = bintoasc[radbuf[2]&077];
|
||||
iobuf_put(a, c);
|
||||
if( ++idx2 >= (64/4) )
|
||||
{ /* pgp doesn't like 72 here */
|
||||
iobuf_writestr(a,afx->eol);
|
||||
idx2=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i=0; i < idx; i++ )
|
||||
afx->radbuf[i] = radbuf[i];
|
||||
afx->idx = idx;
|
||||
afx->idx2 = idx2;
|
||||
afx->crc = crc;
|
||||
}
|
||||
else if( control == IOBUFCTRL_INIT )
|
||||
{
|
||||
@ -1250,7 +1458,8 @@ armor_filter( void *opaque, int control,
|
||||
if( afx->cancel )
|
||||
;
|
||||
else if( afx->status ) { /* pad, write cecksum, and bottom line */
|
||||
crc = afx->crc;
|
||||
gcry_md_final (afx->crc_md);
|
||||
crc = get_afx_crc (afx);
|
||||
idx = afx->idx;
|
||||
idx2 = afx->idx2;
|
||||
if( idx ) {
|
||||
@ -1350,221 +1559,3 @@ make_radix64_string( const byte *data, size_t len )
|
||||
*p = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************
|
||||
* For the pipemode command we can't use the armor filter for various
|
||||
* reasons, so we use this new unarmor_pump stuff to remove the armor
|
||||
*/
|
||||
|
||||
enum unarmor_state_e {
|
||||
STA_init = 0,
|
||||
STA_bypass,
|
||||
STA_wait_newline,
|
||||
STA_wait_dash,
|
||||
STA_first_dash,
|
||||
STA_compare_header,
|
||||
STA_found_header_wait_newline,
|
||||
STA_skip_header_lines,
|
||||
STA_skip_header_lines_non_ws,
|
||||
STA_read_data,
|
||||
STA_wait_crc,
|
||||
STA_read_crc,
|
||||
STA_ready
|
||||
};
|
||||
|
||||
struct unarmor_pump_s {
|
||||
enum unarmor_state_e state;
|
||||
byte val;
|
||||
int checkcrc;
|
||||
int pos; /* counts from 0..3 */
|
||||
u32 crc;
|
||||
u32 mycrc; /* the one store in the data */
|
||||
};
|
||||
|
||||
|
||||
|
||||
UnarmorPump
|
||||
unarmor_pump_new (void)
|
||||
{
|
||||
UnarmorPump x;
|
||||
|
||||
if( !is_initialized )
|
||||
initialize();
|
||||
x = xmalloc_clear (sizeof *x);
|
||||
return x;
|
||||
}
|
||||
|
||||
void
|
||||
unarmor_pump_release (UnarmorPump x)
|
||||
{
|
||||
xfree (x);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next character from the ascii armor taken from the IOBUF
|
||||
* created earlier by unarmor_pump_new().
|
||||
* Return: c = Character
|
||||
* 256 = ignore this value
|
||||
* -1 = End of current armor
|
||||
* -2 = Premature EOF (not used)
|
||||
* -3 = Invalid armor
|
||||
*/
|
||||
int
|
||||
unarmor_pump (UnarmorPump x, int c)
|
||||
{
|
||||
int rval = 256; /* default is to ignore the return value */
|
||||
|
||||
switch (x->state) {
|
||||
case STA_init:
|
||||
{
|
||||
byte tmp[2];
|
||||
tmp[0] = c;
|
||||
tmp[1] = 0;
|
||||
if ( is_armored (tmp) )
|
||||
x->state = c == '-'? STA_first_dash : STA_wait_newline;
|
||||
else {
|
||||
x->state = STA_bypass;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STA_bypass:
|
||||
return c; /* return here to avoid crc calculation */
|
||||
case STA_wait_newline:
|
||||
if (c == '\n')
|
||||
x->state = STA_wait_dash;
|
||||
break;
|
||||
case STA_wait_dash:
|
||||
x->state = c == '-'? STA_first_dash : STA_wait_newline;
|
||||
break;
|
||||
case STA_first_dash: /* just need for initialization */
|
||||
x->pos = 0;
|
||||
x->state = STA_compare_header; /* fall through */
|
||||
case STA_compare_header:
|
||||
if ( "-----BEGIN PGP SIGNATURE-----"[++x->pos] == c ) {
|
||||
if ( x->pos == 28 )
|
||||
x->state = STA_found_header_wait_newline;
|
||||
}
|
||||
else
|
||||
x->state = c == '\n'? STA_wait_dash : STA_wait_newline;
|
||||
break;
|
||||
case STA_found_header_wait_newline:
|
||||
/* to make CR,LF issues easier we simply allow for white space
|
||||
behind the 5 dashes */
|
||||
if ( c == '\n' )
|
||||
x->state = STA_skip_header_lines;
|
||||
else if ( c != '\r' && c != ' ' && c != '\t' )
|
||||
x->state = STA_wait_dash; /* garbage after the header line */
|
||||
break;
|
||||
case STA_skip_header_lines:
|
||||
/* i.e. wait for one empty line */
|
||||
if ( c == '\n' ) {
|
||||
x->state = STA_read_data;
|
||||
x->crc = CRCINIT;
|
||||
x->val = 0;
|
||||
x->pos = 0;
|
||||
}
|
||||
else if ( c != '\r' && c != ' ' && c != '\t' )
|
||||
x->state = STA_skip_header_lines_non_ws;
|
||||
break;
|
||||
case STA_skip_header_lines_non_ws:
|
||||
/* like above but we already encountered non white space */
|
||||
if ( c == '\n' )
|
||||
x->state = STA_skip_header_lines;
|
||||
break;
|
||||
case STA_read_data:
|
||||
/* fixme: we don't check for the trailing dash lines but rely
|
||||
* on the armor stop characters */
|
||||
if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
|
||||
break; /* skip all kind of white space */
|
||||
|
||||
if( c == '=' ) { /* pad character: stop */
|
||||
if( x->pos == 1 ) /* in this case val has some value */
|
||||
rval = x->val;
|
||||
x->state = STA_wait_crc;
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
int c2;
|
||||
if( (c = asctobin[(c2=c)]) == 255 ) {
|
||||
log_error(_("invalid radix64 character %02X skipped\n"), c2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(x->pos) {
|
||||
case 0:
|
||||
x->val = c << 2;
|
||||
break;
|
||||
case 1:
|
||||
x->val |= (c>>4)&3;
|
||||
rval = x->val;
|
||||
x->val = (c<<4)&0xf0;
|
||||
break;
|
||||
case 2:
|
||||
x->val |= (c>>2)&15;
|
||||
rval = x->val;
|
||||
x->val = (c<<6)&0xc0;
|
||||
break;
|
||||
case 3:
|
||||
x->val |= c&0x3f;
|
||||
rval = x->val;
|
||||
break;
|
||||
}
|
||||
x->pos = (x->pos+1) % 4;
|
||||
break;
|
||||
case STA_wait_crc:
|
||||
if( c == '\n' || c == ' ' || c == '\r' || c == '\t' || c == '=' )
|
||||
break; /* skip ws and pad characters */
|
||||
/* assume that we are at the next line */
|
||||
x->state = STA_read_crc;
|
||||
x->pos = 0;
|
||||
x->mycrc = 0; /* fall through */
|
||||
case STA_read_crc:
|
||||
if( (c = asctobin[c]) == 255 ) {
|
||||
rval = -1; /* ready */
|
||||
if( x->crc != x->mycrc ) {
|
||||
log_info (_("CRC error; %06lX - %06lX\n"),
|
||||
(ulong)x->crc, (ulong)x->mycrc);
|
||||
if ( invalid_crc() )
|
||||
rval = -3;
|
||||
}
|
||||
x->state = STA_ready; /* not sure whether this is correct */
|
||||
break;
|
||||
}
|
||||
|
||||
switch(x->pos) {
|
||||
case 0:
|
||||
x->val = c << 2;
|
||||
break;
|
||||
case 1:
|
||||
x->val |= (c>>4)&3;
|
||||
x->mycrc |= x->val << 16;
|
||||
x->val = (c<<4)&0xf0;
|
||||
break;
|
||||
case 2:
|
||||
x->val |= (c>>2)&15;
|
||||
x->mycrc |= x->val << 8;
|
||||
x->val = (c<<6)&0xc0;
|
||||
break;
|
||||
case 3:
|
||||
x->val |= c&0x3f;
|
||||
x->mycrc |= x->val;
|
||||
break;
|
||||
}
|
||||
x->pos = (x->pos+1) % 4;
|
||||
break;
|
||||
case STA_ready:
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !(rval & ~255) ) { /* compute the CRC */
|
||||
x->crc = (x->crc << 8) ^ crc_table[((x->crc >> 16)&0xff) ^ rval];
|
||||
x->crc &= 0x00ffffff;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
@ -243,12 +243,15 @@ build_packet_and_meta (iobuf_t out, PACKET *pkt)
|
||||
|
||||
|
||||
/*
|
||||
* Write the mpi A to OUT.
|
||||
* Write the mpi A to OUT. If R_NWRITTEN is not NULL the number of
|
||||
* bytes written is stored there. To only get the number of bytes
|
||||
* which would be written NULL may be passed for OUT.
|
||||
*/
|
||||
gpg_error_t
|
||||
gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
|
||||
gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten)
|
||||
{
|
||||
int rc;
|
||||
gpg_error_t err;
|
||||
unsigned int nwritten = 0;
|
||||
|
||||
if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
@ -277,9 +280,17 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
|
||||
/* gcry_log_debughex (" ", p, (nbits+7)/8); */
|
||||
lenhdr[0] = nbits >> 8;
|
||||
lenhdr[1] = nbits;
|
||||
rc = iobuf_write (out, lenhdr, 2);
|
||||
if (!rc && p)
|
||||
rc = iobuf_write (out, p, (nbits+7)/8);
|
||||
err = out? iobuf_write (out, lenhdr, 2) : 0;
|
||||
if (!err)
|
||||
{
|
||||
nwritten += 2;
|
||||
if (p)
|
||||
{
|
||||
err = out? iobuf_write (out, p, (nbits+7)/8) : 0;
|
||||
if (!err)
|
||||
nwritten += (nbits+7)/8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -287,18 +298,25 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
|
||||
size_t nbytes;
|
||||
|
||||
nbytes = DIM(buffer);
|
||||
rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
|
||||
if( !rc )
|
||||
rc = iobuf_write( out, buffer, nbytes );
|
||||
else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT )
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
|
||||
if (!err)
|
||||
{
|
||||
err = out? iobuf_write (out, buffer, nbytes) : 0;
|
||||
if (!err)
|
||||
nwritten += nbytes;
|
||||
}
|
||||
else if (gpg_err_code (err) == GPG_ERR_TOO_SHORT )
|
||||
{
|
||||
log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a));
|
||||
/* The buffer was too small. We better tell the user about the MPI. */
|
||||
rc = gpg_error (GPG_ERR_TOO_LARGE);
|
||||
/* The buffer was too small. We better tell the user about
|
||||
* the MPI. */
|
||||
err = gpg_error (GPG_ERR_TOO_LARGE);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
if (r_nwritten)
|
||||
*r_nwritten = nwritten;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@ -463,29 +481,29 @@ static int
|
||||
do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
/* The length of the body is stored in the packet's header, which
|
||||
occurs before the body. Unfortunately, we don't know the length
|
||||
of the packet's body until we've written all of the data! To
|
||||
work around this, we first write the data into this temporary
|
||||
buffer, then generate the header, and finally copy the contents
|
||||
of this buffer to OUT. */
|
||||
iobuf_t a = iobuf_temp();
|
||||
iobuf_t a;
|
||||
int i, nskey, npkey;
|
||||
u32 pkbytes = 0;
|
||||
int is_v5;
|
||||
|
||||
log_assert (pk->version == 0 || pk->version == 4);
|
||||
log_assert (pk->version == 0 || pk->version == 4 || pk->version == 5);
|
||||
log_assert (ctb_pkttype (ctb) == PKT_PUBLIC_KEY
|
||||
|| ctb_pkttype (ctb) == PKT_PUBLIC_SUBKEY
|
||||
|| ctb_pkttype (ctb) == PKT_SECRET_KEY
|
||||
|| ctb_pkttype (ctb) == PKT_SECRET_SUBKEY);
|
||||
|
||||
/* Write the version number - if none is specified, use 4 */
|
||||
if ( !pk->version )
|
||||
iobuf_put ( a, 4 );
|
||||
else
|
||||
iobuf_put ( a, pk->version );
|
||||
write_32 (a, pk->timestamp );
|
||||
/* The length of the body is stored in the packet's header, which
|
||||
* occurs before the body. Unfortunately, we don't know the length
|
||||
* of the packet's body until we've written all of the data! To
|
||||
* work around this, we first write the data into this temporary
|
||||
* buffer, then generate the header, and finally copy the content
|
||||
* of this buffer to OUT. */
|
||||
a = iobuf_temp();
|
||||
|
||||
iobuf_put (a, pk->pubkey_algo );
|
||||
/* Note that the Version number, Timestamp, Algo, and the v5 Key
|
||||
* material count are written at the end of the function. */
|
||||
|
||||
is_v5 = (pk->version == 5);
|
||||
|
||||
/* Get number of secret and public parameters. They are held in one
|
||||
array: the public ones followed by the secret ones. */
|
||||
@ -509,11 +527,13 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
|| (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
|
||||
err = gpg_mpi_write_nohdr (a, pk->pkey[i]);
|
||||
else
|
||||
err = gpg_mpi_write (a, pk->pkey[i]);
|
||||
err = gpg_mpi_write (a, pk->pkey[i], NULL);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Record the length of the public key part. */
|
||||
pkbytes = iobuf_get_temp_length (a);
|
||||
|
||||
if (pk->seckey_info)
|
||||
{
|
||||
@ -523,9 +543,26 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
/* Build the header for protected (encrypted) secret parameters. */
|
||||
if (ski->is_protected)
|
||||
{
|
||||
/* OpenPGP protection according to rfc2440. */
|
||||
iobuf_put (a, ski->sha1chk? 0xfe : 0xff);
|
||||
iobuf_put (a, ski->algo);
|
||||
iobuf_put (a, ski->sha1chk? 0xfe : 0xff); /* S2k usage. */
|
||||
if (is_v5)
|
||||
{
|
||||
/* For a v5 key determine the count of the following
|
||||
* key-protection material and write it. */
|
||||
int count = 1; /* Pubkey algo octet. */
|
||||
if (ski->s2k.mode >= 1000)
|
||||
count += 6; /* GNU specific mode descriptor. */
|
||||
else
|
||||
count += 2; /* Mode and hash algo. */
|
||||
if (ski->s2k.mode == 1 || ski->s2k.mode == 3)
|
||||
count += 8; /* Salt. */
|
||||
if (ski->s2k.mode == 3)
|
||||
count++; /* S2K.COUNT */
|
||||
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002)
|
||||
count += ski->ivlen;
|
||||
|
||||
iobuf_put (a, count);
|
||||
}
|
||||
iobuf_put (a, ski->algo); /* Pubkey algo octet. */
|
||||
if (ski->s2k.mode >= 1000)
|
||||
{
|
||||
/* These modes are not possible in OpenPGP, we use them
|
||||
@ -556,13 +593,24 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
|
||||
}
|
||||
else /* Not protected. */
|
||||
iobuf_put (a, 0 );
|
||||
{
|
||||
iobuf_put (a, 0 ); /* S2K usage = not protected. */
|
||||
if (is_v5)
|
||||
iobuf_put (a, 0); /* Zero octets of key-protection
|
||||
* material follows. */
|
||||
}
|
||||
|
||||
if (ski->s2k.mode == 1001)
|
||||
; /* GnuPG extension - don't write a secret key at all. */
|
||||
{
|
||||
/* GnuPG extension - don't write a secret key at all. */
|
||||
if (is_v5)
|
||||
write_32 (a, 0); /* Zero octets of key material. */
|
||||
}
|
||||
else if (ski->s2k.mode == 1002)
|
||||
{
|
||||
/* GnuPG extension - divert to OpenPGP smartcard. */
|
||||
if (is_v5)
|
||||
write_32 (a, 1 + ski->ivlen);
|
||||
/* Length of the serial number or 0 for no serial number. */
|
||||
iobuf_put (a, ski->ivlen );
|
||||
/* The serial number gets stored in the IV field. */
|
||||
@ -576,15 +624,36 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
|
||||
log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
|
||||
p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
|
||||
/* For v5 keys we first write the number of octets of the
|
||||
* following encrypted key material. */
|
||||
if (is_v5)
|
||||
write_32 (a, p? (ndatabits+7)/8 : 0);
|
||||
if (p)
|
||||
iobuf_write (a, p, (ndatabits+7)/8 );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Non-protected key. */
|
||||
for ( ; i < nskey; i++ )
|
||||
if ( (err = gpg_mpi_write (a, pk->pkey[i])))
|
||||
if (is_v5)
|
||||
{
|
||||
unsigned int skbytes = 0;
|
||||
unsigned int n;
|
||||
int j;
|
||||
|
||||
for (j=i; j < nskey; j++ )
|
||||
{
|
||||
if ((err = gpg_mpi_write (NULL, pk->pkey[j], &n)))
|
||||
goto leave;
|
||||
skbytes += n;
|
||||
}
|
||||
|
||||
write_32 (a, skbytes);
|
||||
}
|
||||
|
||||
for ( ; i < nskey; i++ )
|
||||
if ( (err = gpg_mpi_write (a, pk->pkey[i], NULL)))
|
||||
goto leave;
|
||||
|
||||
write_16 (a, ski->csum );
|
||||
}
|
||||
}
|
||||
@ -593,11 +662,23 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
if (!err)
|
||||
{
|
||||
/* Build the header of the packet - which we must do after
|
||||
writing all the other stuff, so that we know the length of
|
||||
the packet */
|
||||
write_header2 (out, ctb, iobuf_get_temp_length(a), 0);
|
||||
* writing all the other stuff, so that we know the length of
|
||||
* the packet */
|
||||
u32 len = iobuf_get_temp_length (a);
|
||||
len += 1; /* version number */
|
||||
len += 4; /* timestamp */
|
||||
len += 1; /* algo */
|
||||
if (is_v5)
|
||||
len += 4; /* public key material count */
|
||||
|
||||
write_header2 (out, ctb, len, 0);
|
||||
/* And finally write it out to the real stream. */
|
||||
err = iobuf_write_temp (out, a);
|
||||
iobuf_put (out, pk->version? pk->version : 4); /* version number */
|
||||
write_32 (out, pk->timestamp );
|
||||
iobuf_put (out, pk->pubkey_algo); /* algo */
|
||||
if (is_v5)
|
||||
write_32 (out, pkbytes); /* public key material count */
|
||||
err = iobuf_write_temp (out, a); /* pub and sec key material */
|
||||
}
|
||||
|
||||
iobuf_close (a); /* Close the temporary buffer */
|
||||
@ -688,7 +769,7 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
|
||||
if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
|
||||
rc = gpg_mpi_write_nohdr (a, enc->data[i]);
|
||||
else
|
||||
rc = gpg_mpi_write (a, enc->data[i]);
|
||||
rc = gpg_mpi_write (a, enc->data[i], NULL);
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
@ -1135,10 +1216,10 @@ build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
|
||||
|
||||
/* Write the new ISSUER_FPR subpacket. */
|
||||
fingerprint_from_pk (pksk, buf+1, &fprlen);
|
||||
if (fprlen == 20)
|
||||
if (fprlen == 20 || fprlen == 32)
|
||||
{
|
||||
buf[0] = pksk->version;
|
||||
build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, 21);
|
||||
build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, fprlen + 1);
|
||||
}
|
||||
|
||||
/* Write the timestamp. */
|
||||
@ -1297,7 +1378,7 @@ string_to_notation(const char *string,int is_utf8)
|
||||
}
|
||||
|
||||
notation->name=xmalloc((s-string)+1);
|
||||
strncpy(notation->name,string,s-string);
|
||||
memcpy(notation->name,string,s-string);
|
||||
notation->name[s-string]='\0';
|
||||
|
||||
if(!saw_at && !opt.expert)
|
||||
@ -1536,7 +1617,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
|
||||
else
|
||||
iobuf_put( a, sig->version );
|
||||
if ( sig->version < 4 )
|
||||
iobuf_put (a, 5 ); /* Constant */
|
||||
iobuf_put (a, 5 ); /* Constant used by pre-v4 signatures. */
|
||||
iobuf_put (a, sig->sig_class );
|
||||
if ( sig->version < 4 )
|
||||
{
|
||||
@ -1567,7 +1648,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
|
||||
if ( !n )
|
||||
write_fake_data( a, sig->data[0] );
|
||||
for (i=0; i < n && !rc ; i++ )
|
||||
rc = gpg_mpi_write (a, sig->data[i] );
|
||||
rc = gpg_mpi_write (a, sig->data[i], NULL);
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
|
@ -609,6 +609,8 @@ learn_status_cb (void *opaque, const char *line)
|
||||
parm->extcap.ki = abool;
|
||||
else if (!strcmp (p, "aac"))
|
||||
parm->extcap.aac = abool;
|
||||
else if (!strcmp (p, "bt"))
|
||||
parm->extcap.bt = abool;
|
||||
else if (!strcmp (p, "kdf"))
|
||||
parm->extcap.kdf = abool;
|
||||
else if (!strcmp (p, "si"))
|
||||
@ -705,6 +707,21 @@ learn_status_cb (void *opaque, const char *line)
|
||||
xfree (parm->private_do[no]);
|
||||
parm->private_do[no] = unescape_status_string (line);
|
||||
}
|
||||
else if (keywordlen == 3 && !memcmp (keyword, "KDF", 3))
|
||||
{
|
||||
parm->kdf_do_enabled = 1;
|
||||
}
|
||||
else if (keywordlen == 5 && !memcmp (keyword, "UIF-", 4)
|
||||
&& strchr("123", keyword[4]))
|
||||
{
|
||||
unsigned char *data;
|
||||
int no = keyword[4] - '1';
|
||||
|
||||
log_assert (no >= 0 && no <= 2);
|
||||
data = unescape_status_string (line);
|
||||
parm->uif[no] = (data[0] != 0xff);
|
||||
xfree (data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1201,7 +1218,7 @@ agent_scd_cardlist (strlist_t *result)
|
||||
|
||||
memset (&parm, 0, sizeof parm);
|
||||
*result = NULL;
|
||||
err = start_agent (NULL, 1);
|
||||
err = start_agent (NULL, 1 | FLAG_FOR_CARD_SUPPRESS_ERRORS);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -1444,19 +1461,19 @@ gpg_agent_get_confirmation (const char *desc)
|
||||
}
|
||||
|
||||
|
||||
/* Return the S2K iteration count as computed by gpg-agent. */
|
||||
gpg_error_t
|
||||
agent_get_s2k_count (unsigned long *r_count)
|
||||
/* Return the S2K iteration count as computed by gpg-agent. On error
|
||||
* print a warning and return a default value. */
|
||||
unsigned long
|
||||
agent_get_s2k_count (void)
|
||||
{
|
||||
gpg_error_t err;
|
||||
membuf_t data;
|
||||
char *buf;
|
||||
|
||||
*r_count = 0;
|
||||
unsigned long count = 0;
|
||||
|
||||
err = start_agent (NULL, 0);
|
||||
if (err)
|
||||
return err;
|
||||
goto leave;
|
||||
|
||||
init_membuf (&data, 32);
|
||||
err = assuan_transact (agent_ctx, "GETINFO s2k_count",
|
||||
@ -1472,11 +1489,23 @@ agent_get_s2k_count (unsigned long *r_count)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
*r_count = strtoul (buf, NULL, 10);
|
||||
count = strtoul (buf, NULL, 10);
|
||||
xfree (buf);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
|
||||
leave:
|
||||
if (err || count < 65536)
|
||||
{
|
||||
/* Don't print an error if an older agent is used. */
|
||||
if (err && gpg_err_code (err) != GPG_ERR_ASS_PARAMETER)
|
||||
log_error (_("problem with the agent: %s\n"), gpg_strerror (err));
|
||||
|
||||
/* Default to 65536 which was used up to 2.0.13. */
|
||||
count = 65536;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,8 +69,11 @@ struct agent_card_info_s
|
||||
unsigned int ki:1; /* Key import available. */
|
||||
unsigned int aac:1; /* Algorithm attributes are changeable. */
|
||||
unsigned int kdf:1; /* KDF object to support PIN hashing available. */
|
||||
unsigned int bt:1; /* Button for confirmation available. */
|
||||
} extcap;
|
||||
unsigned int status_indicator;
|
||||
int kdf_do_enabled; /* True if card has a KDF object. */
|
||||
int uif[3]; /* True if User Interaction Flag is on. */
|
||||
};
|
||||
|
||||
|
||||
@ -143,7 +146,7 @@ gpg_error_t agent_clear_passphrase (const char *cache_id);
|
||||
gpg_error_t gpg_agent_get_confirmation (const char *desc);
|
||||
|
||||
/* Return the S2K iteration count as computed by gpg-agent. */
|
||||
gpg_error_t agent_get_s2k_count (unsigned long *r_count);
|
||||
unsigned long agent_get_s2k_count (void);
|
||||
|
||||
/* Check whether a secret key for public key PK is available. Returns
|
||||
0 if the secret key is available. */
|
||||
|
@ -608,6 +608,12 @@ gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr,
|
||||
NULL, NULL, ks_status_cb, &stparm);
|
||||
if (!err)
|
||||
err = cb (cb_value, 0, NULL); /* Send EOF. */
|
||||
else if (parm.stparm->source)
|
||||
{
|
||||
/* Error but we received a SOURCE status. Tell via callback but
|
||||
* ignore errors. */
|
||||
parm.data_cb (parm.data_cb_value, 1, parm.stparm->source);
|
||||
}
|
||||
|
||||
xfree (get_membuf (&parm.saveddata, NULL));
|
||||
xfree (parm.helpbuf);
|
||||
@ -650,6 +656,7 @@ ks_get_data_cb (void *opaque, const void *data, size_t datalen)
|
||||
|
||||
If R_SOURCE is not NULL the source of the data is stored as a
|
||||
malloced string there. If a source is not known NULL is stored.
|
||||
Note that this may even be returned after an error.
|
||||
|
||||
If there are too many patterns the function returns an error. That
|
||||
could be fixed by issuing several search commands or by
|
||||
@ -737,13 +744,13 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern,
|
||||
*r_fp = parm.memfp;
|
||||
parm.memfp = NULL;
|
||||
|
||||
if (r_source)
|
||||
|
||||
leave:
|
||||
if (r_source && stparm.source)
|
||||
{
|
||||
*r_source = stparm.source;
|
||||
stparm.source = NULL;
|
||||
}
|
||||
|
||||
leave:
|
||||
es_fclose (parm.memfp);
|
||||
xfree (stparm.source);
|
||||
xfree (line);
|
||||
@ -1076,7 +1083,7 @@ ks_put_inq_cb (void *opaque, const char *line)
|
||||
|
||||
/* Send a key to the configured server. {DATA,DATLEN} contains the
|
||||
key in OpenPGP binary transport format. If KEYBLOCK is not NULL it
|
||||
has the internal representaion of that key; this is for example
|
||||
has the internal representation of that key; this is for example
|
||||
used to convey meta data to LDAP keyservers. */
|
||||
gpg_error_t
|
||||
gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock)
|
||||
|
@ -216,6 +216,7 @@ get_manufacturer (unsigned int no)
|
||||
|
||||
case 0x1337: return "Warsaw Hackerspace";
|
||||
case 0x2342: return "warpzone"; /* hackerspace Muenster. */
|
||||
case 0x4354: return "Confidential Technologies"; /* cotech.de */
|
||||
case 0x63AF: return "Trustica";
|
||||
case 0xBD0E: return "Paranoidlabs";
|
||||
case 0xF517: return "FSIJ";
|
||||
@ -275,7 +276,7 @@ print_keygrip (estream_t fp, const unsigned char *grp)
|
||||
{
|
||||
tty_fprintf (fp, " keygrip ....: ");
|
||||
for (i=0; i < 20 ; i++, grp++)
|
||||
es_fprintf (fp, "%02X", *grp);
|
||||
tty_fprintf (fp, "%02X", *grp);
|
||||
tty_fprintf (fp, "\n");
|
||||
}
|
||||
}
|
||||
@ -511,6 +512,15 @@ current_card_status (ctrl_t ctrl, estream_t fp,
|
||||
es_fprintf (fp, "pinretry:%d:%d:%d:\n",
|
||||
info.chvretry[0], info.chvretry[1], info.chvretry[2]);
|
||||
es_fprintf (fp, "sigcount:%lu:::\n", info.sig_counter);
|
||||
if (info.extcap.kdf)
|
||||
{
|
||||
es_fprintf (fp, "kdf:%s:\n", info.kdf_do_enabled ? "on" : "off");
|
||||
}
|
||||
if (info.extcap.bt)
|
||||
{
|
||||
es_fprintf (fp, "uif:%d:%d:%d:\n",
|
||||
info.uif[0], info.uif[1], info.uif[2]);
|
||||
}
|
||||
|
||||
for (i=0; i < 4; i++)
|
||||
{
|
||||
@ -617,6 +627,17 @@ current_card_status (ctrl_t ctrl, estream_t fp,
|
||||
tty_fprintf (fp, "PIN retry counter : %d %d %d\n",
|
||||
info.chvretry[0], info.chvretry[1], info.chvretry[2]);
|
||||
tty_fprintf (fp, "Signature counter : %lu\n", info.sig_counter);
|
||||
if (info.extcap.kdf)
|
||||
{
|
||||
tty_fprintf (fp, "KDF setting ......: %s\n",
|
||||
info.kdf_do_enabled ? "on" : "off");
|
||||
}
|
||||
if (info.extcap.bt)
|
||||
{
|
||||
tty_fprintf (fp, "UIF setting ......: Sign=%s Decrypt=%s Auth=%s\n",
|
||||
info.uif[0] ? "on" : "off", info.uif[1] ? "on" : "off",
|
||||
info.uif[2] ? "on" : "off");
|
||||
}
|
||||
tty_fprintf (fp, "Signature key ....:");
|
||||
print_shax_fpr (fp, info.fpr1len? info.fpr1:NULL, info.fpr1len);
|
||||
if (info.fpr1len && info.fpr1time)
|
||||
@ -647,7 +668,7 @@ current_card_status (ctrl_t ctrl, estream_t fp,
|
||||
info.fpr3len? info.fpr3 : NULL);
|
||||
thefprlen = (info.fpr1len? info.fpr1len : info.fpr2len? info.fpr2len :
|
||||
info.fpr3len? info.fpr3len : 0);
|
||||
/* If the fingerprint is all 0xff, the key has no asssociated
|
||||
/* If the fingerprint is all 0xff, the key has no associated
|
||||
OpenPGP certificate. */
|
||||
if ( thefpr && !fpr_is_ff (thefpr, thefprlen)
|
||||
&& !get_pubkey_byfprint (ctrl, pk, &keyblock, thefpr, thefprlen))
|
||||
@ -674,7 +695,7 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
|
||||
{
|
||||
int err;
|
||||
strlist_t card_list, sl;
|
||||
char *serialno0;
|
||||
char *serialno0, *serialno1;
|
||||
int all_cards = 0;
|
||||
|
||||
if (serialno == NULL)
|
||||
@ -700,8 +721,6 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
|
||||
|
||||
for (sl = card_list; sl; sl = sl->next)
|
||||
{
|
||||
char *serialno1;
|
||||
|
||||
if (!all_cards && strcmp (serialno, sl->d))
|
||||
continue;
|
||||
|
||||
@ -722,7 +741,8 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
|
||||
}
|
||||
|
||||
/* Select the original card again. */
|
||||
err = agent_scd_serialno (&serialno0, serialno0);
|
||||
err = agent_scd_serialno (&serialno1, serialno0);
|
||||
xfree (serialno1);
|
||||
|
||||
leave:
|
||||
xfree (serialno0);
|
||||
@ -2019,7 +2039,7 @@ gen_kdf_data (unsigned char *data, int single_salt)
|
||||
|
||||
p = data;
|
||||
|
||||
s2k_char = encode_s2k_iterations (0);
|
||||
s2k_char = encode_s2k_iterations (agent_get_s2k_count ());
|
||||
iterations = S2K_DECODE_COUNT (s2k_char);
|
||||
count_4byte[0] = (iterations >> 24) & 0xff;
|
||||
count_4byte[1] = (iterations >> 16) & 0xff;
|
||||
@ -2110,6 +2130,49 @@ kdf_setup (const char *args)
|
||||
leave:
|
||||
agent_release_card_info (&info);
|
||||
}
|
||||
|
||||
static void
|
||||
uif (int arg_number, const char *arg_rest)
|
||||
{
|
||||
struct agent_card_info_s info;
|
||||
int feature_available;
|
||||
gpg_error_t err;
|
||||
char name[100];
|
||||
unsigned char data[2];
|
||||
|
||||
memset (&info, 0, sizeof info);
|
||||
|
||||
err = agent_scd_getattr ("EXTCAP", &info);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("error getting card info: %s\n"), gpg_strerror (err));
|
||||
return;
|
||||
}
|
||||
|
||||
feature_available = info.extcap.bt;
|
||||
agent_release_card_info (&info);
|
||||
|
||||
if (!feature_available)
|
||||
{
|
||||
log_error (_("This command is not supported by this card\n"));
|
||||
tty_printf ("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf (name, sizeof name, "UIF-%d", arg_number);
|
||||
if ( !strcmp (arg_rest, "off") )
|
||||
data[0] = 0x00;
|
||||
else if ( !strcmp (arg_rest, "on") )
|
||||
data[0] = 0x01;
|
||||
else if ( !strcmp (arg_rest, "permanent") )
|
||||
data[0] = 0x02;
|
||||
|
||||
data[1] = 0x20;
|
||||
|
||||
err = agent_scd_setattr (name, data, 2, NULL);
|
||||
if (err)
|
||||
log_error (_("error for setup UIF: %s\n"), gpg_strerror (err));
|
||||
}
|
||||
|
||||
/* Data used by the command parser. This needs to be outside of the
|
||||
function scope to allow readline based command completion. */
|
||||
@ -2120,7 +2183,7 @@ enum cmdids
|
||||
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
|
||||
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
|
||||
cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
|
||||
cmdKEYATTR,
|
||||
cmdKEYATTR, cmdUIF,
|
||||
cmdINVCMD
|
||||
};
|
||||
|
||||
@ -2152,10 +2215,11 @@ static struct
|
||||
{ "generate", cmdGENERATE, 1, N_("generate new keys")},
|
||||
{ "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
|
||||
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
|
||||
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") },
|
||||
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code")},
|
||||
{ "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
|
||||
{ "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
|
||||
{ "key-attr", cmdKEYATTR, 1, N_("change the key attribute")},
|
||||
{ "uif", cmdUIF, 1, N_("change the User Interaction Flag")},
|
||||
/* Note, that we do not announce these command yet. */
|
||||
{ "privatedo", cmdPRIVATEDO, 0, NULL },
|
||||
{ "readcert", cmdREADCERT, 0, NULL },
|
||||
@ -2447,6 +2511,14 @@ card_edit (ctrl_t ctrl, strlist_t commands)
|
||||
key_attr ();
|
||||
break;
|
||||
|
||||
case cmdUIF:
|
||||
if ( arg_number < 1 || arg_number > 3 )
|
||||
tty_printf ("usage: uif N [on|off|permanent]\n"
|
||||
" 1 <= N <= 3\n");
|
||||
else
|
||||
uif (arg_number, arg_rest);
|
||||
break;
|
||||
|
||||
case cmdQUIT:
|
||||
goto leave;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user