Merge branch 'master' into switch-to-gpgk

--
This commit is contained in:
Werner Koch 2019-03-18 19:41:07 +01:00
commit a52d883fdb
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
237 changed files with 21268 additions and 4575 deletions

View File

@ -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"

106
NEWS
View File

@ -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]
@ -317,15 +377,17 @@ Noteworthy changes in version 2.3.0 (unreleased)
Release dates of 2.2.x versions:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Version 2.2.1 (2017-09-19)
Version 2.2.2 (2017-11-07)
Version 2.2.3 (2017-11-20)
Version 2.2.4 (2017-12-20)
Version 2.2.5 (2018-02-22)
Version 2.2.6 (2018-04-09)
Version 2.2.7 (2018-05-02)
Version 2.2.8 (2018-06-08)
Version 2.2.9 (2018-07-12)
Version 2.2.1 (2017-09-19)
Version 2.2.2 (2017-11-07)
Version 2.2.3 (2017-11-20)
Version 2.2.4 (2017-12-20)
Version 2.2.5 (2018-02-22)
Version 2.2.6 (2018-04-09)
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

View File

@ -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
{
@ -275,7 +287,8 @@ struct pin_entry_info_s
int failed_tries; /* Number of tries so far failed. */
int with_qualitybar; /* Set if the quality bar should be displayed. */
int with_repeat; /* Request repetition of the passphrase. */
int repeat_okay; /* Repetition worked. */
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,12 +591,12 @@ 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,
int (*getpin_cb)(void *, const char *,
const char *, char*, size_t),
void *getpin_cb_arg);
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);
gpg_error_t agent_card_getattr (ctrl_t ctrl, const char *name, char **result);
gpg_error_t agent_card_cardlist (ctrl_t ctrl, strlist_t *result);
int agent_card_scd (ctrl_t ctrl, const char *cmdline,

View File

@ -85,6 +85,7 @@ struct entry_parm_s
int lines;
size_t size;
unsigned char *buffer;
int status;
};
@ -98,11 +99,15 @@ void
initialize_module_call_pinentry (void)
{
static int initialized;
int err;
if (!initialized)
{
if (npth_mutex_init (&entry_lock, NULL))
initialized = 1;
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)
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"));
/* 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

View File

@ -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. */
assuan_context_t ctx; /* NULL or session context for the SCdaemon
used with this connection. */
unsigned int in_use: 1; /* CTX is in use. */
unsigned int invalid:1; /* CTX is invalid, should be released. */
};
@ -138,7 +131,7 @@ initialize_module_call_scd (void)
{
err = npth_mutex_init (&start_scd_lock, NULL);
if (err)
log_fatal ("error initializing mutex: %s\n", strerror (err));
log_fatal ("error initializing mutex: %s\n", strerror (err));
initialized = 1;
}
}
@ -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. */
@ -351,7 +444,7 @@ start_scd (ctrl_t ctrl)
detached flag so that under Windows SCDAEMON does not show up a
new window. */
rc = assuan_pipe_connect (ctx, opt.scdaemon_program, argv,
no_close_list, atfork_cb, NULL,
no_close_list, atfork_cb, NULL,
ASSUAN_PIPE_CONNECT_DETACHED);
if (rc)
{
@ -415,21 +508,41 @@ 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)
{
unlock_scd (ctrl, err);
if (ctx)
assuan_release (ctx);
assuan_release (ctx);
}
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,144 +557,69 @@ 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)
{
if (ctrl->scd_local)
int err = npth_mutex_lock (&start_scd_lock);
if (err)
{
if (ctrl->scd_local->ctx)
log_error ("failed to acquire the start_scd lock: %s\n",
strerror (err));
}
else
{
if (ctrl->scd_local)
{
/* 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. */
if (ctrl->scd_local->ctx == primary_scd_ctx)
if (ctrl->scd_local->ctx)
{
/* Send a RESTART to the SCD. This is required for the
primary connection as a kind of virtual EOF; we don't
have another way to tell it that the next command
should be viewed as if a new connection has been
made. For the non-primary connections this is not
needed as we simply close the socket. We don't check
for an error here because the RESTART may fail for
example if the scdaemon has already been terminated.
Anyway, we need to set the reusable flag to make sure
that the aliveness check can clean it up. */
assuan_transact (primary_scd_ctx, "RESTART",
NULL, NULL, NULL, NULL, NULL, NULL);
primary_scd_ctx_reusable = 1;
/* 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
primary connection as a kind of virtual EOF; we don't
have another way to tell it that the next command
should be viewed as if a new connection has been
made. For the non-primary connections this is not
needed as we simply close the socket. We don't check
for an error here because the RESTART may fail for
example if the scdaemon has already been terminated.
Anyway, we need to set the reusable flag to make sure
that the aliveness check can clean it up. */
assuan_transact (primary_scd_ctx, "RESTART",
NULL, NULL, NULL, NULL, NULL, NULL);
primary_scd_ctx_reusable = 1;
}
else
assuan_release (ctrl->scd_local->ctx);
ctrl->scd_local->ctx = NULL;
}
else
assuan_release (ctrl->scd_local->ctx);
ctrl->scd_local->ctx = NULL;
}
/* Remove the local context from our list and release it. */
if (!scd_local_list)
BUG ();
else if (scd_local_list == ctrl->scd_local)
scd_local_list = ctrl->scd_local->next_local;
else
{
struct scd_local_s *sl;
for (sl=scd_local_list; sl->next_local; sl = sl->next_local)
if (sl->next_local == ctrl->scd_local)
break;
if (!sl->next_local)
/* Remove the local context from our list and release it. */
if (!scd_local_list)
BUG ();
sl->next_local = ctrl->scd_local->next_local;
else if (scd_local_list == ctrl->scd_local)
scd_local_list = ctrl->scd_local->next_local;
else
{
struct scd_local_s *sl;
for (sl=scd_local_list; sl->next_local; sl = sl->next_local)
if (sl->next_local == ctrl->scd_local)
break;
if (!sl->next_local)
BUG ();
sl->next_local = ctrl->scd_local->next_local;
}
xfree (ctrl->scd_local);
ctrl->scd_local = NULL;
}
xfree (ctrl->scd_local);
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,
inq_writekey_parms, &parms, NULL, NULL);
return unlock_scd (ctrl, rc);
err = assuan_transact (ctrl->scd_local->ctx, line, NULL, NULL,
inq_writekey_parms, &parms, NULL, NULL);
return unlock_scd (ctrl, err);
}

View File

@ -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))
return ssh_key_types[i].ssh_identifier;
&& (!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)
{
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)
name = gcry_pk_get_curve (sexp, 0, NULL);
if (!name)
{
xfree (curve_name);
curve_name = xtrystrdup (mapped);
if (!curve_name)
{
err = gpg_error_from_syserror ();
goto out;
}
err = gpg_error (GPG_ERR_INV_CURVE);
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 ();
goto out;
}
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,9 +3219,10 @@ 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)
{
err = 0;
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_pid = unp.unp_pid;
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;
}

View File

@ -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;
}
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;
}
keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
/* 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 ());

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}
/*
* 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;
r_buf = r_buf_allocated;
memcpy (r_buf + 1, buf, len/2);
*r_buf = 0;
}
else
r_buf = buf;
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;
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);

View File

@ -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)
{

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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 \

View File

@ -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.
*/

View File

@ -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 */

View File

@ -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

View File

@ -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:

View File

@ -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,7 +421,8 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
argv[argsaveidx] = argsave;
if (err)
{
log_error ("error running '%s': %s\n", pgmname, gpg_strerror (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);

View File

@ -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)
{
*p++ = c;
nbytes++;
if (c == '\n')
break;
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

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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).
*

View File

@ -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.

View File

@ -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
View 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;
}

View File

@ -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*/

View File

@ -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;
}

View File

@ -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 *

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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++ = ':';

View File

@ -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)
{

View File

@ -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);

View File

@ -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.

View File

@ -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 );

View File

@ -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
}

View File

@ -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 };

View File

@ -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;
run_mbox_test ();
run_dns_test ();
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;
}

View File

@ -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);
}
}

View File

@ -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);
{
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;
}

View File

@ -404,166 +404,192 @@ tty_print_utf8_string( const byte *p, size_t n )
static char *
do_get( const char *prompt, int hidden )
{
char *buf;
char *buf;
#ifndef __riscos__
byte cbuf[1];
byte cbuf[1];
#endif
int c, n, i;
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));
i = 0;
last_prompt_len = 0;
tty_printf ("%s", prompt);
buf = xmalloc ((n=50));
i = 0;
#ifdef USE_W32_CONSOLE
if( hidden )
SetConsoleMode(con.in, HID_INPMODE );
if (hidden)
SetConsoleMode(con.in, HID_INPMODE );
for(;;) {
DWORD nread;
for (;;)
{
DWORD nread;
if( !ReadConsoleA( con.in, cbuf, 1, &nread, NULL ) )
log_fatal("ReadConsole failed: rc=%d", (int)GetLastError() );
if( !nread )
continue;
if( *cbuf == '\n' )
break;
if (!ReadConsoleA( con.in, cbuf, 1, &nread, NULL))
log_fatal ("ReadConsole failed: rc=%d", (int)GetLastError ());
if (!nread)
continue;
if (*cbuf == '\n')
break;
if( !hidden )
last_prompt_len++;
c = *cbuf;
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) )
continue;
if( !(i < n-1) ) {
n += 50;
buf = xrealloc (buf, n);
}
buf[i++] = c;
if (!hidden)
last_prompt_len++;
c = *cbuf;
if (c == '\t')
c = ' ';
else if ( (c >= 0 && c <= 0x1f) || c == 0x7f)
continue;
if (!(i < n-1))
{
n += 50;
buf = xrealloc (buf, n);
}
buf[i++] = c;
}
if( hidden )
SetConsoleMode(con.in, DEF_INPMODE );
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
should rework this as soon as we have switched this entire
module to estream. */
c = getchar();
c = getchar();
#else
c = riscos_getchar();
c = riscos_getchar();
#endif
if (c == 0xa || c == 0xd) { /* Return || Enter */
c = (int) '\n';
} else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */
if (i>0) {
i--;
if (!hidden) {
last_prompt_len--;
fputc(8, ttyfp);
fputc(32, ttyfp);
fputc(8, ttyfp);
fflush(ttyfp);
if (c == 0xa || c == 0xd) /* Return || Enter */
{
c = (int) '\n';
}
else if (c == 0x8 || c == 0x7f) /* Backspace || Delete */
{
if (i>0)
{
i--;
if (!hidden)
{
last_prompt_len--;
fputc(8, ttyfp);
fputc(32, ttyfp);
fputc(8, ttyfp);
fflush(ttyfp);
}
} else {
fputc(7, ttyfp);
fflush(ttyfp);
}
continue;
} else if (c == (int) '\t') { /* Tab */
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;
else
{
fputc(7, ttyfp);
fflush(ttyfp);
}
continue;
}
if(!(i < n-1)) {
n += 50;
buf = xrealloc (buf, n);
else if (c == (int) '\t') /* Tab */
{
c = ' ';
}
buf[i++] = c;
if (!hidden) {
last_prompt_len++;
fputc(c, ttyfp);
fflush(ttyfp);
else if (c > 0xa0)
{
; /* we don't allow 0xa0, as this is a protected blank which may
* confuse the user */
}
} while (c != '\n');
i = (i>0) ? i-1 : 0;
#else /* Other systems. */
if( hidden ) {
#ifdef HAVE_TCGETATTR
struct termios term;
else if (iscntrl(c))
{
continue;
}
if (!(i < n-1))
{
n += 50;
buf = xrealloc (buf, n);
}
buf[i++] = c;
if (!hidden)
{
last_prompt_len++;
fputc(c, ttyfp);
fflush(ttyfp);
}
}
while (c != '\n');
i = (i>0) ? i-1 : 0;
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) );
#else /* Other systems. */
if (hidden)
{
#ifdef HAVE_TCGETATTR
struct termios term;
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));
#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 )
last_prompt_len++;
c = *cbuf;
if( c == CONTROL_D )
log_info("control d found\n");
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) )
continue;
if( !(i < n-1) ) {
n += 50;
buf = xrealloc (buf, n );
}
buf[i++] = c;
/* 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)
last_prompt_len++;
c = *cbuf;
if (c == CONTROL_D)
log_info ("Control-D detected\n");
if (c == '\t') /* Map tab to a space. */
c = ' ';
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[i++] = c;
}
if( *cbuf != '\n' ) {
buf[0] = CONTROL_D;
i = 1;
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) );
restore_termios = 0;
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;
buf[i] = 0;
return buf;
}
/* Note: This function never returns NULL. */
char *
tty_get( const char *prompt )
{

View File

@ -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. */

View File

@ -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);

View File

@ -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

View File

@ -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 \

View File

@ -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 */

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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))

View File

@ -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;

View File

@ -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,7 +3262,8 @@ unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct
return count;
error:
*error_ = error;
if (error_)
*error_ = error;
return count;
} /* dns_rr_grep() */
@ -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;

View File

@ -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 {
/*

View File

@ -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)

View File

@ -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++)
{

View File

@ -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, '/')))
*p2++ = 0;
{
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;
{
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 "";
}

View File

@ -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*/

View File

@ -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);

View File

@ -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)
return err;
goto leave;
}
}
return 0;
leave:
if (npth_mutex_unlock (&hosttable_lock))
log_fatal ("failed to release mutex\n");
return err;
}
@ -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");
xfree (request_buffer);
err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
http_get_header (http, "Location"),
&request_buffer);
if (err)
goto leave;
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);
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"));
request = request_buffer;
http_close (http, 0);
http = NULL;
}
goto leave;
goto once_more;
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)
goto leave;
{
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)
goto leave;
{
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));
}

View File

@ -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");
xfree (request_buffer);
err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
http_get_header (http, "Location"),
&request_buffer);
if (err)
goto leave;
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);
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);
goto once_more;
}
err = gpg_error_from_syserror ();
}
else
err = gpg_error (GPG_ERR_NO_DATA);
log_error (_("too many redirections\n"));
url = request_buffer;
http_close (http, 0);
http = NULL;
http_session_release (session);
session = NULL;
}
goto leave;
goto once_more;
default:
log_error (_("error accessing '%s': http status %u\n"),

View File

@ -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,26 +1692,16 @@ extract_attributes (LDAPMod ***modlist, char *line)
if (is_pub || is_sub)
{
char *size = fields[2];
int val = atoi (size);
size = NULL;
char padded[6];
int val;
if (val > 0)
{
/* We zero pad this on the left to make PGP happy. */
char padded[6];
if (val < 99999 && val > 0)
{
snprintf (padded, sizeof padded, "%05u", val);
size = padded;
}
}
if (size)
{
if (is_pub || is_sub)
modlist_add (modlist, "pgpKeySize", size);
}
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);
modlist_add (modlist, "pgpKeySize", padded);
}
}
if (is_pub)
@ -1736,10 +1724,7 @@ extract_attributes (LDAPMod ***modlist, char *line)
}
if (algo)
{
if (is_pub)
modlist_add (modlist, "pgpKeyType", algo);
}
modlist_add (modlist, "pgpKeyType", algo);
}
if (is_pub || is_sub || is_sig)

View File

@ -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)
{

View File

@ -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)

View File

@ -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);

View File

@ -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,24 +994,39 @@ 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
{
uri = strconcat ("https://",
domain,
portstr,
"/.well-known/openpgpkey/hu/",
encodedhash,
NULL);
no_log = 1;
if (uri)
char *escapedmbox;
escapedmbox = http_escape_string (mbox, "%;?&=");
if (escapedmbox)
{
err = dirmngr_status_printf (ctrl, "SOURCE", "https://%s%s",
domain, portstr);
if (err)
goto leave;
uri = strconcat ("https://",
domain,
portstr,
"/.well-known/openpgpkey/",
subdomain_mode? domain_orig : "",
subdomain_mode? "/" : "",
"hu/",
encodedhash,
"?l=",
escapedmbox,
NULL);
xfree (escapedmbox);
no_log = 1;
if (uri)
{
err = dirmngr_status_printf (ctrl, "SOURCE", "https://%s%s",
domain, portstr);
if (err)
goto leave;
}
}
}
if (!uri)
@ -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
View 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;
}

View File

@ -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);

View File

@ -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)
{

View File

@ -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>]

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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

View File

@ -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 | \

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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:

View File

@ -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)
{

View File

@ -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"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static byte asctobin[256]; /* runtime initialized */
static const byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
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);
afx->refcount = 1;
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,10 +1080,10 @@ 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 ) {
log_info (_("CRC error; %06lX - %06lX\n"),
(ulong)afx->crc, (ulong)mycrc);
rc = invalid_crc();
else if( mycrc != get_afx_crc (afx) ) {
log_info (_("CRC error; %06lX - %06lX\n"),
(ulong)get_afx_crc (afx), (ulong)mycrc);
rc = invalid_crc();
}
else {
rc = 0;
@ -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);
}
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;
if( size ) {
gcry_md_write (afx->crc_md, buf, size);
armor_output_buf_as_radix64 (afx, a, buf, size);
}
}
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;
}

View File

@ -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. */
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])))
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)
{

View File

@ -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;
}

View File

@ -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. */
@ -192,14 +195,14 @@ gpg_error_t agent_keywrap_key (ctrl_t ctrl, int forexport,
gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc,
char **cache_nonce_addr, const void *key,
size_t keylen, int unattended, int force,
u32 *keyid, u32 *mainkeyid, int pubkey_algo);
u32 *keyid, u32 *mainkeyid, int pubkey_algo);
/* Receive a key from the agent. */
gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip,
const char *desc, int openpgp_protected,
char **cache_nonce_addr,
unsigned char **r_result, size_t *r_resultlen,
u32 *keyid, u32 *mainkeyid, int pubkey_algo);
u32 *keyid, u32 *mainkeyid, int pubkey_algo);
/* Delete a key from the agent. */
gpg_error_t agent_delete_key (ctrl_t ctrl, const char *hexkeygrip,

View File

@ -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)

View File

@ -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