Compare commits

...
83 Commits
Author SHA1 Message Date
cyd01 4d15c4e032 Tagging the 0.76.0.2 release of the KiTTY project. 2021-11-17 10:37:32 +01:00
cyd01 bf495102c3 Tagging the 0.76.0.1 release of the KiTTY project. 2021-11-06 14:41:52 +01:00
cyd01 7996f3d3bf fix adb issue 2021-10-28 17:04:41 +02:00
cyd01 3f2c71a3f1 0.76 first commit and other tools adaptation 2021-10-28 16:26:56 +02:00
cyd01 2dab7f5482 Add doc 2021-10-28 14:18:30 +02:00
cyd01 07af177dd1 0.75: remove tutty colors patch 2021-10-28 11:42:13 +02:00
cyd01 60cd52704a 0.75: fix launcher issue 2021-10-28 10:56:58 +02:00
cyd01 af9fe9f03c 0.75: fix integrated keygen and agent issue 2021-10-28 09:16:27 +02:00
cyd01 e7e682bb70 0.75 try to re-integrate TuTTY patch 2021-10-26 18:32:18 +02:00
cyd01 e026c881f0 first 0.75 version that starts 2021-10-26 15:42:07 +02:00
cyd01 fb701dced1 first 0.75 version that compiles 2021-10-26 10:22:12 +02:00
cyd01 30e00a32a6 0.75 first commit 2021-09-08 23:02:51 +02:00
CydandGitHub 64dd8883c3 Update PscpIntegration.md 2021-05-14 15:35:04 +02:00
CydandGitHub 1e27f1f6b0 Update PscpIntegration.md 2021-05-13 15:24:59 +02:00
CydandGitHub 62418b79bf Update lodash.js 2021-05-13 11:18:03 +02:00
CydandGitHub b6efad68ea Merge pull request #294 from mortalis13/master
Corrected some typos in the docs/pages/0.71.md
2021-05-13 11:15:26 +02:00
cyd01 4f79b1ec48 Tagging the 0.74.4.13 release of the KiTTY project. 2021-05-02 18:37:09 +02:00
cyd01 8ee447f8c5 Tagging the 0.74.4.12 release of the KiTTY project. 2021-05-01 22:35:33 +02:00
mortalis13 0f027f8433 typos corrected 2021-04-29 15:32:00 +02:00
cyd01 9c043bb83a Tagging the 0.74.4.11 release of the KiTTY project. 2021-04-20 11:36:09 +02:00
cyd01 8f12302da6 Tagging the 0.74.4.10 release of the KiTTY project. 2021-04-17 22:08:51 +02:00
cyd01 2090b4e851 Tagging the 0.74.4.9 release of the KiTTY project. 2021-04-16 19:55:15 +02:00
cyd01 e8ec2007b8 Tagging the 0.74.4.8 release of the KiTTY project. 2021-04-12 15:13:29 +02:00
cyd01 ee18bc69e0 Tagging the 0.74.4.7 release of the KiTTY project. 2021-03-01 09:58:45 +01:00
cyd01 2c7c0116da Tagging the 0.74.4.6 release of the KiTTY project. 2021-01-25 18:45:42 +01:00
cyd01 5b2a4ea8a0 Proxy choice documentation 2021-01-25 18:27:28 +01:00
cyd01 34a61f4270 Tagging the 0.74.4.5 release of the KiTTY project. 2021-01-20 08:27:42 +01:00
CydandGitHub a218a7a454 Update FUNDING.yml 2021-01-17 12:33:01 +01:00
CydandGitHub 15db0a9468 Update FUNDING.yml 2021-01-17 12:31:46 +01:00
CydandGitHub 1fab988b10 Update FUNDING.yml 2021-01-14 16:35:07 +01:00
CydandGitHub aadc177664 Update FUNDING.yml 2021-01-14 16:32:04 +01:00
cyd01 c4b14921cc Tagging the 0.74.4.4 release of the KiTTY project. 2021-01-11 19:30:11 +01:00
CydandGitHub 5b879f1e6c Merge pull request #270 from lars18th/fix-ipv4-fwd
fix ipv4 port forwards window
2021-01-08 19:58:46 +01:00
Lars TheandGitHub 44aa59f27b Fix another time the port fwd window
Print correct values in some other cases
2021-01-07 16:59:34 +01:00
Lars TheandGitHub 18543833a1 fix ipv4 port forwards window
When using IPv4 (or IPv6) only forwards the window doesn't print the status. This patch fixes it.
2021-01-07 16:13:07 +01:00
cyd01 6388f577ad Tagging the 0.74.4.3 release of the KiTTY project. 2021-01-06 23:52:58 +01:00
cyd01 2d1b66aa3f Tagging the 0.74.4.2 release of the KiTTY project. 2021-01-05 19:40:17 +01:00
cyd01 3d0137720e Docs 2021-01-05 18:43:09 +01:00
cyd01 964ed999e1 Docs 2021-01-04 19:44:20 +01:00
cyd01 44b198279a Rebuild blocnote for 64bits 2020-12-29 18:10:39 +01:00
cyd01 3deb60e589 Tagging the 0.74.4.1 release of the KiTTY project. 2020-12-28 19:09:59 +01:00
cyd01 1e7be14779 Tagging the 0.74.3.5 release of the KiTTY project. 2020-12-14 18:42:46 +01:00
cyd01 1c3398cbb7 Tagging the 0.74.3.4 release of the kitty project. 2020-12-02 19:46:26 +01:00
cyd01 2d0a377626 Tagging the 0.74.3.3 release of the kitty project. 2020-12-01 18:43:53 +01:00
cyd01 232c3b29fd Tagging the 0.74.3.2 release of the kitty project. 2020-11-30 19:33:29 +01:00
cyd01 3bab5a6151 New Github workflow 2020-11-15 12:38:37 +01:00
CydandGitHub 9bb4b61196 Merge pull request #248 from jaynemo/cygwindocupdate
Streamline instructions, changes to quoting to ensure commands run
2020-11-15 12:33:47 +01:00
jaynemo 80597e340d Streamline instructions, changes to quoting to ensure commands run
correctly.
2020-11-07 10:20:55 +13:00
cyd01 c558736424 Tagging the 0.74.3.1 release of the kitty project. 2020-11-06 18:37:06 +01:00
cyd01 7f7fac22e9 Tagging the 0.74.2.8 release of the kitty project. 2020-11-03 13:26:02 +01:00
cyd01 8124638aba Tagging the 0.74.2.7 release of the kitty project. 2020-10-29 08:40:58 +01:00
cyd01 63053a885f New funding 2020-10-11 19:49:07 +02:00
cyd01 464c88d396 Tagging the 0.74.2.6 release of the kitty project. 2020-10-10 23:57:13 +02:00
cyd01 6af39c95c2 Tagging the 0.74.2.5 release of the kitty project. 2020-10-09 19:18:36 +02:00
cyd01 ebb5e2f164 Tagging the 0.74.2.4 release of the kitty project. 2020-10-05 07:55:27 +02:00
cyd01 c4b6dabb28 Add 64 bits tools to Github Actions 2020-09-27 12:12:48 +02:00
CydandGitHub e85550c70e Update README.md 2020-09-26 23:34:05 +02:00
cyd01 9d80c6b171 Website update 2020-09-26 23:21:52 +02:00
CydandGitHub 9a8af62267 Update README.md 2020-09-26 23:18:45 +02:00
CydandGitHub 45c65bbdb0 Update README.md 2020-09-26 23:18:18 +02:00
CydandGitHub 12d8132e56 Update README.md 2020-09-26 23:17:52 +02:00
CydandGitHub b76939b3d0 Update README.md 2020-09-26 23:16:31 +02:00
cyd01 659bc96519 Tagging the 0.74.2.3 release of the kitty project. 2020-09-26 22:54:48 +02:00
cyd01 cb833b241a Add Website source code 2020-09-26 22:13:26 +02:00
cyd01 042b9f5cef Tagging the 0.74.2.2 release of the kitty project. 2020-09-23 10:57:01 +02:00
cyd01 1d13ae9175 Change github actions 2020-09-20 12:22:45 +02:00
cyd01 2e87a6dc2b Change github actions 2020-09-20 12:18:09 +02:00
cyd01 057faa84f9 Merge branch 'master' of github.com:cyd01/KiTTY 2020-09-20 12:11:37 +02:00
cyd01 8612fa5ef2 Change github actions 2020-09-20 12:11:17 +02:00
CydandGitHub 0ae14d0859 Update README.md 2020-09-19 14:50:29 +02:00
cyd01 977da5f49c Tagging the 0.74.2.1 release of the kitty project. 2020-09-18 18:05:42 +02:00
cyd01 cc43da0078 Tagging the 0.74.1.1 release of the kitty project. 2020-09-16 22:14:35 +02:00
cyd01 7400667711 Tagging the 0.74.0.7 release of the kitty project. 2020-09-12 22:52:32 +02:00
cyd01 b9f427b176 Tagging the 0.74.0.6 release of the kitty project. 2020-09-02 10:45:29 +02:00
cyd01 f1377e7040 Tagging the 0.74.0.5 release of the kitty project. 2020-08-24 18:21:15 +02:00
cyd01 62c2de1dd2 Tagging the 0.74.0.4 release of the kitty project. 2020-08-12 09:02:00 +02:00
cyd01 5180166b5d Tagging the 0.74.0.3 release of the kitty project. 2020-08-06 19:18:31 +02:00
cyd01 e45c98b427 New current folder for portablemode definition (shared with pscp, plink ...) 2020-08-03 09:42:00 +02:00
cyd01 dea7220469 New comment 2020-08-03 08:58:49 +02:00
cyd01 49d45ac099 Change main version for Github Actions 2020-07-09 19:33:23 +02:00
cyd01 a38fa17431 Tagging the 0.74.0.2 release of the kitty project. 2020-07-02 23:04:43 +02:00
cyd01 4c9cecbe68 Tagging the 0.74.0.1 release of the kitty project. 2020-07-02 21:31:58 +02:00
cyd01 8312a7eece Tagging the 0.73.2.18 release of the kitty project. 2020-06-23 18:38:39 +02:00
514 changed files with 83358 additions and 53138 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
github: [ cyd01 ]
custom: [ "https://www.paypal.com/donate/?token=oyJhWJ4Z0AW-wJxIBGIfxC2LyYmnbSPU2Vax9EJdVAtaEYvh8VXsSyCOHCVCO8Y9uH_I4G&country.x=GB&locale.x=GB", "http://kitty.9bis.com" ]
github: [ "cyd01" ]
custom: [ "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=65VYL8F5AD57G&source=url", "https://9bis.net/kitty/bitcoin.html" ]
+10 -12
View File
@@ -3,17 +3,17 @@ name: C/C++ CI
on:
push:
# Sequence of patterns matched against refs/heads
branches:
- master # Push events on master branch
- feat-*
- fix-*
- bugfix*
# branches:
# - master # Push events on master branch
# - feat-*
# - fix-*
# - bugfix*
# Sequence of patterns matched against refs/tags
tags:
- v*
env:
VERSION: 0.73
VERSION: 0.76
jobs:
# Build for Win 32bits
@@ -32,15 +32,14 @@ jobs:
mkdir ../builds
docker run --rm -i -v $(pwd)/../builds:/builds -v $(pwd):/sources cyd01/cross-gcc "cd ${VERSION}_My_PuTTY/windows ; make -f MAKEFILE.MINGW cross ; cd /builds ; ls -l"
mv -f $(pwd)/../builds ./
cd builds ; zip kitty.zip *.exe
# Upload runner package tar.gz/zip as artifact
- name: Publish Artifact
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v1
with:
name: kitty.zip
path: builds/kitty.zip
name: kitty
path: builds/
# Build for Win 64bits
build64:
@@ -57,12 +56,11 @@ jobs:
mkdir ../builds
docker run --rm -i -v $(pwd)/../builds:/builds -v $(pwd):/sources cyd01/cross-gcc "cd ${VERSION}_My_PuTTY/windows ; make -f MAKEFILE.MINGW cross64 ; cd /builds ; ls -l"
mv -f $(pwd)/../builds ./
cd builds ; zip kitty.zip *.exe
# Upload runner package tar.gz/zip as artifact
- name: Publish Artifact
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v1
with:
name: kitty64.zip
path: builds/kitty.zip
name: kitty64
path: builds/
-16
View File
@@ -1,16 +0,0 @@
/*
* Linking module for programs that are restricted to only using SSH
* (pscp and psftp). These do not support selection of backend, but
* must still have a backends[] array mentioning SSH because
* settings.c will want to consult it during session load.
*/
#include <stdio.h>
#include "putty.h"
const int be_default_protocol = PROT_SSH;
const struct BackendVtable *const backends[] = {
&ssh_backend,
NULL
};
-6
View File
@@ -1,6 +0,0 @@
/*
* cgtest.c: stub file to compile cmdgen.c in self-test mode
*/
#define TEST_CMDGEN
#include "cmdgen.c"
File diff suppressed because it is too large Load Diff
-223
View File
@@ -1,223 +0,0 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#define PUTTY_DO_GLOBALS
#include "putty.h"
#include "terminal.h"
/* For Unix in particular, but harmless if this main() is reused elsewhere */
const bool buildinfo_gtk_relevant = false;
static const TermWinVtable fuzz_termwin_vt;
int main(int argc, char **argv)
{
char blk[512];
size_t len;
Terminal *term;
Conf *conf;
struct unicode_data ucsdata;
TermWin termwin;
termwin.vt = &fuzz_termwin_vt;
conf = conf_new();
do_defaults(NULL, conf);
init_ucs(&ucsdata, conf_get_str(conf, CONF_line_codepage),
conf_get_bool(conf, CONF_utf8_override),
CS_NONE, conf_get_int(conf, CONF_vtmode));
term = term_init(conf, &ucsdata, &termwin);
term_size(term, 24, 80, 10000);
term->ldisc = NULL;
/* Tell american fuzzy lop that this is a good place to fork. */
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif
while (!feof(stdin)) {
len = fread(blk, 1, sizeof(blk), stdin);
term_data(term, false, blk, len);
}
term_update(term);
return 0;
}
/* functions required by terminal.c */
static bool fuzz_setup_draw_ctx(TermWin *tw) { return true; }
static void fuzz_draw_text(
TermWin *tw, int x, int y, wchar_t *text, int len,
unsigned long attr, int lattr, truecolour tc)
{
int i;
printf("TEXT[attr=%08lx,lattr=%02x]@(%d,%d):", attr, lattr, x, y);
for (i = 0; i < len; i++) {
printf(" %x", (unsigned)text[i]);
}
printf("\n");
}
static void fuzz_draw_cursor(
TermWin *tw, int x, int y, wchar_t *text, int len,
unsigned long attr, int lattr, truecolour tc)
{
int i;
printf("CURS[attr=%08lx,lattr=%02x]@(%d,%d):", attr, lattr, x, y);
for (i = 0; i < len; i++) {
printf(" %x", (unsigned)text[i]);
}
printf("\n");
}
static void fuzz_draw_trust_sigil(TermWin *tw, int x, int y)
{
printf("TRUST@(%d,%d)\n", x, y);
}
static int fuzz_char_width(TermWin *tw, int uc) { return 1; }
static void fuzz_free_draw_ctx(TermWin *tw) {}
static void fuzz_set_cursor_pos(TermWin *tw, int x, int y) {}
static void fuzz_set_raw_mouse_mode(TermWin *tw, bool enable) {}
static void fuzz_set_scrollbar(TermWin *tw, int total, int start, int page) {}
static void fuzz_bell(TermWin *tw, int mode) {}
static void fuzz_clip_write(
TermWin *tw, int clipboard, wchar_t *text, int *attrs,
truecolour *colours, int len, bool must_deselect) {}
static void fuzz_clip_request_paste(TermWin *tw, int clipboard) {}
static void fuzz_refresh(TermWin *tw) {}
static void fuzz_request_resize(TermWin *tw, int w, int h) {}
static void fuzz_set_title(TermWin *tw, const char *title) {}
static void fuzz_set_icon_title(TermWin *tw, const char *icontitle) {}
static void fuzz_set_minimised(TermWin *tw, bool minimised) {}
static bool fuzz_is_minimised(TermWin *tw) { return false; }
static void fuzz_set_maximised(TermWin *tw, bool maximised) {}
static void fuzz_move(TermWin *tw, int x, int y) {}
static void fuzz_set_zorder(TermWin *tw, bool top) {}
static bool fuzz_palette_get(TermWin *tw, int n, int *r, int *g, int *b)
{ return false; }
static void fuzz_palette_set(TermWin *tw, int n, int r, int g, int b) {}
static void fuzz_palette_reset(TermWin *tw) {}
static void fuzz_get_pos(TermWin *tw, int *x, int *y) { *x = *y = 0; }
static void fuzz_get_pixels(TermWin *tw, int *x, int *y) { *x = *y = 0; }
static const char *fuzz_get_title(TermWin *tw, bool icon) { return "moo"; }
static bool fuzz_is_utf8(TermWin *tw) { return true; }
static const TermWinVtable fuzz_termwin_vt = {
fuzz_setup_draw_ctx,
fuzz_draw_text,
fuzz_draw_cursor,
fuzz_draw_trust_sigil,
fuzz_char_width,
fuzz_free_draw_ctx,
fuzz_set_cursor_pos,
fuzz_set_raw_mouse_mode,
fuzz_set_scrollbar,
fuzz_bell,
fuzz_clip_write,
fuzz_clip_request_paste,
fuzz_refresh,
fuzz_request_resize,
fuzz_set_title,
fuzz_set_icon_title,
fuzz_set_minimised,
fuzz_is_minimised,
fuzz_set_maximised,
fuzz_move,
fuzz_set_zorder,
fuzz_palette_get,
fuzz_palette_set,
fuzz_palette_reset,
fuzz_get_pos,
fuzz_get_pixels,
fuzz_get_title,
fuzz_is_utf8,
};
void ldisc_send(Ldisc *ldisc, const void *buf, int len, bool interactive) {}
void ldisc_echoedit_update(Ldisc *ldisc) {}
void modalfatalbox(const char *fmt, ...) { exit(0); }
void nonfatal(const char *fmt, ...) { }
/* needed by timing.c */
void timer_change_notify(unsigned long next) { }
/* needed by config.c and sercfg.c */
void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton) { }
int dlg_radiobutton_get(union control *ctrl, void *dlg) { return 0; }
void dlg_checkbox_set(union control *ctrl, void *dlg, int checked) { }
int dlg_checkbox_get(union control *ctrl, void *dlg) { return 0; }
void dlg_editbox_set(union control *ctrl, void *dlg, char const *text) { }
char *dlg_editbox_get(union control *ctrl, void *dlg) { return dupstr("moo"); }
void dlg_listbox_clear(union control *ctrl, void *dlg) { }
void dlg_listbox_del(union control *ctrl, void *dlg, int index) { }
void dlg_listbox_add(union control *ctrl, void *dlg, char const *text) { }
void dlg_listbox_addwithid(union control *ctrl, void *dlg,
char const *text, int id) { }
int dlg_listbox_getid(union control *ctrl, void *dlg, int index) { return 0; }
int dlg_listbox_index(union control *ctrl, void *dlg) { return -1; }
int dlg_listbox_issel(union control *ctrl, void *dlg, int index) { return 0; }
void dlg_listbox_select(union control *ctrl, void *dlg, int index) { }
void dlg_text_set(union control *ctrl, void *dlg, char const *text) { }
void dlg_filesel_set(union control *ctrl, void *dlg, Filename *fn) { }
Filename *dlg_filesel_get(union control *ctrl, void *dlg) { return NULL; }
void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec *fn) { }
FontSpec *dlg_fontsel_get(union control *ctrl, void *dlg) { return NULL; }
void dlg_update_start(union control *ctrl, void *dlg) { }
void dlg_update_done(union control *ctrl, void *dlg) { }
void dlg_set_focus(union control *ctrl, void *dlg) { }
void dlg_label_change(union control *ctrl, void *dlg, char const *text) { }
union control *dlg_last_focused(union control *ctrl, void *dlg) { return NULL; }
void dlg_beep(void *dlg) { }
void dlg_error_msg(void *dlg, const char *msg) { }
void dlg_end(void *dlg, int value) { }
void dlg_coloursel_start(union control *ctrl, void *dlg,
int r, int g, int b) { }
bool dlg_coloursel_results(union control *ctrl, void *dlg,
int *r, int *g, int *b) { return false; }
void dlg_refresh(union control *ctrl, void *dlg) { }
bool dlg_is_visible(union control *ctrl, dlgparam *dp) { return false; }
const char *const appname = "FuZZterm";
const int ngsslibs = 0;
const char *const gsslibnames[0] = { };
const struct keyvalwhere gsslibkeywords[0] = { };
/*
* Default settings that are specific to Unix plink.
*/
char *platform_default_s(const char *name)
{
if (!strcmp(name, "TermType"))
return dupstr(getenv("TERM"));
if (!strcmp(name, "SerialLine"))
return dupstr("/dev/ttyS0");
return NULL;
}
bool platform_default_b(const char *name, bool def)
{
return def;
}
int platform_default_i(const char *name, int def)
{
return def;
}
FontSpec *platform_default_fontspec(const char *name)
{
return fontspec_new("");
}
Filename *platform_default_filename(const char *name)
{
if (!strcmp(name, "LogFileName"))
return filename_from_str("putty.log");
else
return filename_from_str("");
}
char *x_get_default(const char *key)
{
return NULL; /* this is a stub */
}
File diff suppressed because it is too large Load Diff
-153
View File
@@ -1,153 +0,0 @@
/*
* pageant.h: header for pageant.c.
*/
#include <stdarg.h>
#ifdef MOD_PERSO
NOTIFYICONDATA trayIcone ;
int GetAskConfirmationFlag(void) ;
int GetShowBalloonOnKeyUsage( void ) ;
int ShowBalloonTip( NOTIFYICONDATA tnid, TCHAR title[], TCHAR msg[] ) ;
#endif
/*
* Upper limit on length of any agent message. Used as a basic sanity
* check on messages' length fields, and used by the Windows Pageant
* client IPC to decide how large a file mapping to allocate.
*/
#define AGENT_MAX_MSGLEN 262144
typedef void (*pageant_logfn_t)(void *logctx, const char *fmt, va_list ap);
/*
* Initial setup.
*/
void pageant_init(void);
/*
* The main agent function that answers messages.
*
* Expects a message/length pair as input, minus its initial length
* field but still with its type code on the front.
*
* Returns a fully formatted message as output, *with* its initial
* length field, and sets *outlen to the full size of that message.
*/
void pageant_handle_msg(BinarySink *bs,
const void *msg, int msglen,
void *logctx, pageant_logfn_t logfn);
/*
* Construct a failure response. Useful for agent front ends which
* suffer a problem before they even get to pageant_handle_msg.
*
* 'log_reason' is only used if logfn is not NULL.
*/
void pageant_failure_msg(BinarySink *bs,
const char *log_reason,
void *logctx, pageant_logfn_t logfn);
/*
* Construct a list of public keys, just as the two LIST_IDENTITIES
* requests would have returned them.
*/
void pageant_make_keylist1(BinarySink *);
void pageant_make_keylist2(BinarySink *);
/*
* Accessor functions for Pageant's internal key lists. Fetch the nth
* key; count the keys; attempt to add a key (returning true on
* success, in which case the ownership of the key structure has been
* taken over by pageant.c); attempt to delete a key (returning true
* on success, in which case the ownership of the key structure is
* passed back to the client).
*/
RSAKey *pageant_nth_ssh1_key(int i);
ssh2_userkey *pageant_nth_ssh2_key(int i);
int pageant_count_ssh1_keys(void);
int pageant_count_ssh2_keys(void);
bool pageant_add_ssh1_key(RSAKey *rkey);
bool pageant_add_ssh2_key(ssh2_userkey *skey);
bool pageant_delete_ssh1_key(RSAKey *rkey);
bool pageant_delete_ssh2_key(ssh2_userkey *skey);
/*
* This callback must be provided by the Pageant front end code.
* pageant_handle_msg calls it to indicate that the message it's just
* handled has changed the list of keys held by the agent. Front ends
* which expose that key list through dedicated UI may need to refresh
* that UI's state in this function; other front ends can leave it
* empty.
*/
void keylist_update(void);
/*
* Functions to establish a listening socket speaking the SSH agent
* protocol. Call pageant_listener_new() to set up a state; then
* create a socket using the returned Plug; then call
* pageant_listener_got_socket() to give the listening state its own
* socket pointer. Also, provide a logging function later if you want
* to.
*/
struct pageant_listen_state;
struct pageant_listen_state *pageant_listener_new(Plug **plug);
void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket *);
void pageant_listener_set_logfn(struct pageant_listen_state *pl,
void *logctx, pageant_logfn_t logfn);
void pageant_listener_free(struct pageant_listen_state *pl);
/*
* Functions to perform specific key actions, either as a client of an
* ssh-agent running elsewhere, or directly on the agent state in this
* process. (On at least one platform we want to do this in an
* agnostic way between the two situations.)
*
* pageant_get_keylist{1,2} work just like pageant_make_keylist{1,2}
* above, except that they can also cope if they have to contact an
* external agent.
*
* pageant_add_keyfile() is used to load a private key from a file and
* add it to the agent. Initially, you should call it with passphrase
* NULL, and it will check if the key is already in the agent, and
* whether a passphrase is required. Return values are given in the
* enum below. On return, *retstr will either be NULL, or a
* dynamically allocated string containing a key comment or an error
* message.
*
* pageant_add_keyfile() also remembers passphrases with which it's
* successfully decrypted keys (because if you try to add multiple
* keys in one go, you might very well have used the same passphrase
* for keys that have the same trust properties). Call
* pageant_forget_passphrases() to get rid of them all.
*/
void *pageant_get_keylist1(int *length);
void *pageant_get_keylist2(int *length);
enum {
PAGEANT_ACTION_OK, /* success; no further action needed */
PAGEANT_ACTION_FAILURE, /* failure; *retstr is error message */
PAGEANT_ACTION_NEED_PP /* need passphrase: *retstr is key comment */
};
int pageant_add_keyfile(Filename *filename, const char *passphrase,
char **retstr);
void pageant_forget_passphrases(void);
struct pageant_pubkey {
/* Everything needed to identify a public key found by
* pageant_enum_keys and pass it back to the agent or other code
* later */
strbuf *blob;
char *comment;
int ssh_version;
};
struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key);
void pageant_pubkey_free(struct pageant_pubkey *key);
typedef void (*pageant_key_enum_fn_t)(void *ctx,
const char *fingerprint,
const char *comment,
struct pageant_pubkey *key);
int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
char **retstr);
int pageant_delete_key(struct pageant_pubkey *key, char **retstr);
int pageant_delete_all_keys(char **retstr);
File diff suppressed because it is too large Load Diff
-204
View File
@@ -1,204 +0,0 @@
/*
* sercfg.c - the serial-port specific parts of the PuTTY
* configuration box. Centralised as cross-platform code because
* more than one platform will want to use it, but not part of the
* main configuration. The expectation is that each platform's
* local config function will call out to ser_setup_config_box() if
* it needs to set up the standard serial stuff. (Of course, it can
* then apply local tweaks after ser_setup_config_box() returns, if
* it needs to.)
*/
#include <assert.h>
#include <stdlib.h>
#include "putty.h"
#include "dialog.h"
#include "storage.h"
static void serial_parity_handler(union control *ctrl, dlgparam *dlg,
void *data, int event)
{
static const struct {
const char *name;
int val;
} parities[] = {
{"None", SER_PAR_NONE},
{"Odd", SER_PAR_ODD},
{"Even", SER_PAR_EVEN},
{"Mark", SER_PAR_MARK},
{"Space", SER_PAR_SPACE},
};
int mask = ctrl->listbox.context.i;
int i, j;
Conf *conf = (Conf *)data;
if (event == EVENT_REFRESH) {
/* Fetching this once at the start of the function ensures we
* remember what the right value is supposed to be when
* operations below cause reentrant calls to this function. */
int oldparity = conf_get_int(conf, CONF_serparity);
dlg_update_start(ctrl, dlg);
dlg_listbox_clear(ctrl, dlg);
for (i = 0; i < lenof(parities); i++) {
if (mask & (1 << i))
dlg_listbox_addwithid(ctrl, dlg, parities[i].name,
parities[i].val);
}
for (i = j = 0; i < lenof(parities); i++) {
if (mask & (1 << i)) {
if (oldparity == parities[i].val) {
dlg_listbox_select(ctrl, dlg, j);
break;
}
j++;
}
}
if (i == lenof(parities)) { /* an unsupported setting was chosen */
dlg_listbox_select(ctrl, dlg, 0);
oldparity = SER_PAR_NONE;
}
dlg_update_done(ctrl, dlg);
conf_set_int(conf, CONF_serparity, oldparity); /* restore */
} else if (event == EVENT_SELCHANGE) {
int i = dlg_listbox_index(ctrl, dlg);
if (i < 0)
i = SER_PAR_NONE;
else
i = dlg_listbox_getid(ctrl, dlg, i);
conf_set_int(conf, CONF_serparity, i);
}
}
static void serial_flow_handler(union control *ctrl, dlgparam *dlg,
void *data, int event)
{
static const struct {
const char *name;
int val;
} flows[] = {
{"None", SER_FLOW_NONE},
{"XON/XOFF", SER_FLOW_XONXOFF},
{"RTS/CTS", SER_FLOW_RTSCTS},
{"DSR/DTR", SER_FLOW_DSRDTR},
};
int mask = ctrl->listbox.context.i;
int i, j;
Conf *conf = (Conf *)data;
if (event == EVENT_REFRESH) {
/* Fetching this once at the start of the function ensures we
* remember what the right value is supposed to be when
* operations below cause reentrant calls to this function. */
int oldflow = conf_get_int(conf, CONF_serflow);
dlg_update_start(ctrl, dlg);
dlg_listbox_clear(ctrl, dlg);
for (i = 0; i < lenof(flows); i++) {
if (mask & (1 << i))
dlg_listbox_addwithid(ctrl, dlg, flows[i].name, flows[i].val);
}
for (i = j = 0; i < lenof(flows); i++) {
if (mask & (1 << i)) {
if (oldflow == flows[i].val) {
dlg_listbox_select(ctrl, dlg, j);
break;
}
j++;
}
}
if (i == lenof(flows)) { /* an unsupported setting was chosen */
dlg_listbox_select(ctrl, dlg, 0);
oldflow = SER_FLOW_NONE;
}
dlg_update_done(ctrl, dlg);
conf_set_int(conf, CONF_serflow, oldflow);/* restore */
} else if (event == EVENT_SELCHANGE) {
int i = dlg_listbox_index(ctrl, dlg);
if (i < 0)
i = SER_FLOW_NONE;
else
i = dlg_listbox_getid(ctrl, dlg, i);
conf_set_int(conf, CONF_serflow, i);
}
}
void ser_setup_config_box(struct controlbox *b, bool midsession,
int parity_mask, int flow_mask)
{
struct controlset *s;
union control *c;
if (!midsession) {
int i;
/*
* Add the serial back end to the protocols list at the
* top of the config box.
*/
s = ctrl_getset(b, "Session", "hostport",
"Specify the destination you want to connect to");
for (i = 0; i < s->ncontrols; i++) {
c = s->ctrls[i];
if (c->generic.type == CTRL_RADIO &&
c->generic.handler == config_protocolbuttons_handler) {
c->radio.nbuttons++;
c->radio.ncolumns++;
c->radio.buttons =
sresize(c->radio.buttons, c->radio.nbuttons, char *);
c->radio.buttons[c->radio.nbuttons-1] =
dupstr("Serial");
c->radio.buttondata =
sresize(c->radio.buttondata, c->radio.nbuttons, intorptr);
c->radio.buttondata[c->radio.nbuttons-1] = I(PROT_SERIAL);
if (c->radio.shortcuts) {
c->radio.shortcuts =
sresize(c->radio.shortcuts, c->radio.nbuttons, char);
c->radio.shortcuts[c->radio.nbuttons-1] = 'r';
}
}
}
}
/*
* Entirely new Connection/Serial panel for serial port
* configuration.
*/
ctrl_settitle(b, "Connection/Serial",
"Options controlling local serial lines");
if (!midsession) {
/*
* We don't permit switching to a different serial port in
* midflight, although we do allow all other
* reconfiguration.
*/
s = ctrl_getset(b, "Connection/Serial", "serline",
"Select a serial line");
ctrl_editbox(s, "Serial line to connect to", 'l', 40,
HELPCTX(serial_line),
conf_editbox_handler, I(CONF_serline), I(1));
}
s = ctrl_getset(b, "Connection/Serial", "sercfg", "Configure the serial line");
ctrl_editbox(s, "Speed (baud)", 's', 40,
HELPCTX(serial_speed),
conf_editbox_handler, I(CONF_serspeed), I(-1));
ctrl_editbox(s, "Data bits", 'b', 40,
HELPCTX(serial_databits),
conf_editbox_handler, I(CONF_serdatabits), I(-1));
/*
* Stop bits come in units of one half.
*/
ctrl_editbox(s, "Stop bits", 't', 40,
HELPCTX(serial_stopbits),
conf_editbox_handler, I(CONF_serstopbits), I(-2));
ctrl_droplist(s, "Parity", 'p', 40,
HELPCTX(serial_parity),
serial_parity_handler, I(parity_mask));
ctrl_droplist(s, "Flow control", 'f', 40,
HELPCTX(serial_flow),
serial_flow_handler, I(flow_mask));
}
-113
View File
@@ -1,113 +0,0 @@
/*
* DSS key generation.
*/
#include "misc.h"
#include "ssh.h"
#include "mpint.h"
int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
void *pfnparam)
{
/*
* Set up the phase limits for the progress report. We do this
* by passing minus the phase number.
*
* For prime generation: our initial filter finds things
* coprime to everything below 2^16. Computing the product of
* (p-1)/p for all prime p below 2^16 gives about 20.33; so
* among B-bit integers, one in every 20.33 will get through
* the initial filter to be a candidate prime.
*
* Meanwhile, we are searching for primes in the region of 2^B;
* since pi(x) ~ x/log(x), when x is in the region of 2^B, the
* prime density will be d/dx pi(x) ~ 1/log(B), i.e. about
* 1/0.6931B. So the chance of any given candidate being prime
* is 20.33/0.6931B, which is roughly 29.34 divided by B.
*
* So now we have this probability P, we're looking at an
* exponential distribution with parameter P: we will manage in
* one attempt with probability P, in two with probability
* P(1-P), in three with probability P(1-P)^2, etc. The
* probability that we have still not managed to find a prime
* after N attempts is (1-P)^N.
*
* We therefore inform the progress indicator of the number B
* (29.34/B), so that it knows how much to increment by each
* time. We do this in 16-bit fixed point, so 29.34 becomes
* 0x1D.57C4.
*/
pfn(pfnparam, PROGFN_PHASE_EXTENT, 1, 0x2800);
pfn(pfnparam, PROGFN_EXP_PHASE, 1, -0x1D57C4 / 160);
pfn(pfnparam, PROGFN_PHASE_EXTENT, 2, 0x40 * bits);
pfn(pfnparam, PROGFN_EXP_PHASE, 2, -0x1D57C4 / bits);
/*
* In phase three we are finding an order-q element of the
* multiplicative group of p, by finding an element whose order
* is _divisible_ by q and raising it to the power of (p-1)/q.
* _Most_ elements will have order divisible by q, since for a
* start phi(p) of them will be primitive roots. So
* realistically we don't need to set this much below 1 (64K).
* Still, we'll set it to 1/2 (32K) to be on the safe side.
*/
pfn(pfnparam, PROGFN_PHASE_EXTENT, 3, 0x2000);
pfn(pfnparam, PROGFN_EXP_PHASE, 3, -32768);
pfn(pfnparam, PROGFN_READY, 0, 0);
unsigned pfirst, qfirst;
invent_firstbits(&pfirst, &qfirst, 0);
/*
* Generate q: a prime of length 160.
*/
mp_int *q = primegen(160, 2, 2, NULL, 1, pfn, pfnparam, qfirst);
/*
* Now generate p: a prime of length `bits', such that p-1 is
* divisible by q.
*/
mp_int *p = primegen(bits-160, 2, 2, q, 2, pfn, pfnparam, pfirst);
/*
* Next we need g. Raise 2 to the power (p-1)/q modulo p, and
* if that comes out to one then try 3, then 4 and so on. As
* soon as we hit a non-unit (and non-zero!) one, that'll do
* for g.
*/
mp_int *power = mp_div(p, q); /* this is floor(p/q) == (p-1)/q */
mp_int *h = mp_from_integer(1);
int progress = 0;
mp_int *g;
while (1) {
pfn(pfnparam, PROGFN_PROGRESS, 3, ++progress);
g = mp_modpow(h, power, p);
if (mp_hs_integer(g, 2))
break; /* got one */
mp_free(g);
mp_add_integer_into(h, h, 1);
}
mp_free(h);
mp_free(power);
/*
* Now we're nearly done. All we need now is our private key x,
* which should be a number between 1 and q-1 exclusive, and
* our public key y = g^x mod p.
*/
mp_int *two = mp_from_integer(2);
mp_int *qm1 = mp_copy(q);
mp_sub_integer_into(qm1, qm1, 1);
mp_int *x = mp_random_in_range(two, qm1);
mp_free(two);
mp_free(qm1);
key->sshk.vt = &ssh_dss;
key->p = p;
key->q = q;
key->g = g;
key->x = x;
key->y = mp_modpow(key->g, key->x, key->p);
return 1;
}
-275
View File
@@ -1,275 +0,0 @@
#include <assert.h>
#include "ssh.h"
/*
* MD5 implementation for PuTTY. Written directly from the spec by
* Simon Tatham.
*/
typedef struct {
uint32_t h[4];
} MD5_Core_State;
struct MD5Context {
MD5_Core_State core;
unsigned char block[64];
int blkused;
uint64_t len;
BinarySink_IMPLEMENTATION;
};
/* ----------------------------------------------------------------------
* Core MD5 algorithm: processes 16-word blocks into a message digest.
*/
#define F(x,y,z) ( ((x) & (y)) | ((~(x)) & (z)) )
#define G(x,y,z) ( ((x) & (z)) | ((~(z)) & (y)) )
#define H(x,y,z) ( (x) ^ (y) ^ (z) )
#define I(x,y,z) ( (y) ^ ( (x) | ~(z) ) )
#define rol(x,y) ( ((x) << (y)) | (((uint32_t)x) >> (32-y)) )
#define subround(f,w,x,y,z,k,s,ti) \
w = x + rol(w + f(x,y,z) + block[k] + ti, s)
static void MD5_Core_Init(MD5_Core_State * s)
{
s->h[0] = 0x67452301;
s->h[1] = 0xefcdab89;
s->h[2] = 0x98badcfe;
s->h[3] = 0x10325476;
}
static void MD5_Block(MD5_Core_State *s, uint32_t *block)
{
uint32_t a, b, c, d;
a = s->h[0];
b = s->h[1];
c = s->h[2];
d = s->h[3];
subround(F, a, b, c, d, 0, 7, 0xd76aa478);
subround(F, d, a, b, c, 1, 12, 0xe8c7b756);
subround(F, c, d, a, b, 2, 17, 0x242070db);
subround(F, b, c, d, a, 3, 22, 0xc1bdceee);
subround(F, a, b, c, d, 4, 7, 0xf57c0faf);
subround(F, d, a, b, c, 5, 12, 0x4787c62a);
subround(F, c, d, a, b, 6, 17, 0xa8304613);
subround(F, b, c, d, a, 7, 22, 0xfd469501);
subround(F, a, b, c, d, 8, 7, 0x698098d8);
subround(F, d, a, b, c, 9, 12, 0x8b44f7af);
subround(F, c, d, a, b, 10, 17, 0xffff5bb1);
subround(F, b, c, d, a, 11, 22, 0x895cd7be);
subround(F, a, b, c, d, 12, 7, 0x6b901122);
subround(F, d, a, b, c, 13, 12, 0xfd987193);
subround(F, c, d, a, b, 14, 17, 0xa679438e);
subround(F, b, c, d, a, 15, 22, 0x49b40821);
subround(G, a, b, c, d, 1, 5, 0xf61e2562);
subround(G, d, a, b, c, 6, 9, 0xc040b340);
subround(G, c, d, a, b, 11, 14, 0x265e5a51);
subround(G, b, c, d, a, 0, 20, 0xe9b6c7aa);
subround(G, a, b, c, d, 5, 5, 0xd62f105d);
subround(G, d, a, b, c, 10, 9, 0x02441453);
subround(G, c, d, a, b, 15, 14, 0xd8a1e681);
subround(G, b, c, d, a, 4, 20, 0xe7d3fbc8);
subround(G, a, b, c, d, 9, 5, 0x21e1cde6);
subround(G, d, a, b, c, 14, 9, 0xc33707d6);
subround(G, c, d, a, b, 3, 14, 0xf4d50d87);
subround(G, b, c, d, a, 8, 20, 0x455a14ed);
subround(G, a, b, c, d, 13, 5, 0xa9e3e905);
subround(G, d, a, b, c, 2, 9, 0xfcefa3f8);
subround(G, c, d, a, b, 7, 14, 0x676f02d9);
subround(G, b, c, d, a, 12, 20, 0x8d2a4c8a);
subround(H, a, b, c, d, 5, 4, 0xfffa3942);
subround(H, d, a, b, c, 8, 11, 0x8771f681);
subround(H, c, d, a, b, 11, 16, 0x6d9d6122);
subround(H, b, c, d, a, 14, 23, 0xfde5380c);
subround(H, a, b, c, d, 1, 4, 0xa4beea44);
subround(H, d, a, b, c, 4, 11, 0x4bdecfa9);
subround(H, c, d, a, b, 7, 16, 0xf6bb4b60);
subround(H, b, c, d, a, 10, 23, 0xbebfbc70);
subround(H, a, b, c, d, 13, 4, 0x289b7ec6);
subround(H, d, a, b, c, 0, 11, 0xeaa127fa);
subround(H, c, d, a, b, 3, 16, 0xd4ef3085);
subround(H, b, c, d, a, 6, 23, 0x04881d05);
subround(H, a, b, c, d, 9, 4, 0xd9d4d039);
subround(H, d, a, b, c, 12, 11, 0xe6db99e5);
subround(H, c, d, a, b, 15, 16, 0x1fa27cf8);
subround(H, b, c, d, a, 2, 23, 0xc4ac5665);
subround(I, a, b, c, d, 0, 6, 0xf4292244);
subround(I, d, a, b, c, 7, 10, 0x432aff97);
subround(I, c, d, a, b, 14, 15, 0xab9423a7);
subround(I, b, c, d, a, 5, 21, 0xfc93a039);
subround(I, a, b, c, d, 12, 6, 0x655b59c3);
subround(I, d, a, b, c, 3, 10, 0x8f0ccc92);
subround(I, c, d, a, b, 10, 15, 0xffeff47d);
subround(I, b, c, d, a, 1, 21, 0x85845dd1);
subround(I, a, b, c, d, 8, 6, 0x6fa87e4f);
subround(I, d, a, b, c, 15, 10, 0xfe2ce6e0);
subround(I, c, d, a, b, 6, 15, 0xa3014314);
subround(I, b, c, d, a, 13, 21, 0x4e0811a1);
subround(I, a, b, c, d, 4, 6, 0xf7537e82);
subround(I, d, a, b, c, 11, 10, 0xbd3af235);
subround(I, c, d, a, b, 2, 15, 0x2ad7d2bb);
subround(I, b, c, d, a, 9, 21, 0xeb86d391);
s->h[0] += a;
s->h[1] += b;
s->h[2] += c;
s->h[3] += d;
}
/* ----------------------------------------------------------------------
* Outer MD5 algorithm: take an arbitrary length byte string,
* convert it into 16-word blocks with the prescribed padding at
* the end, and pass those blocks to the core MD5 algorithm.
*/
#define BLKSIZE 64
static void MD5_BinarySink_write(BinarySink *bs, const void *data, size_t len);
void MD5Init(struct MD5Context *s)
{
MD5_Core_Init(&s->core);
s->blkused = 0;
s->len = 0;
BinarySink_INIT(s, MD5_BinarySink_write);
}
static void MD5_BinarySink_write(BinarySink *bs, const void *data, size_t len)
{
struct MD5Context *s = BinarySink_DOWNCAST(bs, struct MD5Context);
const unsigned char *q = (const unsigned char *)data;
uint32_t wordblock[16];
uint32_t lenw = len;
int i;
assert(lenw == len);
/*
* Update the length field.
*/
s->len += lenw;
if (s->blkused + len < BLKSIZE) {
/*
* Trivial case: just add to the block.
*/
memcpy(s->block + s->blkused, q, len);
s->blkused += len;
} else {
/*
* We must complete and process at least one block.
*/
while (s->blkused + len >= BLKSIZE) {
memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused);
q += BLKSIZE - s->blkused;
len -= BLKSIZE - s->blkused;
/* Now process the block. Gather bytes little-endian into words */
for (i = 0; i < 16; i++) {
wordblock[i] =
(((uint32_t) s->block[i * 4 + 3]) << 24) |
(((uint32_t) s->block[i * 4 + 2]) << 16) |
(((uint32_t) s->block[i * 4 + 1]) << 8) |
(((uint32_t) s->block[i * 4 + 0]) << 0);
}
MD5_Block(&s->core, wordblock);
s->blkused = 0;
}
memcpy(s->block, q, len);
s->blkused = len;
}
}
void MD5Final(unsigned char output[16], struct MD5Context *s)
{
int i;
unsigned pad;
unsigned char c[64];
uint64_t len;
if (s->blkused >= 56)
pad = 56 + 64 - s->blkused;
else
pad = 56 - s->blkused;
len = (s->len << 3);
memset(c, 0, pad);
c[0] = 0x80;
put_data(s, c, pad);
PUT_64BIT_LSB_FIRST(c, len);
put_data(s, c, 8);
for (i = 0; i < 4; i++) {
output[4 * i + 3] = (s->core.h[i] >> 24) & 0xFF;
output[4 * i + 2] = (s->core.h[i] >> 16) & 0xFF;
output[4 * i + 1] = (s->core.h[i] >> 8) & 0xFF;
output[4 * i + 0] = (s->core.h[i] >> 0) & 0xFF;
}
}
void MD5Simple(void const *p, unsigned len, unsigned char output[16])
{
struct MD5Context s;
MD5Init(&s);
put_data(&s, (unsigned char const *)p, len);
MD5Final(output, &s);
smemclr(&s, sizeof(s));
}
/* ----------------------------------------------------------------------
* Thin abstraction for things where hashes are pluggable.
*/
struct md5_hash {
struct MD5Context state;
ssh_hash hash;
};
static ssh_hash *md5_new(const ssh_hashalg *alg)
{
struct md5_hash *h = snew(struct md5_hash);
MD5Init(&h->state);
h->hash.vt = alg;
BinarySink_DELEGATE_INIT(&h->hash, &h->state);
return &h->hash;
}
static ssh_hash *md5_copy(ssh_hash *hashold)
{
struct md5_hash *hold, *hnew;
ssh_hash *hashnew = md5_new(hashold->vt);
hold = container_of(hashold, struct md5_hash, hash);
hnew = container_of(hashnew, struct md5_hash, hash);
hnew->state = hold->state;
BinarySink_COPIED(&hnew->state);
return hashnew;
}
static void md5_free(ssh_hash *hash)
{
struct md5_hash *h = container_of(hash, struct md5_hash, hash);
smemclr(h, sizeof(*h));
sfree(h);
}
static void md5_final(ssh_hash *hash, unsigned char *output)
{
struct md5_hash *h = container_of(hash, struct md5_hash, hash);
MD5Final(output, &h->state);
md5_free(hash);
}
const ssh_hashalg ssh_md5 = {
md5_new, md5_copy, md5_final, md5_free, 16, 64, HASHALG_NAMES_BARE("MD5"),
};
-477
View File
@@ -1,477 +0,0 @@
/*
* Prime generation.
*/
#include <assert.h>
#include "ssh.h"
#include "mpint.h"
/*
* This prime generation algorithm is pretty much cribbed from
* OpenSSL. The algorithm is:
*
* - invent a B-bit random number and ensure the top and bottom
* bits are set (so it's definitely B-bit, and it's definitely
* odd)
*
* - see if it's coprime to all primes below 2^16; increment it by
* two until it is (this shouldn't take long in general)
*
* - perform the Miller-Rabin primality test enough times to
* ensure the probability of it being composite is 2^-80 or
* less
*
* - go back to square one if any M-R test fails.
*/
/*
* The Miller-Rabin primality test is an extension to the Fermat
* test. The Fermat test just checks that a^(p-1) == 1 mod p; this
* is vulnerable to Carmichael numbers. Miller-Rabin considers how
* that 1 is derived as well.
*
* Lemma: if a^2 == 1 (mod p), and p is prime, then either a == 1
* or a == -1 (mod p).
*
* Proof: p divides a^2-1, i.e. p divides (a+1)(a-1). Hence,
* since p is prime, either p divides (a+1) or p divides (a-1).
* But this is the same as saying that either a is congruent to
* -1 mod p or a is congruent to +1 mod p. []
*
* Comment: This fails when p is not prime. Consider p=mn, so
* that mn divides (a+1)(a-1). Now we could have m dividing (a+1)
* and n dividing (a-1), without the whole of mn dividing either.
* For example, consider a=10 and p=99. 99 = 9 * 11; 9 divides
* 10-1 and 11 divides 10+1, so a^2 is congruent to 1 mod p
* without a having to be congruent to either 1 or -1.
*
* So the Miller-Rabin test, as well as considering a^(p-1),
* considers a^((p-1)/2), a^((p-1)/4), and so on as far as it can
* go. In other words. we write p-1 as q * 2^k, with k as large as
* possible (i.e. q must be odd), and we consider the powers
*
* a^(q*2^0) a^(q*2^1) ... a^(q*2^(k-1)) a^(q*2^k)
* i.e. a^((n-1)/2^k) a^((n-1)/2^(k-1)) ... a^((n-1)/2) a^(n-1)
*
* If p is to be prime, the last of these must be 1. Therefore, by
* the above lemma, the one before it must be either 1 or -1. And
* _if_ it's 1, then the one before that must be either 1 or -1,
* and so on ... In other words, we expect to see a trailing chain
* of 1s preceded by a -1. (If we're unlucky, our trailing chain of
* 1s will be as long as the list so we'll never get to see what
* lies before it. This doesn't count as a test failure because it
* hasn't _proved_ that p is not prime.)
*
* For example, consider a=2 and p=1729. 1729 is a Carmichael
* number: although it's not prime, it satisfies a^(p-1) == 1 mod p
* for any a coprime to it. So the Fermat test wouldn't have a
* problem with it at all, unless we happened to stumble on an a
* which had a common factor.
*
* So. 1729 - 1 equals 27 * 2^6. So we look at
*
* 2^27 mod 1729 == 645
* 2^108 mod 1729 == 1065
* 2^216 mod 1729 == 1
* 2^432 mod 1729 == 1
* 2^864 mod 1729 == 1
* 2^1728 mod 1729 == 1
*
* We do have a trailing string of 1s, so the Fermat test would
* have been happy. But this trailing string of 1s is preceded by
* 1065; whereas if 1729 were prime, we'd expect to see it preceded
* by -1 (i.e. 1728.). Guards! Seize this impostor.
*
* (If we were unlucky, we might have tried a=16 instead of a=2;
* now 16^27 mod 1729 == 1, so we would have seen a long string of
* 1s and wouldn't have seen the thing _before_ the 1s. So, just
* like the Fermat test, for a given p there may well exist values
* of a which fail to show up its compositeness. So we try several,
* just like the Fermat test. The difference is that Miller-Rabin
* is not _in general_ fooled by Carmichael numbers.)
*
* Put simply, then, the Miller-Rabin test requires us to:
*
* 1. write p-1 as q * 2^k, with q odd
* 2. compute z = (a^q) mod p.
* 3. report success if z == 1 or z == -1.
* 4. square z at most k-1 times, and report success if it becomes
* -1 at any point.
* 5. report failure otherwise.
*
* (We expect z to become -1 after at most k-1 squarings, because
* if it became -1 after k squarings then a^(p-1) would fail to be
* 1. And we don't need to investigate what happens after we see a
* -1, because we _know_ that -1 squared is 1 modulo anything at
* all, so after we've seen a -1 we can be sure of seeing nothing
* but 1s.)
*/
static unsigned short primes[6542]; /* # primes < 65536 */
#define NPRIMES (lenof(primes))
static void init_primes_array(void)
{
if (primes[0])
return; /* already done */
bool A[65536];
for (size_t i = 2; i < lenof(A); i++)
A[i] = true;
for (size_t i = 2; i < lenof(A); i++) {
if (!A[i])
continue;
for (size_t j = 2*i; j < lenof(A); j += i)
A[j] = false;
}
size_t pos = 0;
for (size_t i = 2; i < lenof(A); i++)
if (A[i])
primes[pos++] = i;
assert(pos == NPRIMES);
}
static unsigned short mp_mod_short(mp_int *x, unsigned short modulus)
{
/*
* This function lives here rather than in mpint.c partly because
* this is the only place it's needed, but mostly because it
* doesn't pay careful attention to constant running time, since
* as far as I can tell that's a lost cause for key generation
* anyway.
*/
unsigned accumulator = 0;
for (size_t i = mp_max_bytes(x); i-- > 0 ;) {
accumulator = 0x100 * accumulator + mp_get_byte(x, i);
accumulator %= modulus;
}
return accumulator;
}
/*
* Generate a prime. We can deal with various extra properties of
* the prime:
*
* - to speed up use in RSA, we can arrange to select a prime with
* the property (prime % modulus) != residue.
*
* - for use in DSA, we can arrange to select a prime which is one
* more than a multiple of a dirty great bignum. In this case
* `bits' gives the size of the factor by which we _multiply_
* that bignum, rather than the size of the whole number.
*
* - for the basically cosmetic purposes of generating keys of the
* length actually specified rather than off by one bit, we permit
* the caller to provide an unsigned integer 'firstbits' which will
* match the top few bits of the returned prime. (That is, there
* will exist some n such that (returnvalue >> n) == firstbits.) If
* 'firstbits' is not needed, specifying it to either 0 or 1 is
* an adequate no-op.
*/
mp_int *primegen(
int bits, int modulus, int residue, mp_int *factor,
int phase, progfn_t pfn, void *pfnparam, unsigned firstbits)
{
init_primes_array();
int progress = 0;
size_t fbsize = 0;
while (firstbits >> fbsize) /* work out how to align this */
fbsize++;
STARTOVER:
pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress);
/*
* Generate a k-bit random number with top and bottom bits set.
* Alternatively, if `factor' is nonzero, generate a k-bit
* random number with the top bit set and the bottom bit clear,
* multiply it by `factor', and add one.
*/
mp_int *p = mp_power_2(bits - 1); /* ensure top bit is 1 */
mp_int *r = mp_random_bits(bits - 1);
mp_or_into(p, p, r);
mp_free(r);
mp_set_bit(p, 0, factor ? 0 : 1); /* set bottom bit appropriately */
for (size_t i = 0; i < fbsize; i++)
mp_set_bit(p, bits-fbsize + i, 1 & (firstbits >> i));
if (factor) {
mp_int *tmp = p;
p = mp_mul(tmp, factor);
mp_free(tmp);
assert(mp_get_bit(p, 0) == 0);
mp_set_bit(p, 0, 1);
}
/*
* We need to ensure this random number is coprime to the first
* few primes, by repeatedly adding either 2 or 2*factor to it
* until it is. To do this we make a list of (modulus, residue)
* pairs to avoid, and we also add to that list the extra pair our
* caller wants to avoid.
*/
/* List the moduli */
unsigned long moduli[NPRIMES + 1];
for (size_t i = 0; i < NPRIMES; i++)
moduli[i] = primes[i];
moduli[NPRIMES] = modulus;
/* Find the residue of our starting number mod each of them. Also
* set up the multipliers array which tells us how each one will
* change when we increment the number (which isn't just 1 if
* we're incrementing by multiples of factor). */
unsigned long residues[NPRIMES + 1], multipliers[NPRIMES + 1];
for (size_t i = 0; i < lenof(moduli); i++) {
residues[i] = mp_mod_short(p, moduli[i]);
if (factor)
multipliers[i] = mp_mod_short(factor, moduli[i]);
else
multipliers[i] = 1;
}
/* Adjust the last entry so that it avoids a residue other than zero */
residues[NPRIMES] = (residues[NPRIMES] + modulus - residue) % modulus;
/*
* Now loop until no residue in that list is zero, to find a
* sensible increment. We maintain the increment in an ordinary
* integer, so if it gets too big, we'll have to give up and go
* back to making up a fresh random large integer.
*/
unsigned delta = 0;
while (1) {
for (size_t i = 0; i < lenof(moduli); i++)
if (!((residues[i] + delta * multipliers[i]) % moduli[i]))
goto found_a_zero;
/* If we didn't exit that loop by goto, we've got our candidate. */
break;
found_a_zero:
delta += 2;
if (delta > 65536) {
mp_free(p);
goto STARTOVER;
}
}
/*
* Having found a plausible increment, actually add it on.
*/
if (factor) {
mp_int *d = mp_from_integer(delta);
mp_int *df = mp_mul(d, factor);
mp_add_into(p, p, df);
mp_free(d);
mp_free(df);
} else {
mp_add_integer_into(p, p, delta);
}
/*
* Now apply the Miller-Rabin primality test a few times. First
* work out how many checks are needed.
*/
unsigned checks =
bits >= 1300 ? 2 : bits >= 850 ? 3 : bits >= 650 ? 4 :
bits >= 550 ? 5 : bits >= 450 ? 6 : bits >= 400 ? 7 :
bits >= 350 ? 8 : bits >= 300 ? 9 : bits >= 250 ? 12 :
bits >= 200 ? 15 : bits >= 150 ? 18 : 27;
/*
* Next, write p-1 as q*2^k.
*/
size_t k;
for (k = 0; mp_get_bit(p, k) == !k; k++)
continue; /* find first 1 bit in p-1 */
mp_int *q = mp_rshift_safe(p, k);
/*
* Set up stuff for the Miller-Rabin checks.
*/
mp_int *two = mp_from_integer(2);
mp_int *pm1 = mp_copy(p);
mp_sub_integer_into(pm1, pm1, 1);
MontyContext *mc = monty_new(p);
mp_int *m_pm1 = monty_import(mc, pm1);
bool known_bad = false;
/*
* Now, for each check ...
*/
for (unsigned check = 0; check < checks && !known_bad; check++) {
/*
* Invent a random number between 1 and p-1.
*/
mp_int *w = mp_random_in_range(two, pm1);
monty_import_into(mc, w, w);
pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress);
/*
* Compute w^q mod p.
*/
mp_int *wqp = monty_pow(mc, w, q);
mp_free(w);
/*
* See if this is 1, or if it is -1, or if it becomes -1
* when squared at most k-1 times.
*/
bool passed = false;
if (mp_cmp_eq(wqp, monty_identity(mc)) || mp_cmp_eq(wqp, m_pm1)) {
passed = true;
} else {
for (size_t i = 0; i < k - 1; i++) {
monty_mul_into(mc, wqp, wqp, wqp);
if (mp_cmp_eq(wqp, m_pm1)) {
passed = true;
break;
}
}
}
if (!passed)
known_bad = true;
mp_free(wqp);
}
mp_free(q);
mp_free(two);
mp_free(pm1);
monty_free(mc);
mp_free(m_pm1);
if (known_bad) {
mp_free(p);
goto STARTOVER;
}
/*
* We have a prime!
*/
return p;
}
/*
* Invent a pair of values suitable for use as 'firstbits' in the
* above function, such that their product is at least 2, and such
* that their difference is also at least min_separation.
*
* This is used for generating both RSA and DSA keys which have
* exactly the specified number of bits rather than one fewer - if you
* generate an a-bit and a b-bit number completely at random and
* multiply them together, you could end up with either an (ab-1)-bit
* number or an (ab)-bit number. The former happens log(2)*2-1 of the
* time (about 39%) and, though actually harmless, every time it
* occurs it has a non-zero probability of sparking a user email along
* the lines of 'Hey, I asked PuTTYgen for a 2048-bit key and I only
* got 2047 bits! Bug!'
*/
static inline unsigned firstbits_b_min(
unsigned a, unsigned lo, unsigned hi, unsigned min_separation)
{
/* To get a large enough product, b must be at least this much */
unsigned b_min = (2*lo*lo + a - 1) / a;
/* Now enforce a<b, optionally with minimum separation */
if (b_min < a + min_separation)
b_min = a + min_separation;
/* And cap at the upper limit */
if (b_min > hi)
b_min = hi;
return b_min;
}
void invent_firstbits(unsigned *one, unsigned *two, unsigned min_separation)
{
/*
* We'll pick 12 initial bits (number selected at random) for each
* prime, not counting the leading 1. So we want to return two
* values in the range [2^12,2^13) whose product is at least 2^25.
*
* Strategy: count up all the viable pairs, then select a random
* number in that range and use it to pick a pair.
*
* To keep things simple, we'll ensure a < b, and randomly swap
* them at the end.
*/
const unsigned lo = 1<<12, hi = 1<<13, minproduct = 2*lo*lo;
unsigned a, b;
/*
* Count up the number of prefixes of b that would be valid for
* each prefix of a.
*/
mp_int *total = mp_new(32);
for (a = lo; a < hi; a++) {
unsigned b_min = firstbits_b_min(a, lo, hi, min_separation);
mp_add_integer_into(total, total, hi - b_min);
}
/*
* Make up a random number in the range [0,2*total).
*/
mp_int *mlo = mp_from_integer(0), *mhi = mp_new(32);
mp_lshift_fixed_into(mhi, total, 1);
mp_int *randval = mp_random_in_range(mlo, mhi);
mp_free(mlo);
mp_free(mhi);
/*
* Use the low bit of randval as our swap indicator, leaving the
* rest of it in the range [0,total).
*/
unsigned swap = mp_get_bit(randval, 0);
mp_rshift_fixed_into(randval, randval, 1);
/*
* Now do the same counting loop again to make the actual choice.
*/
a = b = 0;
for (unsigned a_candidate = lo; a_candidate < hi; a_candidate++) {
unsigned b_min = firstbits_b_min(a_candidate, lo, hi, min_separation);
unsigned limit = hi - b_min;
unsigned b_candidate = b_min + mp_get_integer(randval);
unsigned use_it = 1 ^ mp_hs_integer(randval, limit);
a ^= (a ^ a_candidate) & -use_it;
b ^= (b ^ b_candidate) & -use_it;
mp_sub_integer_into(randval, randval, limit);
}
mp_free(randval);
mp_free(total);
/*
* Check everything came out right.
*/
assert(lo <= a);
assert(a < hi);
assert(lo <= b);
assert(b < hi);
assert(a * b >= minproduct);
assert(b >= a + min_separation);
/*
* Last-minute optional swap of a and b.
*/
unsigned diff = (a ^ b) & (-swap);
a ^= diff;
b ^= diff;
*one = a;
*two = b;
}
File diff suppressed because it is too large Load Diff
-128
View File
@@ -1,128 +0,0 @@
/*
* RSA key generation.
*/
#include <assert.h>
#include "ssh.h"
#include "mpint.h"
#define RSA_EXPONENT 37 /* we like this prime */
int rsa_generate(RSAKey *key, int bits, progfn_t pfn,
void *pfnparam)
{
unsigned pfirst, qfirst;
key->sshk.vt = &ssh_rsa;
/*
* Set up the phase limits for the progress report. We do this
* by passing minus the phase number.
*
* For prime generation: our initial filter finds things
* coprime to everything below 2^16. Computing the product of
* (p-1)/p for all prime p below 2^16 gives about 20.33; so
* among B-bit integers, one in every 20.33 will get through
* the initial filter to be a candidate prime.
*
* Meanwhile, we are searching for primes in the region of 2^B;
* since pi(x) ~ x/log(x), when x is in the region of 2^B, the
* prime density will be d/dx pi(x) ~ 1/log(B), i.e. about
* 1/0.6931B. So the chance of any given candidate being prime
* is 20.33/0.6931B, which is roughly 29.34 divided by B.
*
* So now we have this probability P, we're looking at an
* exponential distribution with parameter P: we will manage in
* one attempt with probability P, in two with probability
* P(1-P), in three with probability P(1-P)^2, etc. The
* probability that we have still not managed to find a prime
* after N attempts is (1-P)^N.
*
* We therefore inform the progress indicator of the number B
* (29.34/B), so that it knows how much to increment by each
* time. We do this in 16-bit fixed point, so 29.34 becomes
* 0x1D.57C4.
*/
pfn(pfnparam, PROGFN_PHASE_EXTENT, 1, 0x10000);
pfn(pfnparam, PROGFN_EXP_PHASE, 1, -0x1D57C4 / (bits / 2));
pfn(pfnparam, PROGFN_PHASE_EXTENT, 2, 0x10000);
pfn(pfnparam, PROGFN_EXP_PHASE, 2, -0x1D57C4 / (bits - bits / 2));
pfn(pfnparam, PROGFN_PHASE_EXTENT, 3, 0x4000);
pfn(pfnparam, PROGFN_LIN_PHASE, 3, 5);
pfn(pfnparam, PROGFN_READY, 0, 0);
/*
* We don't generate e; we just use a standard one always.
*/
mp_int *exponent = mp_from_integer(RSA_EXPONENT);
/*
* Generate p and q: primes with combined length `bits', not
* congruent to 1 modulo e. (Strictly speaking, we wanted (p-1)
* and e to be coprime, and (q-1) and e to be coprime, but in
* general that's slightly more fiddly to arrange. By choosing
* a prime e, we can simplify the criterion.)
*
* We give a min_separation of 2 to invent_firstbits(), ensuring
* that the two primes won't be very close to each other. (The
* chance of them being _dangerously_ close is negligible - even
* more so than an attacker guessing a whole 256-bit session key -
* but it doesn't cost much to make sure.)
*/
invent_firstbits(&pfirst, &qfirst, 2);
int qbits = bits / 2;
int pbits = bits - qbits;
assert(pbits >= qbits);
mp_int *p = primegen(pbits, RSA_EXPONENT, 1, NULL,
1, pfn, pfnparam, pfirst);
mp_int *q = primegen(qbits, RSA_EXPONENT, 1, NULL,
2, pfn, pfnparam, qfirst);
/*
* Ensure p > q, by swapping them if not.
*
* We only need to do this if the two primes were generated with
* the same number of bits (i.e. if the requested key size is
* even) - otherwise it's already guaranteed!
*/
if (pbits == qbits) {
mp_cond_swap(p, q, mp_cmp_hs(q, p));
} else {
assert(mp_cmp_hs(p, q));
}
/*
* Now we have p, q and e. All we need to do now is work out
* the other helpful quantities: n=pq, d=e^-1 mod (p-1)(q-1),
* and (q^-1 mod p).
*/
pfn(pfnparam, PROGFN_PROGRESS, 3, 1);
mp_int *modulus = mp_mul(p, q);
pfn(pfnparam, PROGFN_PROGRESS, 3, 2);
mp_int *pm1 = mp_copy(p);
mp_sub_integer_into(pm1, pm1, 1);
mp_int *qm1 = mp_copy(q);
mp_sub_integer_into(qm1, qm1, 1);
mp_int *phi_n = mp_mul(pm1, qm1);
pfn(pfnparam, PROGFN_PROGRESS, 3, 3);
mp_free(pm1);
mp_free(qm1);
mp_int *private_exponent = mp_invert(exponent, phi_n);
pfn(pfnparam, PROGFN_PROGRESS, 3, 4);
mp_free(phi_n);
mp_int *iqmp = mp_invert(q, p);
pfn(pfnparam, PROGFN_PROGRESS, 3, 5);
/*
* Populate the returned structure.
*/
key->modulus = modulus;
key->exponent = exponent;
key->private_exponent = private_exponent;
key->p = p;
key->q = q;
key->iqmp = iqmp;
return 1;
}
-369
View File
@@ -1,369 +0,0 @@
/*
* SHA-512 algorithm as described at
*
* http://csrc.nist.gov/cryptval/shs.html
*
* Modifications made for SHA-384 also
*/
#include <assert.h>
#include "ssh.h"
#define BLKSIZE 128
typedef struct {
uint64_t h[8];
unsigned char block[BLKSIZE];
int blkused;
uint64_t lenhi, lenlo;
BinarySink_IMPLEMENTATION;
} SHA512_State;
/*
* Arithmetic implementations. Note that AND, XOR and NOT can
* overlap destination with one source, but the others can't.
*/
#define add(r,x,y) ( r = (x) + (y) )
#define rorB(r,x,y) ( r = ((x) >> (y)) | ((x) << (64-(y))) )
#define rorL(r,x,y) ( r = ((x) >> (y)) | ((x) << (64-(y))) )
#define shrB(r,x,y) ( r = (x) >> (y) )
#define shrL(r,x,y) ( r = (x) >> (y) )
#define and(r,x,y) ( r = (x) & (y) )
#define xor(r,x,y) ( r = (x) ^ (y) )
#define not(r,x) ( r = ~(x) )
#define INIT(h,l) ((((uint64_t)(h)) << 32) | (l))
#define BUILD(r,h,l) ( r = ((((uint64_t)(h)) << 32) | (l)) )
#define EXTRACT(h,l,r) ( h = (r) >> 32, l = (r) & 0xFFFFFFFFU )
/* ----------------------------------------------------------------------
* Core SHA512 algorithm: processes 16-doubleword blocks into a
* message digest.
*/
#define Ch(r,t,x,y,z) ( not(t,x), and(r,t,z), and(t,x,y), xor(r,r,t) )
#define Maj(r,t,x,y,z) ( and(r,x,y), and(t,x,z), xor(r,r,t), \
and(t,y,z), xor(r,r,t) )
#define bigsigma0(r,t,x) ( rorL(r,x,28), rorB(t,x,34), xor(r,r,t), \
rorB(t,x,39), xor(r,r,t) )
#define bigsigma1(r,t,x) ( rorL(r,x,14), rorL(t,x,18), xor(r,r,t), \
rorB(t,x,41), xor(r,r,t) )
#define smallsigma0(r,t,x) ( rorL(r,x,1), rorL(t,x,8), xor(r,r,t), \
shrL(t,x,7), xor(r,r,t) )
#define smallsigma1(r,t,x) ( rorL(r,x,19), rorB(t,x,61), xor(r,r,t), \
shrL(t,x,6), xor(r,r,t) )
static void SHA512_Core_Init(SHA512_State *s) {
static const uint64_t iv[] = {
INIT(0x6a09e667, 0xf3bcc908),
INIT(0xbb67ae85, 0x84caa73b),
INIT(0x3c6ef372, 0xfe94f82b),
INIT(0xa54ff53a, 0x5f1d36f1),
INIT(0x510e527f, 0xade682d1),
INIT(0x9b05688c, 0x2b3e6c1f),
INIT(0x1f83d9ab, 0xfb41bd6b),
INIT(0x5be0cd19, 0x137e2179),
};
int i;
for (i = 0; i < 8; i++)
s->h[i] = iv[i];
}
static void SHA384_Core_Init(SHA512_State *s) {
static const uint64_t iv[] = {
INIT(0xcbbb9d5d, 0xc1059ed8),
INIT(0x629a292a, 0x367cd507),
INIT(0x9159015a, 0x3070dd17),
INIT(0x152fecd8, 0xf70e5939),
INIT(0x67332667, 0xffc00b31),
INIT(0x8eb44a87, 0x68581511),
INIT(0xdb0c2e0d, 0x64f98fa7),
INIT(0x47b5481d, 0xbefa4fa4),
};
int i;
for (i = 0; i < 8; i++)
s->h[i] = iv[i];
}
static void SHA512_Block(SHA512_State *s, uint64_t *block) {
uint64_t w[80];
uint64_t a,b,c,d,e,f,g,h;
static const uint64_t k[] = {
INIT(0x428a2f98, 0xd728ae22), INIT(0x71374491, 0x23ef65cd),
INIT(0xb5c0fbcf, 0xec4d3b2f), INIT(0xe9b5dba5, 0x8189dbbc),
INIT(0x3956c25b, 0xf348b538), INIT(0x59f111f1, 0xb605d019),
INIT(0x923f82a4, 0xaf194f9b), INIT(0xab1c5ed5, 0xda6d8118),
INIT(0xd807aa98, 0xa3030242), INIT(0x12835b01, 0x45706fbe),
INIT(0x243185be, 0x4ee4b28c), INIT(0x550c7dc3, 0xd5ffb4e2),
INIT(0x72be5d74, 0xf27b896f), INIT(0x80deb1fe, 0x3b1696b1),
INIT(0x9bdc06a7, 0x25c71235), INIT(0xc19bf174, 0xcf692694),
INIT(0xe49b69c1, 0x9ef14ad2), INIT(0xefbe4786, 0x384f25e3),
INIT(0x0fc19dc6, 0x8b8cd5b5), INIT(0x240ca1cc, 0x77ac9c65),
INIT(0x2de92c6f, 0x592b0275), INIT(0x4a7484aa, 0x6ea6e483),
INIT(0x5cb0a9dc, 0xbd41fbd4), INIT(0x76f988da, 0x831153b5),
INIT(0x983e5152, 0xee66dfab), INIT(0xa831c66d, 0x2db43210),
INIT(0xb00327c8, 0x98fb213f), INIT(0xbf597fc7, 0xbeef0ee4),
INIT(0xc6e00bf3, 0x3da88fc2), INIT(0xd5a79147, 0x930aa725),
INIT(0x06ca6351, 0xe003826f), INIT(0x14292967, 0x0a0e6e70),
INIT(0x27b70a85, 0x46d22ffc), INIT(0x2e1b2138, 0x5c26c926),
INIT(0x4d2c6dfc, 0x5ac42aed), INIT(0x53380d13, 0x9d95b3df),
INIT(0x650a7354, 0x8baf63de), INIT(0x766a0abb, 0x3c77b2a8),
INIT(0x81c2c92e, 0x47edaee6), INIT(0x92722c85, 0x1482353b),
INIT(0xa2bfe8a1, 0x4cf10364), INIT(0xa81a664b, 0xbc423001),
INIT(0xc24b8b70, 0xd0f89791), INIT(0xc76c51a3, 0x0654be30),
INIT(0xd192e819, 0xd6ef5218), INIT(0xd6990624, 0x5565a910),
INIT(0xf40e3585, 0x5771202a), INIT(0x106aa070, 0x32bbd1b8),
INIT(0x19a4c116, 0xb8d2d0c8), INIT(0x1e376c08, 0x5141ab53),
INIT(0x2748774c, 0xdf8eeb99), INIT(0x34b0bcb5, 0xe19b48a8),
INIT(0x391c0cb3, 0xc5c95a63), INIT(0x4ed8aa4a, 0xe3418acb),
INIT(0x5b9cca4f, 0x7763e373), INIT(0x682e6ff3, 0xd6b2b8a3),
INIT(0x748f82ee, 0x5defb2fc), INIT(0x78a5636f, 0x43172f60),
INIT(0x84c87814, 0xa1f0ab72), INIT(0x8cc70208, 0x1a6439ec),
INIT(0x90befffa, 0x23631e28), INIT(0xa4506ceb, 0xde82bde9),
INIT(0xbef9a3f7, 0xb2c67915), INIT(0xc67178f2, 0xe372532b),
INIT(0xca273ece, 0xea26619c), INIT(0xd186b8c7, 0x21c0c207),
INIT(0xeada7dd6, 0xcde0eb1e), INIT(0xf57d4f7f, 0xee6ed178),
INIT(0x06f067aa, 0x72176fba), INIT(0x0a637dc5, 0xa2c898a6),
INIT(0x113f9804, 0xbef90dae), INIT(0x1b710b35, 0x131c471b),
INIT(0x28db77f5, 0x23047d84), INIT(0x32caab7b, 0x40c72493),
INIT(0x3c9ebe0a, 0x15c9bebc), INIT(0x431d67c4, 0x9c100d4c),
INIT(0x4cc5d4be, 0xcb3e42b6), INIT(0x597f299c, 0xfc657e2a),
INIT(0x5fcb6fab, 0x3ad6faec), INIT(0x6c44198c, 0x4a475817),
};
int t;
for (t = 0; t < 16; t++)
w[t] = block[t];
for (t = 16; t < 80; t++) {
uint64_t p, q, r, tmp;
smallsigma1(p, tmp, w[t-2]);
smallsigma0(q, tmp, w[t-15]);
add(r, p, q);
add(p, r, w[t-7]);
add(w[t], p, w[t-16]);
}
a = s->h[0]; b = s->h[1]; c = s->h[2]; d = s->h[3];
e = s->h[4]; f = s->h[5]; g = s->h[6]; h = s->h[7];
for (t = 0; t < 80; t+=8) {
uint64_t tmp, p, q, r;
#define ROUND(j,a,b,c,d,e,f,g,h) \
bigsigma1(p, tmp, e); \
Ch(q, tmp, e, f, g); \
add(r, p, q); \
add(p, r, k[j]) ; \
add(q, p, w[j]); \
add(r, q, h); \
bigsigma0(p, tmp, a); \
Maj(tmp, q, a, b, c); \
add(q, tmp, p); \
add(p, r, d); \
d = p; \
add(h, q, r);
ROUND(t+0, a,b,c,d,e,f,g,h);
ROUND(t+1, h,a,b,c,d,e,f,g);
ROUND(t+2, g,h,a,b,c,d,e,f);
ROUND(t+3, f,g,h,a,b,c,d,e);
ROUND(t+4, e,f,g,h,a,b,c,d);
ROUND(t+5, d,e,f,g,h,a,b,c);
ROUND(t+6, c,d,e,f,g,h,a,b);
ROUND(t+7, b,c,d,e,f,g,h,a);
}
{
uint64_t tmp;
#define UPDATE(state, local) ( tmp = state, add(state, tmp, local) )
UPDATE(s->h[0], a); UPDATE(s->h[1], b);
UPDATE(s->h[2], c); UPDATE(s->h[3], d);
UPDATE(s->h[4], e); UPDATE(s->h[5], f);
UPDATE(s->h[6], g); UPDATE(s->h[7], h);
}
}
/* ----------------------------------------------------------------------
* Outer SHA512 algorithm: take an arbitrary length byte string,
* convert it into 16-doubleword blocks with the prescribed padding
* at the end, and pass those blocks to the core SHA512 algorithm.
*/
static void SHA512_BinarySink_write(BinarySink *bs,
const void *p, size_t len);
void SHA512_Init(SHA512_State *s) {
SHA512_Core_Init(s);
s->blkused = 0;
s->lenhi = s->lenlo = 0;
BinarySink_INIT(s, SHA512_BinarySink_write);
}
void SHA384_Init(SHA512_State *s) {
SHA384_Core_Init(s);
s->blkused = 0;
s->lenhi = s->lenlo = 0;
BinarySink_INIT(s, SHA512_BinarySink_write);
}
static void SHA512_BinarySink_write(BinarySink *bs,
const void *p, size_t len)
{
SHA512_State *s = BinarySink_DOWNCAST(bs, SHA512_State);
unsigned char *q = (unsigned char *)p;
uint64_t wordblock[16];
int i;
/*
* Update the length field.
*/
s->lenlo += len;
s->lenhi += (s->lenlo < len);
if (s->blkused && s->blkused+len < BLKSIZE) {
/*
* Trivial case: just add to the block.
*/
memcpy(s->block + s->blkused, q, len);
s->blkused += len;
} else {
/*
* We must complete and process at least one block.
*/
while (s->blkused + len >= BLKSIZE) {
memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused);
q += BLKSIZE - s->blkused;
len -= BLKSIZE - s->blkused;
/* Now process the block. Gather bytes big-endian into words */
for (i = 0; i < 16; i++)
wordblock[i] = GET_64BIT_MSB_FIRST(s->block + i*8);
SHA512_Block(s, wordblock);
s->blkused = 0;
}
memcpy(s->block, q, len);
s->blkused = len;
}
}
void SHA512_Final(SHA512_State *s, unsigned char *digest) {
int i;
int pad;
unsigned char c[BLKSIZE];
uint64_t lenhi, lenlo;
if (s->blkused >= BLKSIZE-16)
pad = (BLKSIZE-16) + BLKSIZE - s->blkused;
else
pad = (BLKSIZE-16) - s->blkused;
lenhi = (s->lenhi << 3) | (s->lenlo >> (32-3));
lenlo = (s->lenlo << 3);
memset(c, 0, pad);
c[0] = 0x80;
put_data(s, &c, pad);
put_uint64(s, lenhi);
put_uint64(s, lenlo);
for (i = 0; i < 8; i++)
PUT_64BIT_MSB_FIRST(digest + i*8, s->h[i]);
}
void SHA384_Final(SHA512_State *s, unsigned char *digest) {
unsigned char biggerDigest[512 / 8];
SHA512_Final(s, biggerDigest);
memcpy(digest, biggerDigest, 384 / 8);
}
void SHA512_Simple(const void *p, int len, unsigned char *output) {
SHA512_State s;
SHA512_Init(&s);
put_data(&s, p, len);
SHA512_Final(&s, output);
smemclr(&s, sizeof(s));
}
void SHA384_Simple(const void *p, int len, unsigned char *output) {
SHA512_State s;
SHA384_Init(&s);
put_data(&s, p, len);
SHA384_Final(&s, output);
smemclr(&s, sizeof(s));
}
/*
* Thin abstraction for things where hashes are pluggable.
*/
struct sha512_hash {
SHA512_State state;
ssh_hash hash;
};
static ssh_hash *sha512_new(const ssh_hashalg *alg)
{
struct sha512_hash *h = snew(struct sha512_hash);
SHA512_Init(&h->state);
h->hash.vt = alg;
BinarySink_DELEGATE_INIT(&h->hash, &h->state);
return &h->hash;
}
static ssh_hash *sha512_copy(ssh_hash *hashold)
{
struct sha512_hash *hold, *hnew;
ssh_hash *hashnew = sha512_new(hashold->vt);
hold = container_of(hashold, struct sha512_hash, hash);
hnew = container_of(hashnew, struct sha512_hash, hash);
hnew->state = hold->state;
BinarySink_COPIED(&hnew->state);
return hashnew;
}
static void sha512_free(ssh_hash *hash)
{
struct sha512_hash *h = container_of(hash, struct sha512_hash, hash);
smemclr(h, sizeof(*h));
sfree(h);
}
static void sha512_final(ssh_hash *hash, unsigned char *output)
{
struct sha512_hash *h = container_of(hash, struct sha512_hash, hash);
SHA512_Final(&h->state, output);
sha512_free(hash);
}
const ssh_hashalg ssh_sha512 = {
sha512_new, sha512_copy, sha512_final, sha512_free,
64, BLKSIZE, HASHALG_NAMES_BARE("SHA-512"),
};
static ssh_hash *sha384_new(const ssh_hashalg *alg)
{
struct sha512_hash *h = snew(struct sha512_hash);
SHA384_Init(&h->state);
h->hash.vt = alg;
BinarySink_DELEGATE_INIT(&h->hash, &h->state);
return &h->hash;
}
static void sha384_final(ssh_hash *hash, unsigned char *output)
{
struct sha512_hash *h = container_of(hash, struct sha512_hash, hash);
SHA384_Final(&h->state, output);
sha512_free(hash);
}
const ssh_hashalg ssh_sha384 = {
sha384_new, sha512_copy, sha384_final, sha512_free,
48, BLKSIZE, HASHALG_NAMES_BARE("SHA-384"),
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-5
View File
@@ -1,5 +0,0 @@
#define RELEASE 0.73
#define TEXTVER "Release 0.73"
#define SSHVER "-Release-0.73"
#define BINARY_VERSION 0,73,2,17
#define SOURCE_COMMIT "unavailable"
-91
View File
@@ -1,91 +0,0 @@
/*
* Windows resources for Pageant.
*/
#include "rcstuff.h"
#ifdef MOD_INTEGRATED_AGENT
#define APPNAME_AGENT "Kageant"
#define APPDESC_AGENT "KiTTY SSH authentication agent"
#else
#define APPNAME "Pageant"
#define APPDESC "PuTTY SSH authentication agent"
#endif
#include "winhelp.rc2"
#ifdef MOD_INTEGRATED_AGENT
900 ICON "pageant.ico"
901 ICON "pageants.ico"
#else
200 ICON "pageant.ico"
201 ICON "pageants.ico"
#endif
210 DIALOG DISCARDABLE 0, 0, 140, 60
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
#ifdef MOD_PERSO
CAPTION "Kageant: Enter Passphrase"
#else
CAPTION "Pageant: Enter Passphrase"
#endif
FONT 8, "MS Shell Dlg"
BEGIN
CTEXT "Enter passphrase for key", 100, 10, 6, 120, 8
CTEXT "", 101, 10, 16, 120, 8
EDITTEXT 102, 10, 26, 120, 12, ES_PASSWORD | ES_AUTOHSCROLL
DEFPUSHBUTTON "O&K", IDOK, 20, 42, 40, 14
PUSHBUTTON "&Cancel", IDCANCEL, 80, 42, 40, 14
END
211 DIALOG DISCARDABLE 0, 0, 330, 200
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
#ifdef MOD_PERSO
CAPTION "Kageant Key List"
#else
CAPTION "Pageant Key List"
#endif
FONT 8, "MS Shell Dlg"
BEGIN
LISTBOX 100, 10, 10, 310, 155,
LBS_EXTENDEDSEL | LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "&Add Key", 101, 75, 162, 60, 14
PUSHBUTTON "&Remove Key", 102, 195, 162, 60, 14
PUSHBUTTON "&Help", 103, 10, 182, 50, 14
DEFPUSHBUTTON "&Close", IDOK, 270, 182, 50, 14
END
/* Accelerators used: cl */
213 DIALOG DISCARDABLE 140, 40, 270, 136
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
#ifdef MOD_PERSO
CAPTION "About Kageant"
#else
CAPTION "About Pageant"
#endif
FONT 8, "MS Shell Dlg"
BEGIN
DEFPUSHBUTTON "&Close", IDOK, 216, 118, 48, 14
PUSHBUTTON "View &Licence", 101, 6, 118, 70, 14
PUSHBUTTON "Visit &Web Site", 102, 140, 118, 70, 14
EDITTEXT 1000, 10, 6, 250, 110, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE
END
/* No accelerators used */
214 DIALOG DISCARDABLE 50, 50, 326, 239
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "PuTTY Licence"
FONT 8, "MS Shell Dlg"
BEGIN
DEFPUSHBUTTON "OK", IDOK, 148, 219, 44, 14
EDITTEXT 1000, 10, 10, 306, 200, ES_READONLY | ES_MULTILINE | ES_LEFT, WS_EX_STATICEDGE
END
#ifndef MOD_INTEGRATED_AGENT
#include "version.rc2"
#ifndef NO_MANIFESTS
1 RT_MANIFEST "pageant.mft"
#endif /* NO_MANIFESTS */
#endif
-194
View File
@@ -1,194 +0,0 @@
/*
* sizetip.c - resize tips for PuTTY(tel) terminal window.
*/
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include "putty.h"
static ATOM tip_class = 0;
static HFONT tip_font;
static COLORREF tip_bg;
static COLORREF tip_text;
static LRESULT CALLBACK SizeTipWndProc(HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam)
{
switch (nMsg) {
case WM_ERASEBKGND:
return true;
case WM_PAINT:
{
HBRUSH hbr;
HGDIOBJ holdbr;
RECT cr;
int wtlen;
LPTSTR wt;
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
SelectObject(hdc, tip_font);
SelectObject(hdc, GetStockObject(BLACK_PEN));
hbr = CreateSolidBrush(tip_bg);
holdbr = SelectObject(hdc, hbr);
GetClientRect(hWnd, &cr);
Rectangle(hdc, cr.left, cr.top, cr.right, cr.bottom);
wtlen = GetWindowTextLength(hWnd);
wt = (LPTSTR) snewn(wtlen + 1, TCHAR);
GetWindowText(hWnd, wt, wtlen + 1);
SetTextColor(hdc, tip_text);
SetBkColor(hdc, tip_bg);
TextOut(hdc, cr.left + 3, cr.top + 3, wt, wtlen);
sfree(wt);
SelectObject(hdc, holdbr);
DeleteObject(hbr);
EndPaint(hWnd, &ps);
}
return 0;
case WM_NCHITTEST:
return HTTRANSPARENT;
case WM_DESTROY:
DeleteObject(tip_font);
tip_font = NULL;
break;
case WM_SETTEXT:
{
LPCTSTR str = (LPCTSTR) lParam;
SIZE sz;
HDC hdc = CreateCompatibleDC(NULL);
SelectObject(hdc, tip_font);
GetTextExtentPoint32(hdc, str, _tcslen(str), &sz);
SetWindowPos(hWnd, NULL, 0, 0, sz.cx + 6, sz.cy + 6,
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
InvalidateRect(hWnd, NULL, false);
DeleteDC(hdc);
}
break;
}
return DefWindowProc(hWnd, nMsg, wParam, lParam);
}
static HWND tip_wnd = NULL;
static bool tip_enabled = false;
void UpdateSizeTip(HWND src, int cx, int cy)
{
TCHAR str[32];
if (!tip_enabled)
return;
if (!tip_wnd) {
NONCLIENTMETRICS nci;
/* First make sure the window class is registered */
if (!tip_class) {
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = SizeTipWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "SizeTipClass";
tip_class = RegisterClass(&wc);
}
#if 0
/* Default values based on Windows Standard color scheme */
tip_font = GetStockObject(SYSTEM_FONT);
tip_bg = RGB(255, 255, 225);
tip_text = RGB(0, 0, 0);
#endif
/* Prepare other GDI objects and drawing info */
tip_bg = GetSysColor(COLOR_INFOBK);
tip_text = GetSysColor(COLOR_INFOTEXT);
memset(&nci, 0, sizeof(NONCLIENTMETRICS));
nci.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
sizeof(NONCLIENTMETRICS), &nci, 0);
tip_font = CreateFontIndirect(&nci.lfStatusFont);
}
/* Generate the tip text */
sprintf(str, "%dx%d", cx, cy);
if (!tip_wnd) {
HDC hdc;
SIZE sz;
RECT wr;
int ix, iy;
/* calculate the tip's size */
hdc = CreateCompatibleDC(NULL);
GetTextExtentPoint32(hdc, str, _tcslen(str), &sz);
DeleteDC(hdc);
GetWindowRect(src, &wr);
ix = wr.left;
if (ix < 16)
ix = 16;
iy = wr.top - sz.cy;
if (iy < 16)
iy = 16;
/* Create the tip window */
tip_wnd =
CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
MAKEINTRESOURCE(tip_class), str, WS_POPUP, ix,
iy, sz.cx, sz.cy, NULL, NULL, hinst, NULL);
ShowWindow(tip_wnd, SW_SHOWNOACTIVATE);
} else {
/* Tip already exists, just set the text */
SetWindowText(tip_wnd, str);
}
}
void EnableSizeTip(bool bEnable)
{
if (tip_wnd && !bEnable) {
DestroyWindow(tip_wnd);
tip_wnd = NULL;
}
tip_enabled = bEnable;
}
-1
View File
@@ -1 +0,0 @@
"0.73.2"
-1
View File
@@ -1 +0,0 @@
17
-34
View File
@@ -1,34 +0,0 @@
/*
* wincapi.c: implementation of wincapi.h.
*/
#include "putty.h"
#if !defined NO_SECURITY
#define WINCAPI_GLOBAL
#include "wincapi.h"
bool got_crypt(void)
{
static bool attempted = false;
static bool successful;
static HMODULE crypt;
if (!attempted) {
attempted = true;
crypt = load_system32_dll("crypt32.dll");
successful = crypt &&
#ifdef COVERITY
/* The build toolchain I use with Coverity doesn't know
* about this function, so can't type-check it */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(crypt, CryptProtectMemory)
#else
GET_WINDOWS_FUNCTION(crypt, CryptProtectMemory)
#endif
;
}
return successful;
}
#endif /* !defined NO_SECURITY */
-18
View File
@@ -1,18 +0,0 @@
/*
* wincapi.h: Windows Crypto API functions defined in wincrypt.c
* that use the crypt32 library. Also centralises the machinery
* for dynamically loading that library.
*/
#if !defined NO_SECURITY
#ifndef WINCAPI_GLOBAL
#define WINCAPI_GLOBAL extern
#endif
DECL_WINDOWS_FUNCTION(WINCAPI_GLOBAL, BOOL, CryptProtectMemory,
(LPVOID,DWORD,DWORD));
bool got_crypt(void);
#endif
File diff suppressed because it is too large Load Diff
-137
View File
@@ -1,137 +0,0 @@
/*
* Pageant client code.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "putty.h"
#include "pageant.h" /* for AGENT_MAX_MSGLEN */
#ifndef NO_SECURITY
#include "winsecur.h"
#endif
#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */
bool agent_exists(void)
{
HWND hwnd;
hwnd = FindWindow("Pageant", "Pageant");
if (!hwnd)
return false;
else
return true;
}
void agent_cancel_query(agent_pending_query *q)
{
unreachable("Windows agent queries are never asynchronous!");
}
agent_pending_query *agent_query(
strbuf *query, void **out, int *outlen,
void (*callback)(void *, void *, int), void *callback_ctx)
{
HWND hwnd;
char *mapname;
HANDLE filemap;
unsigned char *p, *ret;
int id, retlen;
COPYDATASTRUCT cds;
SECURITY_ATTRIBUTES sa, *psa;
PSECURITY_DESCRIPTOR psd = NULL;
PSID usersid = NULL;
*out = NULL;
*outlen = 0;
if (query->len > AGENT_MAX_MSGLEN)
return NULL; /* query too large */
hwnd = FindWindow("Pageant", "Pageant");
if (!hwnd)
return NULL; /* *out == NULL, so failure */
mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId());
psa = NULL;
#ifndef NO_SECURITY
if (got_advapi()) {
/*
* Make the file mapping we create for communication with
* Pageant owned by the user SID rather than the default. This
* should make communication between processes with slightly
* different contexts more reliable: in particular, command
* prompts launched as administrator should still be able to
* run PSFTPs which refer back to the owning user's
* unprivileged Pageant.
*/
usersid = get_user_sid();
if (usersid) {
psd = (PSECURITY_DESCRIPTOR)
LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (psd) {
if (p_InitializeSecurityDescriptor
(psd, SECURITY_DESCRIPTOR_REVISION) &&
p_SetSecurityDescriptorOwner(psd, usersid, false)) {
sa.nLength = sizeof(sa);
sa.bInheritHandle = true;
sa.lpSecurityDescriptor = psd;
psa = &sa;
} else {
LocalFree(psd);
psd = NULL;
}
}
}
}
#endif /* NO_SECURITY */
filemap = CreateFileMapping(INVALID_HANDLE_VALUE, psa, PAGE_READWRITE,
0, AGENT_MAX_MSGLEN, mapname);
if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) {
sfree(mapname);
return NULL; /* *out == NULL, so failure */
}
p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
strbuf_finalise_agent_query(query);
memcpy(p, query->s, query->len);
cds.dwData = AGENT_COPYDATA_ID;
cds.cbData = 1 + strlen(mapname);
cds.lpData = mapname;
/*
* The user either passed a null callback (indicating that the
* query is required to be synchronous) or CreateThread failed.
* Either way, we need a synchronous request.
*/
id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
if (id > 0) {
uint32_t length_field = GET_32BIT_MSB_FIRST(p);
if (length_field > 0 && length_field <= AGENT_MAX_MSGLEN - 4) {
retlen = length_field + 4;
ret = snewn(retlen, unsigned char);
memcpy(ret, p, retlen);
*out = ret;
*outlen = retlen;
} else {
/*
* If we get here, we received an out-of-range length
* field, either without space for a message type code or
* overflowing the FileMapping.
*
* Treat this as if Pageant didn't answer at all - which
* actually means we do nothing, and just don't fill in
* out and outlen.
*/
}
}
UnmapViewOfFile(p);
CloseHandle(filemap);
sfree(mapname);
if (psd)
LocalFree(psd);
return NULL;
}
-450
View File
@@ -1,450 +0,0 @@
/*
* Serial back end (Windows-specific).
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "putty.h"
#define SERIAL_MAX_BACKLOG 4096
typedef struct Serial Serial;
struct Serial {
HANDLE port;
struct handle *out, *in;
Seat *seat;
LogContext *logctx;
int bufsize;
long clearbreak_time;
bool break_in_progress;
Backend backend;
};
static void serial_terminate(Serial *serial)
{
if (serial->out) {
handle_free(serial->out);
serial->out = NULL;
}
if (serial->in) {
handle_free(serial->in);
serial->in = NULL;
}
if (serial->port != INVALID_HANDLE_VALUE) {
if (serial->break_in_progress)
ClearCommBreak(serial->port);
CloseHandle(serial->port);
serial->port = INVALID_HANDLE_VALUE;
}
}
static size_t serial_gotdata(
struct handle *h, const void *data, size_t len, int err)
{
Serial *serial = (Serial *)handle_get_privdata(h);
if (err || len == 0) {
const char *error_msg;
/*
* Currently, len==0 should never happen because we're
* ignoring EOFs. However, it seems not totally impossible
* that this same back end might be usable to talk to named
* pipes or some other non-serial device, in which case EOF
* may become meaningful here.
*/
if (!err)
error_msg = "End of file reading from serial device";
else
error_msg = "Error reading from serial device";
serial_terminate(serial);
seat_notify_remote_exit(serial->seat);
logevent(serial->logctx, error_msg);
seat_connection_fatal(serial->seat, "%s", error_msg);
return 0;
} else {
return seat_stdout(serial->seat, data, len);
}
}
static void serial_sentdata(struct handle *h, size_t new_backlog, int err)
{
Serial *serial = (Serial *)handle_get_privdata(h);
if (err) {
const char *error_msg = "Error writing to serial device";
serial_terminate(serial);
seat_notify_remote_exit(serial->seat);
logevent(serial->logctx, error_msg);
seat_connection_fatal(serial->seat, "%s", error_msg);
} else {
serial->bufsize = new_backlog;
}
}
static const char *serial_configure(Serial *serial, HANDLE serport, Conf *conf)
{
DCB dcb;
COMMTIMEOUTS timeouts;
/*
* Set up the serial port parameters. If we can't even
* GetCommState, we ignore the problem on the grounds that the
* user might have pointed us at some other type of two-way
* device instead of a serial port.
*/
if (GetCommState(serport, &dcb)) {
const char *str;
/*
* Boilerplate.
*/
dcb.fBinary = true;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fDsrSensitivity = false;
dcb.fTXContinueOnXoff = false;
dcb.fOutX = false;
dcb.fInX = false;
dcb.fErrorChar = false;
dcb.fNull = false;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fAbortOnError = false;
dcb.fOutxCtsFlow = false;
dcb.fOutxDsrFlow = false;
/*
* Configurable parameters.
*/
dcb.BaudRate = conf_get_int(conf, CONF_serspeed);
logeventf(serial->logctx, "Configuring baud rate %lu", dcb.BaudRate);
dcb.ByteSize = conf_get_int(conf, CONF_serdatabits);
logeventf(serial->logctx, "Configuring %u data bits", dcb.ByteSize);
switch (conf_get_int(conf, CONF_serstopbits)) {
case 2: dcb.StopBits = ONESTOPBIT; str = "1"; break;
case 3: dcb.StopBits = ONE5STOPBITS; str = "1.5"; break;
case 4: dcb.StopBits = TWOSTOPBITS; str = "2"; break;
default: return "Invalid number of stop bits (need 1, 1.5 or 2)";
}
logeventf(serial->logctx, "Configuring %s data bits", str);
switch (conf_get_int(conf, CONF_serparity)) {
case SER_PAR_NONE: dcb.Parity = NOPARITY; str = "no"; break;
case SER_PAR_ODD: dcb.Parity = ODDPARITY; str = "odd"; break;
case SER_PAR_EVEN: dcb.Parity = EVENPARITY; str = "even"; break;
case SER_PAR_MARK: dcb.Parity = MARKPARITY; str = "mark"; break;
case SER_PAR_SPACE: dcb.Parity = SPACEPARITY; str = "space"; break;
}
logeventf(serial->logctx, "Configuring %s parity", str);
switch (conf_get_int(conf, CONF_serflow)) {
case SER_FLOW_NONE:
str = "no";
break;
case SER_FLOW_XONXOFF:
dcb.fOutX = dcb.fInX = true;
str = "XON/XOFF";
break;
case SER_FLOW_RTSCTS:
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcb.fOutxCtsFlow = true;
str = "RTS/CTS";
break;
case SER_FLOW_DSRDTR:
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
dcb.fOutxDsrFlow = true;
str = "DSR/DTR";
break;
}
logeventf(serial->logctx, "Configuring %s flow control", str);
if (!SetCommState(serport, &dcb))
return "Unable to configure serial port";
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(serport, &timeouts))
return "Unable to configure serial timeouts";
}
return NULL;
}
/*
* Called to set up the serial connection.
*
* Returns an error message, or NULL on success.
*
* Also places the canonical host name into `realhost'. It must be
* freed by the caller.
*/
static const char *serial_init(Seat *seat, Backend **backend_handle,
LogContext *logctx, Conf *conf,
const char *host, int port,
char **realhost, bool nodelay, bool keepalive)
{
Serial *serial;
HANDLE serport;
const char *err;
char *serline;
/* No local authentication phase in this protocol */
seat_set_trust_status(seat, false);
serial = snew(Serial);
serial->port = INVALID_HANDLE_VALUE;
serial->out = serial->in = NULL;
serial->bufsize = 0;
serial->break_in_progress = false;
serial->backend.vt = &serial_backend;
*backend_handle = &serial->backend;
serial->seat = seat;
serial->logctx = logctx;
serline = conf_get_str(conf, CONF_serline);
logeventf(serial->logctx, "Opening serial device %s", serline);
{
/*
* Munge the string supplied by the user into a Windows filename.
*
* Windows supports opening a few "legacy" devices (including
* COM1-9) by specifying their names verbatim as a filename to
* open. (Thus, no files can ever have these names. See
* <http://msdn2.microsoft.com/en-us/library/aa365247.aspx>
* ("Naming a File") for the complete list of reserved names.)
*
* However, this doesn't let you get at devices COM10 and above.
* For that, you need to specify a filename like "\\.\COM10".
* This is also necessary for special serial and serial-like
* devices such as \\.\WCEUSBSH001. It also works for the "legacy"
* names, so you can do \\.\COM1 (verified as far back as Win95).
* See <http://msdn2.microsoft.com/en-us/library/aa363858.aspx>
* (CreateFile() docs).
*
* So, we believe that prepending "\\.\" should always be the
* Right Thing. However, just in case someone finds something to
* talk to that doesn't exist under there, if the serial line
* contains a backslash, we use it verbatim. (This also lets
* existing configurations using \\.\ continue working.)
*/
char *serfilename =
dupprintf("%s%s", strchr(serline, '\\') ? "" : "\\\\.\\", serline);
serport = CreateFile(serfilename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
sfree(serfilename);
}
if (serport == INVALID_HANDLE_VALUE)
return "Unable to open serial port";
err = serial_configure(serial, serport, conf);
if (err)
return err;
serial->port = serport;
serial->out = handle_output_new(serport, serial_sentdata, serial,
HANDLE_FLAG_OVERLAPPED);
serial->in = handle_input_new(serport, serial_gotdata, serial,
HANDLE_FLAG_OVERLAPPED |
HANDLE_FLAG_IGNOREEOF |
HANDLE_FLAG_UNITBUFFER);
*realhost = dupstr(serline);
/*
* Specials are always available.
*/
seat_update_specials_menu(serial->seat);
return NULL;
}
static void serial_free(Backend *be)
{
Serial *serial = container_of(be, Serial, backend);
serial_terminate(serial);
expire_timer_context(serial);
sfree(serial);
}
static void serial_reconfig(Backend *be, Conf *conf)
{
Serial *serial = container_of(be, Serial, backend);
serial_configure(serial, serial->port, conf);
/*
* FIXME: what should we do if that call returned a non-NULL error
* message?
*/
}
/*
* Called to send data down the serial connection.
*/
static size_t serial_send(Backend *be, const char *buf, size_t len)
{
Serial *serial = container_of(be, Serial, backend);
if (serial->out == NULL)
return 0;
serial->bufsize = handle_write(serial->out, buf, len);
return serial->bufsize;
}
/*
* Called to query the current sendability status.
*/
static size_t serial_sendbuffer(Backend *be)
{
Serial *serial = container_of(be, Serial, backend);
return serial->bufsize;
}
/*
* Called to set the size of the window
*/
static void serial_size(Backend *be, int width, int height)
{
/* Do nothing! */
return;
}
static void serbreak_timer(void *ctx, unsigned long now)
{
Serial *serial = (Serial *)ctx;
if (now == serial->clearbreak_time && serial->port) {
ClearCommBreak(serial->port);
serial->break_in_progress = false;
logevent(serial->logctx, "Finished serial break");
}
}
/*
* Send serial special codes.
*/
static void serial_special(Backend *be, SessionSpecialCode code, int arg)
{
Serial *serial = container_of(be, Serial, backend);
if (serial->port && code == SS_BRK) {
logevent(serial->logctx, "Starting serial break at user request");
SetCommBreak(serial->port);
/*
* To send a serial break on Windows, we call SetCommBreak
* to begin the break, then wait a bit, and then call
* ClearCommBreak to finish it. Hence, I must use timing.c
* to arrange a callback when it's time to do the latter.
*
* SUS says that a default break length must be between 1/4
* and 1/2 second. FreeBSD apparently goes with 2/5 second,
* and so will I.
*/
serial->clearbreak_time =
schedule_timer(TICKSPERSEC * 2 / 5, serbreak_timer, serial);
serial->break_in_progress = true;
}
return;
}
/*
* Return a list of the special codes that make sense in this
* protocol.
*/
static const SessionSpecial *serial_get_specials(Backend *be)
{
static const SessionSpecial specials[] = {
{"Break", SS_BRK},
{NULL, SS_EXITMENU}
};
return specials;
}
static bool serial_connected(Backend *be)
{
return true; /* always connected */
}
static bool serial_sendok(Backend *be)
{
return true;
}
static void serial_unthrottle(Backend *be, size_t backlog)
{
Serial *serial = container_of(be, Serial, backend);
if (serial->in)
handle_unthrottle(serial->in, backlog);
}
static bool serial_ldisc(Backend *be, int option)
{
/*
* Local editing and local echo are off by default.
*/
return false;
}
static void serial_provide_ldisc(Backend *be, Ldisc *ldisc)
{
/* This is a stub. */
}
static int serial_exitcode(Backend *be)
{
Serial *serial = container_of(be, Serial, backend);
if (serial->port != INVALID_HANDLE_VALUE)
return -1; /* still connected */
else
/* Exit codes are a meaningless concept with serial ports */
return INT_MAX;
}
/*
* cfg_info for Serial does nothing at all.
*/
static int serial_cfg_info(Backend *be)
{
return 0;
}
const struct BackendVtable serial_backend = {
serial_init,
serial_free,
serial_reconfig,
serial_send,
serial_sendbuffer,
serial_size,
serial_special,
serial_get_specials,
serial_connected,
serial_exitcode,
serial_sendok,
serial_ldisc,
serial_provide_ldisc,
serial_unthrottle,
serial_cfg_info,
NULL /* test_for_upstream */,
"serial",
PROT_SERIAL,
0
};
-628
View File
@@ -1,628 +0,0 @@
/*
* winutils.c: miscellaneous Windows utilities for GUI apps
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "putty.h"
#include "misc.h"
#ifdef TESTMODE
/* Definitions to allow this module to be compiled standalone for testing
* split_into_argv(). */
#define smalloc malloc
#define srealloc realloc
#define sfree free
#endif
/*
* GetOpenFileName/GetSaveFileName tend to muck around with the process'
* working directory on at least some versions of Windows.
* Here's a wrapper that gives more control over this, and hides a little
* bit of other grottiness.
*/
struct filereq_tag {
TCHAR cwd[MAX_PATH];
};
/*
* `of' is expected to be initialised with most interesting fields, but
* this function does some administrivia. (assume `of' was memset to 0)
* save==1 -> GetSaveFileName; save==0 -> GetOpenFileName
* `state' is optional.
*/
bool request_file(filereq *state, OPENFILENAME *of, bool preserve, bool save)
{
TCHAR cwd[MAX_PATH]; /* process CWD */
bool ret;
/* Get process CWD */
if (preserve) {
DWORD r = GetCurrentDirectory(lenof(cwd), cwd);
if (r == 0 || r >= lenof(cwd))
/* Didn't work, oh well. Stop trying to be clever. */
preserve = false;
}
/* Open the file requester, maybe setting lpstrInitialDir */
{
#ifdef OPENFILENAME_SIZE_VERSION_400
of->lStructSize = OPENFILENAME_SIZE_VERSION_400;
#else
of->lStructSize = sizeof(*of);
#endif
of->lpstrInitialDir = (state && state->cwd[0]) ? state->cwd : NULL;
/* Actually put up the requester. */
ret = save ? GetSaveFileName(of) : GetOpenFileName(of);
}
/* Get CWD left by requester */
if (state) {
DWORD r = GetCurrentDirectory(lenof(state->cwd), state->cwd);
if (r == 0 || r >= lenof(state->cwd))
/* Didn't work, oh well. */
state->cwd[0] = '\0';
}
/* Restore process CWD */
if (preserve)
/* If it fails, there's not much we can do. */
(void) SetCurrentDirectory(cwd);
return ret;
}
filereq *filereq_new(void)
{
filereq *ret = snew(filereq);
ret->cwd[0] = '\0';
return ret;
}
void filereq_free(filereq *state)
{
sfree(state);
}
/*
* Message box with optional context help.
*/
/* Callback function to launch context help. */
static VOID CALLBACK message_box_help_callback(LPHELPINFO lpHelpInfo)
{
const char *context = NULL;
#define CHECK_CTX(name) \
do { \
if (lpHelpInfo->dwContextId == WINHELP_CTXID_ ## name) \
context = WINHELP_CTX_ ## name; \
} while (0)
CHECK_CTX(errors_hostkey_absent);
CHECK_CTX(errors_hostkey_changed);
CHECK_CTX(errors_cantloadkey);
CHECK_CTX(option_cleanup);
CHECK_CTX(pgp_fingerprints);
#undef CHECK_CTX
if (context)
launch_help(hwnd, context);
}
int message_box(LPCTSTR text, LPCTSTR caption, DWORD style, DWORD helpctxid)
{
MSGBOXPARAMS mbox;
/*
* We use MessageBoxIndirect() because it allows us to specify a
* callback function for the Help button.
*/
mbox.cbSize = sizeof(mbox);
/* Assumes the globals `hinst' and `hwnd' have sensible values. */
mbox.hInstance = hinst;
mbox.hwndOwner = hwnd;
mbox.lpfnMsgBoxCallback = &message_box_help_callback;
mbox.dwLanguageId = LANG_NEUTRAL;
mbox.lpszText = text;
mbox.lpszCaption = caption;
mbox.dwContextHelpId = helpctxid;
mbox.dwStyle = style;
if (helpctxid != 0 && has_help()) mbox.dwStyle |= MB_HELP;
return MessageBoxIndirect(&mbox);
}
/*
* Display the fingerprints of the PGP Master Keys to the user.
*/
void pgp_fingerprints(void)
{
message_box("These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
"be used to establish a trust path from this executable to another\n"
"one. See the manual for more information.\n"
"(Note: these fingerprints have nothing to do with SSH!)\n"
"\n"
"PuTTY Master Key as of " PGP_MASTER_KEY_YEAR
" (" PGP_MASTER_KEY_DETAILS "):\n"
" " PGP_MASTER_KEY_FP "\n\n"
"Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR
", " PGP_PREV_MASTER_KEY_DETAILS "):\n"
" " PGP_PREV_MASTER_KEY_FP,
"PGP fingerprints", MB_ICONINFORMATION | MB_OK,
HELPCTXID(pgp_fingerprints));
}
/*
* Handy wrapper around GetDlgItemText which doesn't make you invent
* an arbitrary length limit on the output string. Returned string is
* dynamically allocated; caller must free.
*/
char *GetDlgItemText_alloc(HWND hwnd, int id)
{
char *ret = NULL;
size_t size = 0;
do {
sgrowarray_nm(ret, size, size);
GetDlgItemText(hwnd, id, ret, size);
} while (!memchr(ret, '\0', size-1));
return ret;
}
/*
* Split a complete command line into argc/argv, attempting to do it
* exactly the same way the Visual Studio C library would do it (so
* that our console utilities, which receive argc and argv already
* broken apart by the C library, will have their command lines
* processed in the same way as the GUI utilities which get a whole
* command line and must call this function).
*
* Does not modify the input command line.
*
* The final parameter (argstart) is used to return a second array
* of char * pointers, the same length as argv, each one pointing
* at the start of the corresponding element of argv in the
* original command line. So if you get half way through processing
* your command line in argc/argv form and then decide you want to
* treat the rest as a raw string, you can. If you don't want to,
* `argstart' can be safely left NULL.
*/
void split_into_argv(char *cmdline, int *argc, char ***argv,
char ***argstart)
{
char *p;
char *outputline, *q;
char **outputargv, **outputargstart;
int outputargc;
/*
* These argument-breaking rules apply to Visual Studio 7, which
* is currently the compiler expected to be used for PuTTY. Visual
* Studio 10 has different rules, lacking the curious mod 3
* behaviour of consecutive quotes described below; I presume they
* fixed a bug. As and when we migrate to a newer compiler, we'll
* have to adjust this to match; however, for the moment we
* faithfully imitate in our GUI utilities what our CLI utilities
* can't be prevented from doing.
*
* When I investigated this, at first glance the rules appeared to
* be:
*
* - Single quotes are not special characters.
*
* - Double quotes are removed, but within them spaces cease
* to be special.
*
* - Backslashes are _only_ special when a sequence of them
* appear just before a double quote. In this situation,
* they are treated like C backslashes: so \" just gives a
* literal quote, \\" gives a literal backslash and then
* opens or closes a double-quoted segment, \\\" gives a
* literal backslash and then a literal quote, \\\\" gives
* two literal backslashes and then opens/closes a
* double-quoted segment, and so forth. Note that this
* behaviour is identical inside and outside double quotes.
*
* - Two successive double quotes become one literal double
* quote, but only _inside_ a double-quoted segment.
* Outside, they just form an empty double-quoted segment
* (which may cause an empty argument word).
*
* - That only leaves the interesting question of what happens
* when one or more backslashes precedes two or more double
* quotes, starting inside a double-quoted string. And the
* answer to that appears somewhat bizarre. Here I tabulate
* number of backslashes (across the top) against number of
* quotes (down the left), and indicate how many backslashes
* are output, how many quotes are output, and whether a
* quoted segment is open at the end of the sequence:
*
* backslashes
*
* 0 1 2 3 4
*
* 0 0,0,y | 1,0,y 2,0,y 3,0,y 4,0,y
* --------+-----------------------------
* 1 0,0,n | 0,1,y 1,0,n 1,1,y 2,0,n
* q 2 0,1,n | 0,1,n 1,1,n 1,1,n 2,1,n
* u 3 0,1,y | 0,2,n 1,1,y 1,2,n 2,1,y
* o 4 0,1,n | 0,2,y 1,1,n 1,2,y 2,1,n
* t 5 0,2,n | 0,2,n 1,2,n 1,2,n 2,2,n
* e 6 0,2,y | 0,3,n 1,2,y 1,3,n 2,2,y
* s 7 0,2,n | 0,3,y 1,2,n 1,3,y 2,2,n
* 8 0,3,n | 0,3,n 1,3,n 1,3,n 2,3,n
* 9 0,3,y | 0,4,n 1,3,y 1,4,n 2,3,y
* 10 0,3,n | 0,4,y 1,3,n 1,4,y 2,3,n
* 11 0,4,n | 0,4,n 1,4,n 1,4,n 2,4,n
*
*
* [Test fragment was of the form "a\\\"""b c" d.]
*
* There is very weird mod-3 behaviour going on here in the
* number of quotes, and it even applies when there aren't any
* backslashes! How ghastly.
*
* With a bit of thought, this extremely odd diagram suddenly
* coalesced itself into a coherent, if still ghastly, model of
* how things work:
*
* - As before, backslashes are only special when one or more
* of them appear contiguously before at least one double
* quote. In this situation the backslashes do exactly what
* you'd expect: each one quotes the next thing in front of
* it, so you end up with n/2 literal backslashes (if n is
* even) or (n-1)/2 literal backslashes and a literal quote
* (if n is odd). In the latter case the double quote
* character right after the backslashes is used up.
*
* - After that, any remaining double quotes are processed. A
* string of contiguous unescaped double quotes has a mod-3
* behaviour:
*
* * inside a quoted segment, a quote ends the segment.
* * _immediately_ after ending a quoted segment, a quote
* simply produces a literal quote.
* * otherwise, outside a quoted segment, a quote begins a
* quoted segment.
*
* So, for example, if we started inside a quoted segment
* then two contiguous quotes would close the segment and
* produce a literal quote; three would close the segment,
* produce a literal quote, and open a new segment. If we
* started outside a quoted segment, then two contiguous
* quotes would open and then close a segment, producing no
* output (but potentially creating a zero-length argument);
* but three quotes would open and close a segment and then
* produce a literal quote.
*/
/*
* First deal with the simplest of all special cases: if there
* aren't any arguments, return 0,NULL,NULL.
*/
while (*cmdline && isspace(*cmdline)) cmdline++;
if (!*cmdline) {
if (argc) *argc = 0;
if (argv) *argv = NULL;
if (argstart) *argstart = NULL;
return;
}
/*
* This will guaranteeably be big enough; we can realloc it
* down later.
*/
outputline = snewn(1+strlen(cmdline), char);
outputargv = snewn(strlen(cmdline)+1 / 2, char *);
outputargstart = snewn(strlen(cmdline)+1 / 2, char *);
p = cmdline; q = outputline; outputargc = 0;
while (*p) {
bool quote;
/* Skip whitespace searching for start of argument. */
while (*p && isspace(*p)) p++;
if (!*p) break;
/* We have an argument; start it. */
outputargv[outputargc] = q;
outputargstart[outputargc] = p;
outputargc++;
quote = false;
/* Copy data into the argument until it's finished. */
while (*p) {
if (!quote && isspace(*p))
break; /* argument is finished */
if (*p == '"' || *p == '\\') {
/*
* We have a sequence of zero or more backslashes
* followed by a sequence of zero or more quotes.
* Count up how many of each, and then deal with
* them as appropriate.
*/
int i, slashes = 0, quotes = 0;
while (*p == '\\') slashes++, p++;
while (*p == '"') quotes++, p++;
if (!quotes) {
/*
* Special case: if there are no quotes,
* slashes are not special at all, so just copy
* n slashes to the output string.
*/
while (slashes--) *q++ = '\\';
} else {
/* Slashes annihilate in pairs. */
while (slashes >= 2) slashes -= 2, *q++ = '\\';
/* One remaining slash takes out the first quote. */
if (slashes) quotes--, *q++ = '"';
if (quotes > 0) {
/* Outside a quote segment, a quote starts one. */
if (!quote) quotes--;
/* Now we produce (n+1)/3 literal quotes... */
for (i = 3; i <= quotes+1; i += 3) *q++ = '"';
/* ... and end in a quote segment iff 3 divides n. */
quote = (quotes % 3 == 0);
}
}
} else {
*q++ = *p++;
}
}
/* At the end of an argument, just append a trailing NUL. */
*q++ = '\0';
}
outputargv = sresize(outputargv, outputargc, char *);
outputargstart = sresize(outputargstart, outputargc, char *);
if (argc) *argc = outputargc;
if (argv) *argv = outputargv; else sfree(outputargv);
if (argstart) *argstart = outputargstart; else sfree(outputargstart);
}
#ifdef TESTMODE
const struct argv_test {
const char *cmdline;
const char *argv[10];
} argv_tests[] = {
/*
* We generate this set of tests by invoking ourself with
* `-generate'.
*/
{"ab c\" d", {"ab", "c d", NULL}},
{"a\"b c\" d", {"ab c", "d", NULL}},
{"a\"\"b c\" d", {"ab", "c d", NULL}},
{"a\"\"\"b c\" d", {"a\"b", "c d", NULL}},
{"a\"\"\"\"b c\" d", {"a\"b c", "d", NULL}},
{"a\"\"\"\"\"b c\" d", {"a\"b", "c d", NULL}},
{"a\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
{"a\"\"\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
{"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
{"a\\b c\" d", {"a\\b", "c d", NULL}},
{"a\\\"b c\" d", {"a\"b", "c d", NULL}},
{"a\\\"\"b c\" d", {"a\"b c", "d", NULL}},
{"a\\\"\"\"b c\" d", {"a\"b", "c d", NULL}},
{"a\\\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
{"a\\\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
{"a\\\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
{"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
{"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}},
{"a\\\\b c\" d", {"a\\\\b", "c d", NULL}},
{"a\\\\\"b c\" d", {"a\\b c", "d", NULL}},
{"a\\\\\"\"b c\" d", {"a\\b", "c d", NULL}},
{"a\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
{"a\\\\\"\"\"\"b c\" d", {"a\\\"b c", "d", NULL}},
{"a\\\\\"\"\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
{"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
{"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
{"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
{"a\\\\\\b c\" d", {"a\\\\\\b", "c d", NULL}},
{"a\\\\\\\"b c\" d", {"a\\\"b", "c d", NULL}},
{"a\\\\\\\"\"b c\" d", {"a\\\"b c", "d", NULL}},
{"a\\\\\\\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
{"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
{"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
{"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
{"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
{"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}},
{"a\\\\\\\\b c\" d", {"a\\\\\\\\b", "c d", NULL}},
{"a\\\\\\\\\"b c\" d", {"a\\\\b c", "d", NULL}},
{"a\\\\\\\\\"\"b c\" d", {"a\\\\b", "c d", NULL}},
{"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
{"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"b c", "d", NULL}},
{"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
{"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
{"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}},
{"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
{"\"ab c\" d", {"ab c", "d", NULL}},
{"\"a\"b c\" d", {"ab", "c d", NULL}},
{"\"a\"\"b c\" d", {"a\"b", "c d", NULL}},
{"\"a\"\"\"b c\" d", {"a\"b c", "d", NULL}},
{"\"a\"\"\"\"b c\" d", {"a\"b", "c d", NULL}},
{"\"a\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
{"\"a\"\"\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
{"\"a\"\"\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
{"\"a\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
{"\"a\\b c\" d", {"a\\b c", "d", NULL}},
{"\"a\\\"b c\" d", {"a\"b c", "d", NULL}},
{"\"a\\\"\"b c\" d", {"a\"b", "c d", NULL}},
{"\"a\\\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
{"\"a\\\"\"\"\"b c\" d", {"a\"\"b c", "d", NULL}},
{"\"a\\\"\"\"\"\"b c\" d", {"a\"\"b", "c d", NULL}},
{"\"a\\\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
{"\"a\\\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b c", "d", NULL}},
{"\"a\\\"\"\"\"\"\"\"\"b c\" d", {"a\"\"\"b", "c d", NULL}},
{"\"a\\\\b c\" d", {"a\\\\b c", "d", NULL}},
{"\"a\\\\\"b c\" d", {"a\\b", "c d", NULL}},
{"\"a\\\\\"\"b c\" d", {"a\\\"b", "c d", NULL}},
{"\"a\\\\\"\"\"b c\" d", {"a\\\"b c", "d", NULL}},
{"\"a\\\\\"\"\"\"b c\" d", {"a\\\"b", "c d", NULL}},
{"\"a\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
{"\"a\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
{"\"a\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
{"\"a\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
{"\"a\\\\\\b c\" d", {"a\\\\\\b c", "d", NULL}},
{"\"a\\\\\\\"b c\" d", {"a\\\"b c", "d", NULL}},
{"\"a\\\\\\\"\"b c\" d", {"a\\\"b", "c d", NULL}},
{"\"a\\\\\\\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
{"\"a\\\\\\\"\"\"\"b c\" d", {"a\\\"\"b c", "d", NULL}},
{"\"a\\\\\\\"\"\"\"\"b c\" d", {"a\\\"\"b", "c d", NULL}},
{"\"a\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
{"\"a\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b c", "d", NULL}},
{"\"a\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\"\"\"b", "c d", NULL}},
{"\"a\\\\\\\\b c\" d", {"a\\\\\\\\b c", "d", NULL}},
{"\"a\\\\\\\\\"b c\" d", {"a\\\\b", "c d", NULL}},
{"\"a\\\\\\\\\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
{"\"a\\\\\\\\\"\"\"b c\" d", {"a\\\\\"b c", "d", NULL}},
{"\"a\\\\\\\\\"\"\"\"b c\" d", {"a\\\\\"b", "c d", NULL}},
{"\"a\\\\\\\\\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
{"\"a\\\\\\\\\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b c", "d", NULL}},
{"\"a\\\\\\\\\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"b", "c d", NULL}},
{"\"a\\\\\\\\\"\"\"\"\"\"\"\"b c\" d", {"a\\\\\"\"\"b", "c d", NULL}},
};
int main(int argc, char **argv)
{
int i, j;
if (argc > 1) {
/*
* Generation of tests.
*
* Given `-splat <args>', we print out a C-style
* representation of each argument (in the form "a", "b",
* NULL), backslash-escaping each backslash and double
* quote.
*
* Given `-split <string>', we first doctor `string' by
* turning forward slashes into backslashes, single quotes
* into double quotes and underscores into spaces; and then
* we feed the resulting string to ourself with `-splat'.
*
* Given `-generate', we concoct a variety of fun test
* cases, encode them in quote-safe form (mapping \, " and
* space to /, ' and _ respectively) and feed each one to
* `-split'.
*/
if (!strcmp(argv[1], "-splat")) {
int i;
char *p;
for (i = 2; i < argc; i++) {
putchar('"');
for (p = argv[i]; *p; p++) {
if (*p == '\\' || *p == '"')
putchar('\\');
putchar(*p);
}
printf("\", ");
}
printf("NULL");
return 0;
}
if (!strcmp(argv[1], "-split") && argc > 2) {
char *str = malloc(20 + strlen(argv[0]) + strlen(argv[2]));
char *p, *q;
q = str + sprintf(str, "%s -splat ", argv[0]);
printf(" {\"");
for (p = argv[2]; *p; p++, q++) {
switch (*p) {
case '/': printf("\\\\"); *q = '\\'; break;
case '\'': printf("\\\""); *q = '"'; break;
case '_': printf(" "); *q = ' '; break;
default: putchar(*p); *q = *p; break;
}
}
*p = '\0';
printf("\", {");
fflush(stdout);
system(str);
printf("}},\n");
return 0;
}
if (!strcmp(argv[1], "-generate")) {
char *teststr, *p;
int i, initialquote, backslashes, quotes;
teststr = malloc(200 + strlen(argv[0]));
for (initialquote = 0; initialquote <= 1; initialquote++) {
for (backslashes = 0; backslashes < 5; backslashes++) {
for (quotes = 0; quotes < 9; quotes++) {
p = teststr + sprintf(teststr, "%s -split ", argv[0]);
if (initialquote) *p++ = '\'';
*p++ = 'a';
for (i = 0; i < backslashes; i++) *p++ = '/';
for (i = 0; i < quotes; i++) *p++ = '\'';
*p++ = 'b';
*p++ = '_';
*p++ = 'c';
*p++ = '\'';
*p++ = '_';
*p++ = 'd';
*p = '\0';
system(teststr);
}
}
}
return 0;
}
fprintf(stderr, "unrecognised option: \"%s\"\n", argv[1]);
return 1;
}
/*
* If we get here, we were invoked with no arguments, so just
* run the tests.
*/
for (i = 0; i < lenof(argv_tests); i++) {
int ac;
char **av;
split_into_argv(argv_tests[i].cmdline, &ac, &av);
for (j = 0; j < ac && argv_tests[i].argv[j]; j++) {
if (strcmp(av[j], argv_tests[i].argv[j])) {
printf("failed test %d (|%s|) arg %d: |%s| should be |%s|\n",
i, argv_tests[i].cmdline,
j, av[j], argv_tests[i].argv[j]);
}
#ifdef VERBOSE
else {
printf("test %d (|%s|) arg %d: |%s| == |%s|\n",
i, argv_tests[i].cmdline,
j, av[j], argv_tests[i].argv[j]);
}
#endif
}
if (j < ac)
printf("failed test %d (|%s|): %d args returned, should be %d\n",
i, argv_tests[i].cmdline, ac, j);
if (argv_tests[i].argv[j])
printf("failed test %d (|%s|): %d args returned, should be more\n",
i, argv_tests[i].cmdline, ac);
}
return 0;
}
#endif
+249 -249
View File
@@ -1,249 +1,249 @@
/*
* SSH agent forwarding.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "putty.h"
#include "ssh.h"
#include "pageant.h"
#include "sshchan.h"
typedef struct agentf {
SshChannel *c;
bufchain inbuffer;
agent_pending_query *pending;
bool input_wanted;
bool rcvd_eof;
Channel chan;
} agentf;
static void agentf_got_response(agentf *af, void *reply, int replylen)
{
af->pending = NULL;
if (!reply) {
/* The real agent didn't send any kind of reply at all for
* some reason, so fake an SSH_AGENT_FAILURE. */
reply = "\0\0\0\1\5";
replylen = 5;
}
sshfwd_write(af->c, reply, replylen);
}
static void agentf_callback(void *vctx, void *reply, int replylen);
static void agentf_try_forward(agentf *af)
{
size_t datalen, length;
strbuf *message;
unsigned char msglen[4];
void *reply;
int replylen;
/*
* Don't try to parallelise agent requests. Wait for each one to
* return before attempting the next.
*/
if (af->pending)
return;
/*
* If the outgoing side of the channel connection is currently
* throttled, don't submit any new forwarded requests to the real
* agent. This causes the input side of the agent forwarding not
* to be emptied, exerting the required back-pressure on the
* remote client, and encouraging it to read our responses before
* sending too many more requests.
*/
if (!af->input_wanted)
return;
while (1) {
/*
* Try to extract a complete message from the input buffer.
*/
datalen = bufchain_size(&af->inbuffer);
if (datalen < 4)
break; /* not even a length field available yet */
bufchain_fetch(&af->inbuffer, msglen, 4);
length = GET_32BIT_MSB_FIRST(msglen);
if (length > AGENT_MAX_MSGLEN-4) {
/*
* If the remote has sent a message that's just _too_
* long, we should reject it in advance of seeing the rest
* of the incoming message, and also close the connection
* for good measure (which avoids us having to faff about
* with carefully ignoring just the right number of bytes
* from the overlong message).
*/
agentf_got_response(af, NULL, 0);
sshfwd_write_eof(af->c);
return;
}
if (length > datalen - 4)
break; /* a whole message is not yet available */
bufchain_consume(&af->inbuffer, 4);
message = strbuf_new_for_agent_query();
bufchain_fetch_consume(
&af->inbuffer, strbuf_append(message, length), length);
af->pending = agent_query(
message, &reply, &replylen, agentf_callback, af);
strbuf_free(message);
if (af->pending)
return; /* agent_query promised to reply in due course */
/*
* If the agent gave us an answer immediately, pass it
* straight on and go round this loop again.
*/
agentf_got_response(af, reply, replylen);
sfree(reply);
}
/*
* If we get here (i.e. we left the above while loop via 'break'
* rather than 'return'), that means we've determined that the
* input buffer for the agent forwarding connection doesn't
* contain a complete request.
*
* So if there's potentially more data to come, we can return now,
* and wait for the remote client to send it. But if the remote
* has sent EOF, it would be a mistake to do that, because we'd be
* waiting a long time. So this is the moment to check for EOF,
* and respond appropriately.
*/
if (af->rcvd_eof)
sshfwd_write_eof(af->c);
}
static void agentf_callback(void *vctx, void *reply, int replylen)
{
agentf *af = (agentf *)vctx;
agentf_got_response(af, reply, replylen);
sfree(reply);
/*
* Now try to extract and send further messages from the channel's
* input-side buffer.
*/
agentf_try_forward(af);
}
static void agentf_free(Channel *chan);
static size_t agentf_send(Channel *chan, bool is_stderr, const void *, size_t);
static void agentf_send_eof(Channel *chan);
static char *agentf_log_close_msg(Channel *chan);
static void agentf_set_input_wanted(Channel *chan, bool wanted);
static const struct ChannelVtable agentf_channelvt = {
agentf_free,
chan_remotely_opened_confirmation,
chan_remotely_opened_failure,
agentf_send,
agentf_send_eof,
agentf_set_input_wanted,
agentf_log_close_msg,
chan_default_want_close,
chan_no_exit_status,
chan_no_exit_signal,
chan_no_exit_signal_numeric,
chan_no_run_shell,
chan_no_run_command,
chan_no_run_subsystem,
chan_no_enable_x11_forwarding,
chan_no_enable_agent_forwarding,
chan_no_allocate_pty,
chan_no_set_env,
chan_no_send_break,
chan_no_send_signal,
chan_no_change_window_size,
chan_no_request_response,
};
Channel *agentf_new(SshChannel *c)
{
agentf *af = snew(agentf);
af->c = c;
af->chan.vt = &agentf_channelvt;
af->chan.initial_fixed_window_size = 0;
af->rcvd_eof = false;
bufchain_init(&af->inbuffer);
af->pending = NULL;
af->input_wanted = true;
return &af->chan;
}
static void agentf_free(Channel *chan)
{
assert(chan->vt == &agentf_channelvt);
agentf *af = container_of(chan, agentf, chan);
if (af->pending)
agent_cancel_query(af->pending);
bufchain_clear(&af->inbuffer);
sfree(af);
}
static size_t agentf_send(Channel *chan, bool is_stderr,
const void *data, size_t length)
{
assert(chan->vt == &agentf_channelvt);
agentf *af = container_of(chan, agentf, chan);
bufchain_add(&af->inbuffer, data, length);
agentf_try_forward(af);
/*
* We exert back-pressure on an agent forwarding client if and
* only if we're waiting for the response to an asynchronous agent
* request. This prevents the client running out of window while
* receiving the _first_ message, but means that if any message
* takes time to process, the client will be discouraged from
* sending an endless stream of further ones after it.
*/
return (af->pending ? bufchain_size(&af->inbuffer) : 0);
}
static void agentf_send_eof(Channel *chan)
{
assert(chan->vt == &agentf_channelvt);
agentf *af = container_of(chan, agentf, chan);
af->rcvd_eof = true;
/* Call try_forward, which will respond to the EOF now if
* appropriate, or wait until the queue of outstanding requests is
* dealt with if not. */
agentf_try_forward(af);
}
static char *agentf_log_close_msg(Channel *chan)
{
return dupstr("Agent-forwarding connection closed");
}
static void agentf_set_input_wanted(Channel *chan, bool wanted)
{
assert(chan->vt == &agentf_channelvt);
agentf *af = container_of(chan, agentf, chan);
af->input_wanted = wanted;
/* Agent forwarding channels are buffer-managed by not asking the
* agent questions if the SSH channel isn't accepting input. So if
* it's started again, we should ask a question if we have one
* pending.. */
if (wanted)
agentf_try_forward(af);
}
/*
* SSH agent forwarding.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "putty.h"
#include "ssh.h"
#include "pageant.h"
#include "sshchan.h"
typedef struct agentf {
SshChannel *c;
bufchain inbuffer;
agent_pending_query *pending;
bool input_wanted;
bool rcvd_eof;
Channel chan;
} agentf;
static void agentf_got_response(agentf *af, void *reply, int replylen)
{
af->pending = NULL;
if (!reply) {
/* The real agent didn't send any kind of reply at all for
* some reason, so fake an SSH_AGENT_FAILURE. */
reply = "\0\0\0\1\5";
replylen = 5;
}
sshfwd_write(af->c, reply, replylen);
}
static void agentf_callback(void *vctx, void *reply, int replylen);
static void agentf_try_forward(agentf *af)
{
size_t datalen, length;
strbuf *message;
unsigned char msglen[4];
void *reply;
int replylen;
/*
* Don't try to parallelise agent requests. Wait for each one to
* return before attempting the next.
*/
if (af->pending)
return;
/*
* If the outgoing side of the channel connection is currently
* throttled, don't submit any new forwarded requests to the real
* agent. This causes the input side of the agent forwarding not
* to be emptied, exerting the required back-pressure on the
* remote client, and encouraging it to read our responses before
* sending too many more requests.
*/
if (!af->input_wanted)
return;
while (1) {
/*
* Try to extract a complete message from the input buffer.
*/
datalen = bufchain_size(&af->inbuffer);
if (datalen < 4)
break; /* not even a length field available yet */
bufchain_fetch(&af->inbuffer, msglen, 4);
length = GET_32BIT_MSB_FIRST(msglen);
if (length > AGENT_MAX_MSGLEN-4) {
/*
* If the remote has sent a message that's just _too_
* long, we should reject it in advance of seeing the rest
* of the incoming message, and also close the connection
* for good measure (which avoids us having to faff about
* with carefully ignoring just the right number of bytes
* from the overlong message).
*/
agentf_got_response(af, NULL, 0);
sshfwd_write_eof(af->c);
return;
}
if (length > datalen - 4)
break; /* a whole message is not yet available */
bufchain_consume(&af->inbuffer, 4);
message = strbuf_new_for_agent_query();
bufchain_fetch_consume(
&af->inbuffer, strbuf_append(message, length), length);
af->pending = agent_query(
message, &reply, &replylen, agentf_callback, af);
strbuf_free(message);
if (af->pending)
return; /* agent_query promised to reply in due course */
/*
* If the agent gave us an answer immediately, pass it
* straight on and go round this loop again.
*/
agentf_got_response(af, reply, replylen);
sfree(reply);
}
/*
* If we get here (i.e. we left the above while loop via 'break'
* rather than 'return'), that means we've determined that the
* input buffer for the agent forwarding connection doesn't
* contain a complete request.
*
* So if there's potentially more data to come, we can return now,
* and wait for the remote client to send it. But if the remote
* has sent EOF, it would be a mistake to do that, because we'd be
* waiting a long time. So this is the moment to check for EOF,
* and respond appropriately.
*/
if (af->rcvd_eof)
sshfwd_write_eof(af->c);
}
static void agentf_callback(void *vctx, void *reply, int replylen)
{
agentf *af = (agentf *)vctx;
agentf_got_response(af, reply, replylen);
sfree(reply);
/*
* Now try to extract and send further messages from the channel's
* input-side buffer.
*/
agentf_try_forward(af);
}
static void agentf_free(Channel *chan);
static size_t agentf_send(Channel *chan, bool is_stderr, const void *, size_t);
static void agentf_send_eof(Channel *chan);
static char *agentf_log_close_msg(Channel *chan);
static void agentf_set_input_wanted(Channel *chan, bool wanted);
static const ChannelVtable agentf_channelvt = {
.free = agentf_free,
.open_confirmation = chan_remotely_opened_confirmation,
.open_failed = chan_remotely_opened_failure,
.send = agentf_send,
.send_eof = agentf_send_eof,
.set_input_wanted = agentf_set_input_wanted,
.log_close_msg = agentf_log_close_msg,
.want_close = chan_default_want_close,
.rcvd_exit_status = chan_no_exit_status,
.rcvd_exit_signal = chan_no_exit_signal,
.rcvd_exit_signal_numeric = chan_no_exit_signal_numeric,
.run_shell = chan_no_run_shell,
.run_command = chan_no_run_command,
.run_subsystem = chan_no_run_subsystem,
.enable_x11_forwarding = chan_no_enable_x11_forwarding,
.enable_agent_forwarding = chan_no_enable_agent_forwarding,
.allocate_pty = chan_no_allocate_pty,
.set_env = chan_no_set_env,
.send_break = chan_no_send_break,
.send_signal = chan_no_send_signal,
.change_window_size = chan_no_change_window_size,
.request_response = chan_no_request_response,
};
Channel *agentf_new(SshChannel *c)
{
agentf *af = snew(agentf);
af->c = c;
af->chan.vt = &agentf_channelvt;
af->chan.initial_fixed_window_size = 0;
af->rcvd_eof = false;
bufchain_init(&af->inbuffer);
af->pending = NULL;
af->input_wanted = true;
return &af->chan;
}
static void agentf_free(Channel *chan)
{
assert(chan->vt == &agentf_channelvt);
agentf *af = container_of(chan, agentf, chan);
if (af->pending)
agent_cancel_query(af->pending);
bufchain_clear(&af->inbuffer);
sfree(af);
}
static size_t agentf_send(Channel *chan, bool is_stderr,
const void *data, size_t length)
{
assert(chan->vt == &agentf_channelvt);
agentf *af = container_of(chan, agentf, chan);
bufchain_add(&af->inbuffer, data, length);
agentf_try_forward(af);
/*
* We exert back-pressure on an agent forwarding client if and
* only if we're waiting for the response to an asynchronous agent
* request. This prevents the client running out of window while
* receiving the _first_ message, but means that if any message
* takes time to process, the client will be discouraged from
* sending an endless stream of further ones after it.
*/
return (af->pending ? bufchain_size(&af->inbuffer) : 0);
}
static void agentf_send_eof(Channel *chan)
{
assert(chan->vt == &agentf_channelvt);
agentf *af = container_of(chan, agentf, chan);
af->rcvd_eof = true;
/* Call try_forward, which will respond to the EOF now if
* appropriate, or wait until the queue of outstanding requests is
* dealt with if not. */
agentf_try_forward(af);
}
static char *agentf_log_close_msg(Channel *chan)
{
return dupstr("Agent-forwarding connection closed");
}
static void agentf_set_input_wanted(Channel *chan, bool wanted)
{
assert(chan->vt == &agentf_channelvt);
agentf *af = container_of(chan, agentf, chan);
af->input_wanted = wanted;
/* Agent forwarding channels are buffer-managed by not asking the
* agent questions if the SSH channel isn't accepting input. So if
* it's started again, we should ask a question if we have one
* pending.. */
if (wanted)
agentf_try_forward(af);
}
@@ -16,19 +16,19 @@
*/
const char *const appname = "PuTTY";
#ifdef TELNET_DEFAULT
const int be_default_protocol = PROT_TELNET;
#else
const int be_default_protocol = PROT_SSH;
#endif
const struct BackendVtable *const backends[] = {
&ssh_backend,
&telnet_backend,
&rlogin_backend,
&supdup_backend,
&raw_backend,
&sshconn_backend,
#ifdef MOD_ADB
&adb_backend,
#endif
NULL
};
const size_t n_ui_backends = 1;
@@ -14,26 +14,26 @@
* have tiny little source modules containing nothing but
* declarations of appname, for as long as I can...
*/
#if (defined MOD_PERSO) && (!defined FDJ)
#if (defined MOD_PERSO) && (!defined FLJ)
char *appname = "KiTTY";
#else
const char *const appname = "PuTTY";
#endif
#ifdef TELNET_DEFAULT
const int be_default_protocol = PROT_TELNET;
#else
const int be_default_protocol = PROT_SSH;
#endif
const struct BackendVtable *const backends[] = {
&ssh_backend,
&serial_backend,
&telnet_backend,
&rlogin_backend,
&supdup_backend,
&raw_backend,
&serial_backend,
#ifdef MOD_ADB
&adb_backend,
#endif
&sshconn_backend,
NULL
};
const size_t n_ui_backends = 2;
@@ -1,151 +1,154 @@
/*
* be_misc.c: helper functions shared between main network backends.
*/
#include <assert.h>
#include <string.h>
#include "putty.h"
#include "network.h"
void backend_socket_log(Seat *seat, LogContext *logctx,
int type, SockAddr *addr, int port,
const char *error_msg, int error_code, Conf *conf,
bool session_started)
{
char addrbuf[256], *msg;
switch (type) {
case 0:
sk_getaddr(addr, addrbuf, lenof(addrbuf));
if (sk_addr_needs_port(addr)) {
msg = dupprintf("Connecting to %s port %d", addrbuf, port);
} else {
msg = dupprintf("Connecting to %s", addrbuf);
}
break;
case 1:
sk_getaddr(addr, addrbuf, lenof(addrbuf));
msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg);
break;
case 2:
/* Proxy-related log messages have their own identifying
* prefix already, put on by our caller. */
{
int len, log_to_term;
/* Suffix \r\n temporarily, so we can log to the terminal. */
msg = dupprintf("%s\r\n", error_msg);
len = strlen(msg);
assert(len >= 2);
log_to_term = conf_get_int(conf, CONF_proxy_log_to_term);
if (log_to_term == AUTO)
log_to_term = session_started ? FORCE_OFF : FORCE_ON;
if (log_to_term == FORCE_ON)
seat_stderr(seat, msg, len);
msg[len-2] = '\0'; /* remove the \r\n again */
}
break;
default:
msg = NULL; /* shouldn't happen, but placate optimiser */
break;
}
if (msg) {
logevent(logctx, msg);
sfree(msg);
}
}
void psb_init(ProxyStderrBuf *psb)
{
psb->size = 0;
}
void log_proxy_stderr(Plug *plug, ProxyStderrBuf *psb,
const void *vdata, size_t len)
{
const char *data = (const char *)vdata;
/*
* This helper function allows us to collect the data written to a
* local proxy command's standard error in whatever size chunks we
* happen to get from its pipe, and whenever we have a complete
* line, we pass it to plug_log.
*
* (We also do this when the buffer in psb fills up, to avoid just
* allocating more and more memory forever, and also to keep Event
* Log lines reasonably bounded in size.)
*
* Prerequisites: a plug to log to, and a ProxyStderrBuf stored
* somewhere to collect any not-yet-output partial line.
*/
while (len > 0) {
/*
* Copy as much data into psb->buf as will fit.
*/
assert(psb->size < lenof(psb->buf));
size_t to_consume = lenof(psb->buf) - psb->size;
if (to_consume > len)
to_consume = len;
memcpy(psb->buf + psb->size, data, to_consume);
data += to_consume;
len -= to_consume;
psb->size += to_consume;
/*
* Output any full lines in psb->buf.
*/
size_t pos = 0;
while (pos < psb->size) {
char *nlpos = memchr(psb->buf + pos, '\n', psb->size - pos);
if (!nlpos)
break;
/*
* Found a newline in the buffer, so we can output a line.
*/
size_t endpos = nlpos - psb->buf;
while (endpos > pos && (psb->buf[endpos-1] == '\n' ||
psb->buf[endpos-1] == '\r'))
endpos--;
char *msg = dupprintf(
"proxy: %.*s", (int)(endpos - pos), psb->buf + pos);
plug_log(plug, 2, NULL, 0, msg, 0);
sfree(msg);
pos = nlpos - psb->buf + 1;
assert(pos <= psb->size);
}
/*
* If the buffer is completely full and we didn't output
* anything, then output the whole thing, flagging it as a
* truncated line.
*/
if (pos == 0 && psb->size == lenof(psb->buf)) {
char *msg = dupprintf(
"proxy (partial line): %.*s", (int)psb->size, psb->buf);
plug_log(plug, 2, NULL, 0, msg, 0);
sfree(msg);
pos = psb->size = 0;
}
/*
* Now move any remaining data up to the front of the buffer.
*/
size_t newsize = psb->size - pos;
if (newsize)
memmove(psb->buf, psb->buf + pos, newsize);
psb->size = newsize;
/*
* And loop round again if there's more data to be read from
* our input.
*/
}
}
/*
* be_misc.c: helper functions shared between main network backends.
*/
#include <assert.h>
#include <string.h>
#include "putty.h"
#include "network.h"
void backend_socket_log(Seat *seat, LogContext *logctx,
PlugLogType type, SockAddr *addr, int port,
const char *error_msg, int error_code, Conf *conf,
bool session_started)
{
char addrbuf[256], *msg;
switch (type) {
case PLUGLOG_CONNECT_TRYING:
sk_getaddr(addr, addrbuf, lenof(addrbuf));
if (sk_addr_needs_port(addr)) {
msg = dupprintf("Connecting to %s port %d", addrbuf, port);
} else {
msg = dupprintf("Connecting to %s", addrbuf);
}
break;
case PLUGLOG_CONNECT_FAILED:
sk_getaddr(addr, addrbuf, lenof(addrbuf));
msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg);
break;
case PLUGLOG_CONNECT_SUCCESS:
sk_getaddr(addr, addrbuf, lenof(addrbuf));
msg = dupprintf("Connected to %s", addrbuf);
break;
case PLUGLOG_PROXY_MSG: {
/* Proxy-related log messages have their own identifying
* prefix already, put on by our caller. */
int len, log_to_term;
/* Suffix \r\n temporarily, so we can log to the terminal. */
msg = dupprintf("%s\r\n", error_msg);
len = strlen(msg);
assert(len >= 2);
log_to_term = conf_get_int(conf, CONF_proxy_log_to_term);
if (log_to_term == AUTO)
log_to_term = session_started ? FORCE_OFF : FORCE_ON;
if (log_to_term == FORCE_ON)
seat_stderr(seat, msg, len);
msg[len-2] = '\0'; /* remove the \r\n again */
break;
}
default:
msg = NULL; /* shouldn't happen, but placate optimiser */
break;
}
if (msg) {
logevent(logctx, msg);
sfree(msg);
}
}
void psb_init(ProxyStderrBuf *psb)
{
psb->size = 0;
}
void log_proxy_stderr(Plug *plug, ProxyStderrBuf *psb,
const void *vdata, size_t len)
{
const char *data = (const char *)vdata;
/*
* This helper function allows us to collect the data written to a
* local proxy command's standard error in whatever size chunks we
* happen to get from its pipe, and whenever we have a complete
* line, we pass it to plug_log.
*
* (We also do this when the buffer in psb fills up, to avoid just
* allocating more and more memory forever, and also to keep Event
* Log lines reasonably bounded in size.)
*
* Prerequisites: a plug to log to, and a ProxyStderrBuf stored
* somewhere to collect any not-yet-output partial line.
*/
while (len > 0) {
/*
* Copy as much data into psb->buf as will fit.
*/
assert(psb->size < lenof(psb->buf));
size_t to_consume = lenof(psb->buf) - psb->size;
if (to_consume > len)
to_consume = len;
memcpy(psb->buf + psb->size, data, to_consume);
data += to_consume;
len -= to_consume;
psb->size += to_consume;
/*
* Output any full lines in psb->buf.
*/
size_t pos = 0;
while (pos < psb->size) {
char *nlpos = memchr(psb->buf + pos, '\n', psb->size - pos);
if (!nlpos)
break;
/*
* Found a newline in the buffer, so we can output a line.
*/
size_t endpos = nlpos - psb->buf;
while (endpos > pos && (psb->buf[endpos-1] == '\n' ||
psb->buf[endpos-1] == '\r'))
endpos--;
char *msg = dupprintf(
"proxy: %.*s", (int)(endpos - pos), psb->buf + pos);
plug_log(plug, PLUGLOG_PROXY_MSG, NULL, 0, msg, 0);
sfree(msg);
pos = nlpos - psb->buf + 1;
assert(pos <= psb->size);
}
/*
* If the buffer is completely full and we didn't output
* anything, then output the whole thing, flagging it as a
* truncated line.
*/
if (pos == 0 && psb->size == lenof(psb->buf)) {
char *msg = dupprintf(
"proxy (partial line): %.*s", (int)psb->size, psb->buf);
plug_log(plug, PLUGLOG_PROXY_MSG, NULL, 0, msg, 0);
sfree(msg);
pos = psb->size = 0;
}
/*
* Now move any remaining data up to the front of the buffer.
*/
size_t newsize = psb->size - pos;
if (newsize)
memmove(psb->buf, psb->buf + pos, newsize);
psb->size = newsize;
/*
* And loop round again if there's more data to be read from
* our input.
*/
}
}
@@ -1,11 +1,15 @@
/*
* Linking module for programs that do not support selection of backend
* (such as pterm).
*/
#include <stdio.h>
#include "putty.h"
const struct BackendVtable *const backends[] = {
NULL
};
/*
* Linking module for programs that do not support selection of backend
* (such as pterm).
*/
#include <stdio.h>
#include "putty.h"
const int be_default_protocol = -1;
const struct BackendVtable *const backends[] = {
NULL
};
const size_t n_ui_backends = 0;
@@ -12,26 +12,14 @@ const char *const appname = "PuTTYtel";
const struct BackendVtable *const backends[] = {
&telnet_backend,
&serial_backend,
&rlogin_backend,
&supdup_backend,
&raw_backend,
#ifdef MOD_ADB
&adb_backend,
#endif
&serial_backend,
NULL
};
/*
* Stub implementations of functions not used in non-ssh versions.
*/
void random_save_seed(void)
{
}
void random_destroy_seed(void)
{
}
void noise_ultralight(NoiseSourceId id, unsigned long data)
{
}
const size_t n_ui_backends = 2;
@@ -13,6 +13,7 @@ const char *const appname = "PuTTYtel";
const struct BackendVtable *const backends[] = {
&telnet_backend,
&rlogin_backend,
&supdup_backend,
&raw_backend,
#ifdef MOD_ADB
&adb_backend,
@@ -20,17 +21,4 @@ const struct BackendVtable *const backends[] = {
NULL
};
/*
* Stub implementations of functions not used in non-ssh versions.
*/
void random_save_seed(void)
{
}
void random_destroy_seed(void)
{
}
void noise_ultralight(NoiseSourceId id, unsigned long data)
{
}
const size_t n_ui_backends = 1;
+18
View File
@@ -0,0 +1,18 @@
/*
* Linking module for programs that are restricted to only using
* SSH-type protocols (pscp and psftp). These still have a choice of
* two actual backends, because they can also speak PROT_SSHCONN.
*/
#include <stdio.h>
#include "putty.h"
const int be_default_protocol = PROT_SSH;
const struct BackendVtable *const backends[] = {
&ssh_backend,
&sshconn_backend,
NULL
};
const size_t n_ui_backends = 0; /* not used in programs with a config UI */
@@ -1,133 +1,133 @@
/*
* Facility for queueing callback functions to be run from the
* top-level event loop after the current top-level activity finishes.
*/
#include <stddef.h>
#include "putty.h"
struct callback {
struct callback *next;
toplevel_callback_fn_t fn;
void *ctx;
};
struct callback *cbcurr = NULL, *cbhead = NULL, *cbtail = NULL;
toplevel_callback_notify_fn_t notify_frontend = NULL;
void *notify_ctx = NULL;
void request_callback_notifications(toplevel_callback_notify_fn_t fn,
void *ctx)
{
notify_frontend = fn;
notify_ctx = ctx;
}
static void run_idempotent_callback(void *ctx)
{
struct IdempotentCallback *ic = (struct IdempotentCallback *)ctx;
ic->queued = false;
ic->fn(ic->ctx);
}
void queue_idempotent_callback(struct IdempotentCallback *ic)
{
if (ic->queued)
return;
ic->queued = true;
queue_toplevel_callback(run_idempotent_callback, ic);
}
void delete_callbacks_for_context(void *ctx)
{
struct callback *newhead, *newtail;
newhead = newtail = NULL;
while (cbhead) {
struct callback *cb = cbhead;
cbhead = cbhead->next;
if (cb->ctx == ctx ||
(cb->fn == run_idempotent_callback &&
((struct IdempotentCallback *)cb->ctx)->ctx == ctx)) {
sfree(cb);
} else {
if (!newhead)
newhead = cb;
else
newtail->next = cb;
newtail = cb;
}
}
cbhead = newhead;
cbtail = newtail;
if (newtail)
newtail->next = NULL;
}
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
{
struct callback *cb;
cb = snew(struct callback);
cb->fn = fn;
cb->ctx = ctx;
/*
* If the front end has requested notification of pending
* callbacks, and we didn't already have one queued, let it know
* we do have one now.
*
* If cbcurr is non-NULL, i.e. we are actually in the middle of
* executing a callback right now, then we count that as the queue
* already having been non-empty. That saves the front end getting
* a constant stream of needless re-notifications if the last
* callback keeps re-scheduling itself.
*/
if (notify_frontend && !cbhead && !cbcurr)
notify_frontend(notify_ctx);
if (cbtail)
cbtail->next = cb;
else
cbhead = cb;
cbtail = cb;
cb->next = NULL;
}
bool run_toplevel_callbacks(void)
{
bool done_something = false;
if (cbhead) {
/*
* Transfer the head callback into cbcurr to indicate that
* it's being executed. Then operations which transform the
* queue, like delete_callbacks_for_context, can proceed as if
* it's not there.
*/
cbcurr = cbhead;
cbhead = cbhead->next;
if (!cbhead)
cbtail = NULL;
/*
* Now run the callback, and then clear it out of cbcurr.
*/
cbcurr->fn(cbcurr->ctx);
sfree(cbcurr);
cbcurr = NULL;
done_something = true;
}
return done_something;
}
bool toplevel_callback_pending(void)
{
return cbcurr != NULL || cbhead != NULL;
}
/*
* Facility for queueing callback functions to be run from the
* top-level event loop after the current top-level activity finishes.
*/
#include <stddef.h>
#include "putty.h"
struct callback {
struct callback *next;
toplevel_callback_fn_t fn;
void *ctx;
};
static struct callback *cbcurr = NULL, *cbhead = NULL, *cbtail = NULL;
static toplevel_callback_notify_fn_t notify_frontend = NULL;
static void *notify_ctx = NULL;
void request_callback_notifications(toplevel_callback_notify_fn_t fn,
void *ctx)
{
notify_frontend = fn;
notify_ctx = ctx;
}
static void run_idempotent_callback(void *ctx)
{
struct IdempotentCallback *ic = (struct IdempotentCallback *)ctx;
ic->queued = false;
ic->fn(ic->ctx);
}
void queue_idempotent_callback(struct IdempotentCallback *ic)
{
if (ic->queued)
return;
ic->queued = true;
queue_toplevel_callback(run_idempotent_callback, ic);
}
void delete_callbacks_for_context(void *ctx)
{
struct callback *newhead, *newtail;
newhead = newtail = NULL;
while (cbhead) {
struct callback *cb = cbhead;
cbhead = cbhead->next;
if (cb->ctx == ctx ||
(cb->fn == run_idempotent_callback &&
((struct IdempotentCallback *)cb->ctx)->ctx == ctx)) {
sfree(cb);
} else {
if (!newhead)
newhead = cb;
else
newtail->next = cb;
newtail = cb;
}
}
cbhead = newhead;
cbtail = newtail;
if (newtail)
newtail->next = NULL;
}
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
{
struct callback *cb;
cb = snew(struct callback);
cb->fn = fn;
cb->ctx = ctx;
/*
* If the front end has requested notification of pending
* callbacks, and we didn't already have one queued, let it know
* we do have one now.
*
* If cbcurr is non-NULL, i.e. we are actually in the middle of
* executing a callback right now, then we count that as the queue
* already having been non-empty. That saves the front end getting
* a constant stream of needless re-notifications if the last
* callback keeps re-scheduling itself.
*/
if (notify_frontend && !cbhead && !cbcurr)
notify_frontend(notify_ctx);
if (cbtail)
cbtail->next = cb;
else
cbhead = cb;
cbtail = cb;
cb->next = NULL;
}
bool run_toplevel_callbacks(void)
{
bool done_something = false;
if (cbhead) {
/*
* Transfer the head callback into cbcurr to indicate that
* it's being executed. Then operations which transform the
* queue, like delete_callbacks_for_context, can proceed as if
* it's not there.
*/
cbcurr = cbhead;
cbhead = cbhead->next;
if (!cbhead)
cbtail = NULL;
/*
* Now run the callback, and then clear it out of cbcurr.
*/
cbcurr->fn(cbcurr->ctx);
sfree(cbcurr);
cbcurr = NULL;
done_something = true;
}
return done_something;
}
bool toplevel_callback_pending(void)
{
return cbcurr != NULL || cbhead != NULL;
}
+788
View File
@@ -0,0 +1,788 @@
/*
* cgtest.c: stub file to compile cmdgen.c in self-test mode
*/
/*
* Before we #include cmdgen.c, we override some function names for
* test purposes. We do this via #define, so that when we link against
* modules containing the original versions, we don't get a link-time
* symbol clash:
*
* - Calls to get_random_data() are replaced with the diagnostic
* function below, in order to avoid depleting the test system's
* /dev/random unnecessarily.
*
* - Calls to console_get_userpass_input() are replaced with the
* diagnostic function below, so that I can run tests in an
* automated manner and provide their interactive passphrase
* inputs.
*
* - The main() defined by cmdgen.c is renamed to cmdgen_main(); in
* this file I define another main() which calls the former
* repeatedly to run tests.
*/
#define get_random_data get_random_data_diagnostic
#define console_get_userpass_input console_get_userpass_input_diagnostic
#define main cmdgen_main
#define ppk_save_default_parameters ppk_save_cgtest_parameters
#include "cmdgen.c"
#undef get_random_data
#undef console_get_userpass_input
#undef main
static bool cgtest_verbose = false;
const struct ppk_save_parameters ppk_save_cgtest_parameters = {
/* Replacement set of key derivation parameters that make this
* test suite run a bit faster and also add determinism: we don't
* try to auto-scale the number of passes (in case it gets
* different answers twice in the test suite when we were
* expecting two key files to compare equal), and we specify a
* passphrase salt. */
.fmt_version = 3,
.argon2_flavour = Argon2id,
.argon2_mem = 16,
.argon2_passes_auto = false,
.argon2_passes = 2,
.argon2_parallelism = 1,
.salt = (const uint8_t *)"SameSaltEachTime",
.saltlen = 16,
};
/*
* Define the special versions of get_random_data and
* console_get_userpass_input that we need for this test rig.
*/
char *get_random_data_diagnostic(int len, const char *device)
{
char *buf = snewn(len, char);
memset(buf, 'x', len);
return buf;
}
static int nprompts, promptsgot;
static const char *prompts[3];
int console_get_userpass_input_diagnostic(prompts_t *p)
{
size_t i;
int ret = 1;
for (i = 0; i < p->n_prompts; i++) {
if (promptsgot < nprompts) {
prompt_set_result(p->prompts[i], prompts[promptsgot++]);
if (cgtest_verbose)
printf(" prompt \"%s\": response \"%s\"\n",
p->prompts[i]->prompt, p->prompts[i]->result->s);
} else {
promptsgot++; /* track number of requests anyway */
ret = 0;
if (cgtest_verbose)
printf(" prompt \"%s\": no response preloaded\n",
p->prompts[i]->prompt);
}
}
return ret;
}
#include <stdarg.h>
static int passes, fails;
void setup_passphrases(char *first, ...)
{
va_list ap;
char *next;
nprompts = 0;
if (first) {
prompts[nprompts++] = first;
va_start(ap, first);
while ((next = va_arg(ap, char *)) != NULL) {
assert(nprompts < lenof(prompts));
prompts[nprompts++] = next;
}
va_end(ap);
}
}
void test(int retval, ...)
{
va_list ap;
int i, argc, ret;
char **argv;
argc = 0;
va_start(ap, retval);
while (va_arg(ap, char *) != NULL)
argc++;
va_end(ap);
argv = snewn(argc+1, char *);
va_start(ap, retval);
for (i = 0; i <= argc; i++)
argv[i] = va_arg(ap, char *);
va_end(ap);
promptsgot = 0;
if (cgtest_verbose) {
printf("run:");
for (int i = 0; i < argc; i++) {
static const char okchars[] =
"0123456789abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ%+,-./:=[]^_";
const char *arg = argv[i];
printf(" ");
if (arg[strspn(arg, okchars)]) {
printf("'");
for (const char *c = argv[i]; *c; c++) {
if (*c == '\'') {
printf("'\\''");
} else {
putchar(*c);
}
}
printf("'");
} else {
fputs(arg, stdout);
}
}
printf("\n");
}
ret = cmdgen_main(argc, argv);
random_clear();
if (ret != retval) {
printf("FAILED retval (exp %d got %d):", retval, ret);
for (i = 0; i < argc; i++)
printf(" %s", argv[i]);
printf("\n");
fails++;
} else if (promptsgot != nprompts) {
printf("FAILED nprompts (exp %d got %d):", nprompts, promptsgot);
for (i = 0; i < argc; i++)
printf(" %s", argv[i]);
printf("\n");
fails++;
} else {
passes++;
}
sfree(argv);
}
PRINTF_LIKE(3, 4) void filecmp(char *file1, char *file2, char *fmt, ...)
{
/*
* Ideally I should do file comparison myself, to maximise the
* portability of this test suite once this application begins
* running on non-Unix platforms. For the moment, though,
* calling Unix diff is perfectly adequate.
*/
char *buf;
int ret;
buf = dupprintf("diff -q '%s' '%s'", file1, file2);
ret = system(buf);
sfree(buf);
if (ret) {
va_list ap;
printf("FAILED diff (ret=%d): ", ret);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
fails++;
} else
passes++;
}
/*
* General-purpose flags word
*/
#define CGT_FLAGS(X) \
X(CGT_TYPE_KNOWN_EARLY) \
X(CGT_OPENSSH) \
X(CGT_SSHCOM) \
X(CGT_SSH_KEYGEN) \
X(CGT_ED25519) \
/* end of list */
#define FLAG_SHIFTS(name) name ## _shift,
enum { CGT_FLAGS(FLAG_SHIFTS) CGT_dummy_shift };
#define FLAG_VALUES(name) name = 1 << name ## _shift,
enum { CGT_FLAGS(FLAG_VALUES) CGT_dummy_flag };
char *cleanup_fp(char *s, unsigned flags)
{
ptrlen pl = ptrlen_from_asciz(s);
static const char separators[] = " \n\t";
/* Skip initial key type word if we find one */
if (ptrlen_startswith(pl, PTRLEN_LITERAL("ssh-"), NULL) ||
ptrlen_startswith(pl, PTRLEN_LITERAL("ecdsa-"), NULL))
ptrlen_get_word(&pl, separators);
/* Expect two words giving the key length and the hash */
ptrlen bits = ptrlen_get_word(&pl, separators);
ptrlen hash = ptrlen_get_word(&pl, separators);
if (flags & CGT_SSH_KEYGEN) {
/* Strip "MD5:" prefix if it's present, and do nothing if it isn't */
ptrlen_startswith(hash, PTRLEN_LITERAL("MD5:"), &hash);
if (flags & CGT_ED25519) {
/* OpenSSH ssh-keygen lists ed25519 keys as 256 bits, not 255 */
if (ptrlen_eq_string(bits, "256"))
bits = PTRLEN_LITERAL("255");
}
}
return dupprintf("%.*s %.*s", PTRLEN_PRINTF(bits), PTRLEN_PRINTF(hash));
}
char *get_line(char *filename)
{
FILE *fp;
char *line;
fp = fopen(filename, "r");
if (!fp)
return NULL;
line = fgetline(fp);
fclose(fp);
return line;
}
char *get_fp(char *filename, unsigned flags)
{
char *orig = get_line(filename);
if (!orig)
return NULL;
char *toret = cleanup_fp(orig, flags);
sfree(orig);
return toret;
}
PRINTF_LIKE(3, 4) void check_fp(char *filename, char *fp, char *fmt, ...)
{
char *newfp;
if (!fp)
return;
newfp = get_fp(filename, 0);
if (!strcmp(fp, newfp)) {
passes++;
} else {
va_list ap;
printf("FAILED check_fp ['%s' != '%s']: ", newfp, fp);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
fails++;
}
sfree(newfp);
}
static const struct cgtest_keytype {
const char *name;
unsigned flags;
} cgtest_keytypes[] = {
{ "rsa1", CGT_TYPE_KNOWN_EARLY },
{ "dsa", CGT_OPENSSH | CGT_SSHCOM },
{ "rsa", CGT_OPENSSH | CGT_SSHCOM },
{ "ecdsa", CGT_OPENSSH },
{ "ed25519", CGT_OPENSSH | CGT_ED25519 },
};
int main(int argc, char **argv)
{
int i;
int active[lenof(cgtest_keytypes)], active_value;
bool remove_files = true;
active_value = 0;
for (i = 0; i < lenof(cgtest_keytypes); i++)
active[i] = active_value;
while (--argc > 0) {
ptrlen arg = ptrlen_from_asciz(*++argv);
if (ptrlen_eq_string(arg, "-v") ||
ptrlen_eq_string(arg, "--verbose")) {
cgtest_verbose = true;
} else if (ptrlen_eq_string(arg, "--keep")) {
remove_files = false;
} else if (ptrlen_eq_string(arg, "--help")) {
printf("usage: cgtest [options] [key types]\n");
printf("options: -v, --verbose "
"print more output during tests\n");
printf(" --keep "
"do not delete the temporary output files\n");
printf(" --help "
"display this help text\n");
printf("key types: ");
for (i = 0; i < lenof(cgtest_keytypes); i++)
printf("%s%s", i ? ", " : "", cgtest_keytypes[i].name);
printf("\n");
return 0;
} else if (!ptrlen_startswith(arg, PTRLEN_LITERAL("-"), NULL)) {
for (i = 0; i < lenof(cgtest_keytypes); i++)
if (ptrlen_eq_string(arg, cgtest_keytypes[i].name))
break;
if (i == lenof(cgtest_keytypes)) {
fprintf(stderr, "cgtest: unrecognised key type '%.*s'\n",
PTRLEN_PRINTF(arg));
return 1;
}
active_value = 1; /* disables all keys not explicitly enabled */
active[i] = active_value;
} else {
fprintf(stderr, "cgtest: unrecognised option '%.*s'\n",
PTRLEN_PRINTF(arg));
return 1;
}
}
passes = fails = 0;
for (i = 0; i < lenof(cgtest_keytypes); i++) {
if (active[i] != active_value)
continue;
const struct cgtest_keytype *keytype = &cgtest_keytypes[i];
bool supports_openssh = keytype->flags & CGT_OPENSSH;
bool supports_sshcom = keytype->flags & CGT_SSHCOM;
bool type_known_early = keytype->flags & CGT_TYPE_KNOWN_EARLY;
char filename[128], osfilename[128], scfilename[128];
char pubfilename[128], tmpfilename1[128], tmpfilename2[128];
char *fps[SSH_N_FPTYPES];
sprintf(filename, "test-%s.ppk", keytype->name);
sprintf(pubfilename, "test-%s.pub", keytype->name);
sprintf(osfilename, "test-%s.os", keytype->name);
sprintf(scfilename, "test-%s.sc", keytype->name);
sprintf(tmpfilename1, "test-%s.tmp1", keytype->name);
sprintf(tmpfilename2, "test-%s.tmp2", keytype->name);
/*
* Create an encrypted key.
*/
setup_passphrases("sponge", "sponge", NULL);
test(0, "puttygen", "-t", keytype->name, "-o", filename, NULL);
/*
* List the public key in OpenSSH format.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-L", filename, "-o", pubfilename, NULL);
for (FingerprintType fptype = 0; fptype < SSH_N_FPTYPES; fptype++) {
const char *fpname = (fptype == SSH_FPTYPE_MD5 ? "md5" : "sha256");
char *cmdbuf;
char *fp = NULL;
cmdbuf = dupprintf("ssh-keygen -E %s -l -f '%s' > '%s'",
fpname, pubfilename, tmpfilename1);
if (cgtest_verbose)
printf("OpenSSH %s fp check: %s\n", fpname, cmdbuf);
if (system(cmdbuf) ||
(fp = get_fp(tmpfilename1,
CGT_SSH_KEYGEN | keytype->flags)) == NULL) {
printf("UNABLE to test fingerprint matching against "
"OpenSSH\n");
}
sfree(cmdbuf);
if (fp && cgtest_verbose) {
char *line = get_line(tmpfilename1);
printf("OpenSSH %s fp: %s\n", fpname, line);
printf("Cleaned up: %s\n", fp);
sfree(line);
}
fps[fptype] = fp;
}
/*
* List the public key in IETF/ssh.com format.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-p", filename, NULL);
/*
* List the fingerprint of the key.
*/
setup_passphrases(NULL);
for (FingerprintType fptype = 0; fptype < SSH_N_FPTYPES; fptype++) {
const char *fpname = (fptype == SSH_FPTYPE_MD5 ? "md5" : "sha256");
test(0, "puttygen", "-E", fpname, "-l", filename,
"-o", tmpfilename1, NULL);
if (!fps[fptype]) {
/*
* If we can't test fingerprints against OpenSSH, we
* can at the very least test equality of all the
* fingerprints we generate of this key throughout
* testing.
*/
fps[fptype] = get_fp(tmpfilename1, 0);
} else {
check_fp(tmpfilename1, fps[fptype], "%s initial %s fp",
keytype->name, fpname);
}
}
/*
* Change the comment of the key; this _does_ require a
* passphrase owing to the tamperproofing.
*
* NOTE: In SSH-1, this only requires a passphrase because
* of inadequacies of the loading and saving mechanisms. In
* _principle_, it should be perfectly possible to modify
* the comment on an SSH-1 key without requiring a
* passphrase; the only reason I can't do it is because my
* loading and saving mechanisms don't include a method of
* loading all the key data without also trying to decrypt
* the private section.
*
* I don't consider this to be a problem worth solving,
* because (a) to fix it would probably end up bloating
* PuTTY proper, and (b) SSH-1 is on the way out anyway so
* it shouldn't be highly significant. If it seriously
* bothers anyone then perhaps I _might_ be persuadable.
*/
setup_passphrases("sponge", NULL);
test(0, "puttygen", "-C", "new-comment", filename, NULL);
/*
* Change the passphrase to nothing.
*/
setup_passphrases("sponge", "", "", NULL);
test(0, "puttygen", "-P", filename, NULL);
/*
* Change the comment of the key again; this time we expect no
* passphrase to be required.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-C", "new-comment-2", filename, NULL);
/*
* Export the private key into OpenSSH format; no passphrase
* should be required since the key is currently unencrypted.
*/
setup_passphrases(NULL);
test(supports_openssh ? 0 : 1,
"puttygen", "-O", "private-openssh", "-o", osfilename,
filename, NULL);
if (supports_openssh) {
/*
* List the fingerprint of the OpenSSH-formatted key.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-l", osfilename, "-o", tmpfilename1, NULL);
check_fp(tmpfilename1, fps[SSH_FPTYPE_DEFAULT],
"%s openssh clear fp", keytype->name);
/*
* List the public half of the OpenSSH-formatted key in
* OpenSSH format.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-L", osfilename, NULL);
/*
* List the public half of the OpenSSH-formatted key in
* IETF/ssh.com format.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-p", osfilename, NULL);
}
/*
* Export the private key into ssh.com format; no passphrase
* should be required since the key is currently unencrypted.
*/
setup_passphrases(NULL);
test(supports_sshcom ? 0 : 1,
"puttygen", "-O", "private-sshcom",
"-o", scfilename, filename, NULL);
if (supports_sshcom) {
/*
* List the fingerprint of the ssh.com-formatted key.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-l", scfilename, "-o", tmpfilename1, NULL);
check_fp(tmpfilename1, fps[SSH_FPTYPE_DEFAULT],
"%s ssh.com clear fp", keytype->name);
/*
* List the public half of the ssh.com-formatted key in
* OpenSSH format.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-L", scfilename, NULL);
/*
* List the public half of the ssh.com-formatted key in
* IETF/ssh.com format.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-p", scfilename, NULL);
}
if (supports_openssh && supports_sshcom) {
/*
* Convert from OpenSSH into ssh.com.
*/
setup_passphrases(NULL);
test(0, "puttygen", osfilename, "-o", tmpfilename1,
"-O", "private-sshcom", NULL);
/*
* Convert from ssh.com back into a PuTTY key,
* supplying the same comment as we had before we
* started to ensure the comparison works.
*/
setup_passphrases(NULL);
test(0, "puttygen", tmpfilename1, "-C", "new-comment-2",
"-o", tmpfilename2, NULL);
/*
* See if the PuTTY key thus generated is the same as
* the original.
*/
filecmp(filename, tmpfilename2,
"p->o->s->p clear %s", keytype->name);
/*
* Convert from ssh.com to OpenSSH.
*/
setup_passphrases(NULL);
test(0, "puttygen", scfilename, "-o", tmpfilename1,
"-O", "private-openssh", NULL);
/*
* Convert from OpenSSH back into a PuTTY key,
* supplying the same comment as we had before we
* started to ensure the comparison works.
*/
setup_passphrases(NULL);
test(0, "puttygen", tmpfilename1, "-C", "new-comment-2",
"-o", tmpfilename2, NULL);
/*
* See if the PuTTY key thus generated is the same as
* the original.
*/
filecmp(filename, tmpfilename2,
"p->s->o->p clear %s", keytype->name);
/*
* Finally, do a round-trip conversion between PuTTY
* and ssh.com without involving OpenSSH, to test that
* the key comment is preserved in that case.
*/
setup_passphrases(NULL);
test(0, "puttygen", "-O", "private-sshcom", "-o", tmpfilename1,
filename, NULL);
setup_passphrases(NULL);
test(0, "puttygen", tmpfilename1, "-o", tmpfilename2, NULL);
filecmp(filename, tmpfilename2,
"p->s->p clear %s", keytype->name);
}
/*
* Check that mismatched passphrases cause an error.
*/
setup_passphrases("sponge2", "sponge3", NULL);
test(1, "puttygen", "-P", filename, NULL);
/*
* Put a passphrase back on.
*/
setup_passphrases("sponge2", "sponge2", NULL);
test(0, "puttygen", "-P", filename, NULL);
/*
* Export the private key into OpenSSH format, this time
* while encrypted.
*/
if (!supports_openssh && type_known_early) {
/* We'll know far enough in advance that this combination
* is going to fail that we never ask for the passphrase */
setup_passphrases(NULL);
} else {
setup_passphrases("sponge2", NULL);
}
test(supports_openssh ? 0 : 1,
"puttygen", "-O", "private-openssh", "-o", osfilename,
filename, NULL);
if (supports_openssh) {
/*
* List the fingerprint of the OpenSSH-formatted key.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", "-l", osfilename, "-o", tmpfilename1, NULL);
check_fp(tmpfilename1, fps[SSH_FPTYPE_DEFAULT],
"%s openssh encrypted fp", keytype->name);
/*
* List the public half of the OpenSSH-formatted key in
* OpenSSH format.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", "-L", osfilename, NULL);
/*
* List the public half of the OpenSSH-formatted key in
* IETF/ssh.com format.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", "-p", osfilename, NULL);
}
/*
* Export the private key into ssh.com format, this time
* while encrypted. For RSA1 keys, this should give an
* error.
*/
if (!supports_sshcom && type_known_early) {
/* We'll know far enough in advance that this combination
* is going to fail that we never ask for the passphrase */
setup_passphrases(NULL);
} else {
setup_passphrases("sponge2", NULL);
}
test(supports_sshcom ? 0 : 1,
"puttygen", "-O", "private-sshcom", "-o", scfilename,
filename, NULL);
if (supports_sshcom) {
/*
* List the fingerprint of the ssh.com-formatted key.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", "-l", scfilename, "-o", tmpfilename1, NULL);
check_fp(tmpfilename1, fps[SSH_FPTYPE_DEFAULT],
"%s ssh.com encrypted fp", keytype->name);
/*
* List the public half of the ssh.com-formatted key in
* OpenSSH format.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", "-L", scfilename, NULL);
/*
* List the public half of the ssh.com-formatted key in
* IETF/ssh.com format.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", "-p", scfilename, NULL);
}
if (supports_openssh && supports_sshcom) {
/*
* Convert from OpenSSH into ssh.com.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", osfilename, "-o", tmpfilename1,
"-O", "private-sshcom", NULL);
/*
* Convert from ssh.com back into a PuTTY key,
* supplying the same comment as we had before we
* started to ensure the comparison works.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", tmpfilename1, "-C", "new-comment-2",
"-o", tmpfilename2, NULL);
/*
* See if the PuTTY key thus generated is the same as
* the original.
*/
filecmp(filename, tmpfilename2,
"p->o->s->p encrypted %s", keytype->name);
/*
* Convert from ssh.com to OpenSSH.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", scfilename, "-o", tmpfilename1,
"-O", "private-openssh", NULL);
/*
* Convert from OpenSSH back into a PuTTY key,
* supplying the same comment as we had before we
* started to ensure the comparison works.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", tmpfilename1, "-C", "new-comment-2",
"-o", tmpfilename2, NULL);
/*
* See if the PuTTY key thus generated is the same as
* the original.
*/
filecmp(filename, tmpfilename2,
"p->s->o->p encrypted %s", keytype->name);
/*
* Finally, do a round-trip conversion between PuTTY
* and ssh.com without involving OpenSSH, to test that
* the key comment is preserved in that case.
*/
setup_passphrases("sponge2", NULL);
test(0, "puttygen", "-O", "private-sshcom", "-o", tmpfilename1,
filename, NULL);
setup_passphrases("sponge2", NULL);
test(0, "puttygen", tmpfilename1, "-o", tmpfilename2, NULL);
filecmp(filename, tmpfilename2,
"p->s->p encrypted %s", keytype->name);
}
/*
* Load with the wrong passphrase.
*/
setup_passphrases("sponge8", NULL);
test(1, "puttygen", "-C", "spurious-new-comment", filename, NULL);
/*
* Load a totally bogus file.
*/
setup_passphrases(NULL);
test(1, "puttygen", "-C", "spurious-new-comment", pubfilename, NULL);
for (FingerprintType fptype = 0; fptype < SSH_N_FPTYPES; fptype++)
sfree(fps[fptype]);
if (remove_files) {
remove(filename);
remove(pubfilename);
remove(osfilename);
remove(scfilename);
remove(tmpfilename1);
remove(tmpfilename2);
}
}
printf("%d passes, %d fails\n", passes, fails);
return fails == 0 ? 0 : 1;
}
+14
View File
@@ -0,0 +1,14 @@
/*
* clicons.c: definitions limited to tools that link against both
* console.c and cmdline.c.
*/
#include "putty.h"
static const LogPolicyVtable console_cli_logpolicy_vt = {
.eventlog = console_eventlog,
.askappend = console_askappend,
.logging_error = console_logging_error,
.verbose = cmdline_lp_verbose,
};
LogPolicy console_cli_logpolicy[1] = {{ &console_cli_logpolicy_vt }};
File diff suppressed because it is too large Load Diff
@@ -30,9 +30,93 @@
#ifdef MOD_PERSO
#include "kitty_crypt.h"
#include "kitty.h"
int decode64(char *buffer) ;
void SetAutoStoreSSHKey( void ) ;
void load_open_settings_forced(char *filename, Conf *conf) ;
void SetPasswordInConfig( const char * password ) ;
int GetCryptSaltFlag() ;
extern char CurrentFolder[1024] ;
// Manage connect string as: user:pass@@@hostname:port/cmd
void ManageConnectString( Conf *cf, char * hostname ) {
int i, j ;
char *p, *us, *pw, *hn, *po, *cm ;
us = (char*)malloc(strlen(hostname)+1); strcpy(us,"");
pw = (char*)malloc(strlen(hostname)+1); strcpy(pw,"");
hn = (char*)malloc(strlen(hostname)+1); strcpy(hn,hostname);
po = (char*)malloc(strlen(hostname)+1); strcpy(po,"");
cm = (char*)malloc(strlen(hostname)+1); strcpy(cm,"");
for( i=0 ; i<strlen(hostname) ; i++ ) {
if( hostname[i]=='@' ) {
if( hostname[i+1]=='@' ) {
i++ ;
} else {
strcpy( us, hostname ) ;
us[i] = '\0' ;
j = 0 ;
do { i++; hn[j]=hostname[i]; j++; } while( hostname[i]!='\0' ) ;
break ;
}
}
}
if( hn[0]=='[' ) { // IPv6
char *q ;
if( (q = strstr( hn, "]" )) != NULL ) {
q++ ;
if( (p = strstr( q, "/" )) != NULL ) {
strcpy( cm, p+1 ) ;
p[0] = '\0' ;
}
if( (p = strstr( q, ":" )) != NULL ) {
strcpy( po, p+1 ) ;
p[0] = '\0' ;
}
q[0] = '\0' ;
}
} else { // IPv4
if( (p = strstr( hn, "/" )) != NULL ) {
strcpy( cm, p+1 ) ;
p[0] = '\0' ;
}
if( (p = strstr( hn, ":" )) != NULL ) {
strcpy( po, p+1 ) ;
p[0] = '\0' ;
}
}
if( strlen(us)>0 ) {
if( (p = strstr( us, ":" )) != NULL ) {
strcpy( pw, p+1 ) ;
p[0] = '\0' ;
while( (p = strstr( pw, "@@" )) != NULL ) { // Manage @ in password ( @ => double @@)
do { p[0] = p[1] ; p++ ; } while( p[0] != '\0' ) ;
}
}
if( strlen(pw)>0 ) {
SetPasswordInConfig( pw ) ;
}
sprintf( hostname, "%s@%s", us, hn ) ;
} else {
strcpy( hostname, hn ) ;
}
if( strlen(po)>0 ) {
conf_set_int( cf, CONF_port, atoi(po) ) ;
}
if( strlen(cm)>0 ) {
if( cm[0] == '#' ) {
decryptstring( GetCryptSaltFlag(), (char*)cm+1, MASTER_PASSWORD ) ;
conf_set_str( cf, CONF_autocommand, cm+1 ) ;
} else {
char *s = (char*)malloc( strlen(cm)+1 ) ;
strcpy( s, cm ) ;
int i = decode64(s) ;
s[i] = '\0' ;
conf_set_str( cf,CONF_autocommand,s ) ;
free(s) ;
}
}
free(cm);free(po);free(hn);free(pw);free(us);
}
#endif
#ifdef MOD_ADB
int GetADBFlag(void) ;
@@ -119,18 +203,6 @@ int cmdline_get_passwd_input(prompts_t *p)
return 1;
}
/*
* Here we have a flags word which describes the capabilities of
* the particular tool on whose behalf we're running. We will
* refuse certain command-line options if a particular tool
* inherently can't do anything sensible. For example, the file
* transfer tools (psftp, pscp) can't do a great deal with protocol
* selections (ever tried running scp over telnet?) or with port
* forwarding (even if it wasn't a hideously bad idea, they don't
* have the select/poll infrastructure to make them work).
*/
int cmdline_tooltype = 0;
static bool cmdline_check_unavailable(int flag, const char *p)
{
if (cmdline_tooltype & flag) {
@@ -167,12 +239,29 @@ static bool cmdline_check_unavailable(int flag, const char *p)
static bool seen_hostname_argument = false;
static bool seen_port_argument = false;
static bool seen_verbose_option = false;
static bool loaded_session = false;
bool cmdline_verbose(void) { return seen_verbose_option; }
bool cmdline_seat_verbose(Seat *seat) { return cmdline_verbose(); }
bool cmdline_lp_verbose(LogPolicy *lp) { return cmdline_verbose(); }
bool cmdline_loaded_session(void) { return loaded_session; }
static void set_protocol(Conf *conf, int protocol)
{
settings_set_default_protocol(protocol);
conf_set_int(conf, CONF_protocol, protocol);
}
static void set_port(Conf *conf, int port)
{
settings_set_default_port(port);
conf_set_int(conf, CONF_port, port);
}
int cmdline_process_param(const char *p, char *value,
int need_save, Conf *conf)
{
int ret = 0;
if (p[0] != '-') {
if (need_save < 0)
return 0;
@@ -184,7 +273,6 @@ int cmdline_process_param(const char *p, char *value,
* hostname specification appears as part of a more
* complicated scheme.
*/
if ((cmdline_tooltype & TOOLTYPE_HOST_ARG) &&
!seen_hostname_argument &&
(!(cmdline_tooltype & TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD) ||
@@ -207,6 +295,7 @@ int cmdline_process_param(const char *p, char *value,
* the default session and never be able to do anything
* else).
*/
if (!strncmp(p, "telnet:", 7)) {
/*
* If the argument starts with "telnet:", set the
@@ -254,59 +343,26 @@ int cmdline_process_param(const char *p, char *value,
conf_set_int(conf, CONF_port, -1);
}
#ifdef MOD_PERSO
} else if (!strncmp(p, "ssh:", 4)) {
} else if (!strncmp(p, "ssh:", 4)) {
char *pst = (char*)malloc(strlen(p)+1) ; strcpy(pst,p);
char *q = (char*)pst ;
/*
* If the hostname starts with "ssh:",
* set the protocol to SSH and process
* the string as a SSH URL
*/
char c;
q += 4;
if (q[0] == '/' && q[1] == '/')
q += 2;
conf_set_int( conf, CONF_protocol, PROT_SSH);
pst = q;
while (*pst && *pst != ':' && *pst != '/')
pst++;
c = *pst;
/*
* If the hostname starts with "ssh:",
* set the protocol to SSH and process
* the string as a SSH URL
*/
q += 4;
if (q[0] == '/' && q[1] == '/')
q += 2;
//while (*q && *q != ':' && *q != '/') q++ ;
conf_set_int( conf, CONF_protocol, PROT_SSH);
conf_set_int( conf, CONF_port, 22);
ManageConnectString( conf, q ) ;
if (*pst) *pst++ = '\0';
if (c == ':')
conf_set_int( conf,CONF_port,atoi(pst));
else if( (c == '/')&&(strlen(pst)>0) ) {
conf_set_int( conf,CONF_port,22);
char * buf;
buf=(char*)malloc(strlen(pst)+10);
strcpy(buf,pst);
if( pst[0]=='#' ) {
decryptstring( (char*)pst+1, MASTER_PASSWORD ) ;
conf_set_str( conf,CONF_autocommand, pst+1);
}
else
{
char *s = (char*)malloc( strlen(pst)+1 ) ;
strcpy( s, pst ) ;
int i = decode64(s) ;
s[i]='\0';
conf_set_str(conf,CONF_autocommand,s);
free(s);
}
free(buf);
}
else
conf_set_int( conf,CONF_port,22) ;
char * buf;
buf=(char*)malloc( strlen(q)+10 );
strncpy(buf,q,strlen(q)+1);
buf[strlen(q)+1] = '\0' ;
conf_set_str( conf, CONF_host, buf);
free(buf);
seen_hostname_argument = true ;
conf_set_str( conf, CONF_host, q ) ;
seen_hostname_argument = true ;
free(pst);
} else if (!strncmp(p, "putty:", 4)) {
} else if (!strncmp(p, "putty:", 4)) {
char * q = (char*)p ;
int ret = 0;
q += 6;
@@ -348,9 +404,7 @@ int cmdline_process_param(const char *p, char *value,
backend_vt_from_name(prefix);
if (vt) {
default_protocol = vt->protocol;
conf_set_int(conf, CONF_protocol,
default_protocol);
set_protocol(conf, vt->protocol);
port_override = vt->default_port;
} else {
cmdline_error("unrecognised protocol prefix '%s'",
@@ -392,6 +446,10 @@ int cmdline_process_param(const char *p, char *value,
hostname[len-1] == '\t'))
hostname[--len] = '\0';
seen_hostname_argument = true;
#ifdef MOD_PERSO
// Manage connect string user:pass@hostname
ManageConnectString( conf, hostname ) ;
#endif
conf_set_str(conf, CONF_host, hostname);
if ((cmdline_tooltype & TOOLTYPE_HOST_ARG_CAN_BE_SESSION) &&
@@ -470,48 +528,35 @@ int cmdline_process_param(const char *p, char *value,
RETURN(2);
/* This parameter must be processed immediately rather than being
* saved. */
#if MOD_PERSO
if( IniFileFlag == SAVEMODE_REG ) {
do_defaults(value, conf);
loaded_session = true;
} else {
char *pst = strstr( value, "/" ) ;
if( pst==NULL ) {
do_defaults(value, conf);
loaded_session = true;
} else {
char *name = (char*)malloc( strlen(value)+1 ) ;
strcpy(name,value) ;
pst = strstr( name, "/" ) ;
pst[0]='\0';
conf_set_str(conf,CONF_folder,name) ;
SetSessPath( name ) ;
strcpy( CurrentFolder, name ) ;
do_defaults(pst+1, conf);
loaded_session = true;
free(value) ;
}
}
#else
do_defaults(value, conf);
loaded_session = true;
cmdline_session_name = dupstr(value);
#endif
return 2;
}
if (!strcmp(p, "-ssh")) {
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
SAVEABLE(0);
default_protocol = PROT_SSH;
default_port = 22;
conf_set_int(conf, CONF_protocol, default_protocol);
conf_set_int(conf, CONF_port, default_port);
return 1;
}
if (!strcmp(p, "-telnet")) {
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
SAVEABLE(0);
default_protocol = PROT_TELNET;
default_port = 23;
conf_set_int(conf, CONF_protocol, default_protocol);
conf_set_int(conf, CONF_port, default_port);
return 1;
}
if (!strcmp(p, "-rlogin")) {
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
SAVEABLE(0);
default_protocol = PROT_RLOGIN;
default_port = 513;
conf_set_int(conf, CONF_protocol, default_protocol);
conf_set_int(conf, CONF_port, default_port);
return 1;
}
if (!strcmp(p, "-raw")) {
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
SAVEABLE(0);
default_protocol = PROT_RAW;
conf_set_int(conf, CONF_protocol, default_protocol);
}
#ifdef MOD_PERSO
if (!strcmp(p, "-kload")) {
RETURN(2);
@@ -519,9 +564,13 @@ int cmdline_process_param(const char *p, char *value,
* saved. */
load_open_settings_forced( value, conf ) ;
loaded_session = true;
cmdline_session_name = dupstr(value);
//cmdline_session_name = dupstr(value);
return 2;
}
if (!strcmp(p, "-knock")) {
RETURN(2);
conf_set_str( conf, CONF_portknockingoptions, value ) ;
}
if ( !strcmp(p, "-auto_store_sshkey") || !strcmp(p, "-auto-store-sshkey") ) {
RETURN(1);
SetAutoStoreSSHKey();
@@ -532,24 +581,32 @@ int cmdline_process_param(const char *p, char *value,
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
SAVEABLE(0);
default_protocol = PROT_ADB;
conf_set_int(conf, CONF_protocol, default_protocol);
//default_protocol = PROT_ADB;
conf_set_int(conf, CONF_protocol, PROT_ADB);
}
#endif
if (!strcmp(p, "-serial")) {
RETURN(1);
/* Serial is not NONNETWORK in an odd sense of the word */
UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
SAVEABLE(0);
default_protocol = PROT_SERIAL;
conf_set_int(conf, CONF_protocol, default_protocol);
/* The host parameter will already be loaded into CONF_host,
* so copy it across */
conf_set_str(conf, CONF_serline, conf_get_str(conf, CONF_host));
for (size_t i = 0; backends[i]; i++) {
if (p[0] == '-' && !strcmp(p+1, backends[i]->id)) {
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
SAVEABLE(0);
set_protocol(conf, backends[i]->protocol);
if (backends[i]->default_port)
set_port(conf, backends[i]->default_port);
if (backends[i]->protocol == PROT_SERIAL) {
/* Special handling: the 'where to connect to' argument will
* have been placed into CONF_host, but for this protocol, it
* needs to be in CONF_serline */
conf_set_str(conf, CONF_serline,
conf_get_str(conf, CONF_host));
}
return 1;
}
}
if (!strcmp(p, "-v")) {
RETURN(1);
flags |= FLAG_VERBOSE;
UNAVAILABLE_IN(TOOLTYPE_NO_VERBOSE_OPTION);
seen_verbose_option = true;
}
if (!strcmp(p, "-l")) {
RETURN(2);
@@ -686,7 +743,7 @@ int cmdline_process_param(const char *p, char *value,
if (!strcmp(p, "-P")) {
RETURN(2);
UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
SAVEABLE(1); /* lower priority than -ssh,-telnet */
SAVEABLE(1); /* lower priority than -ssh, -telnet, etc */
conf_set_int(conf, CONF_port, atoi(value));
}
if (!strcmp(p, "-pw")) {
@@ -721,6 +778,13 @@ int cmdline_process_param(const char *p, char *value,
SAVEABLE(0);
conf_set_bool(conf, CONF_tryagent, false);
}
if (!strcmp(p, "-no-trivial-auth")) {
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
SAVEABLE(0);
conf_set_bool(conf, CONF_ssh_no_trivial_userauth, true);
}
if (!strcmp(p, "-share")) {
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
@@ -930,6 +994,20 @@ int cmdline_process_param(const char *p, char *value,
filename_free(fn);
}
if (!strcmp(p, "-logoverwrite")) {
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
SAVEABLE(0);
conf_set_int(conf, CONF_logxfovr, LGXF_OVR);
}
if (!strcmp(p, "-logappend")) {
RETURN(1);
UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
SAVEABLE(0);
conf_set_int(conf, CONF_logxfovr, LGXF_APN);
}
if (!strcmp(p, "-proxycmd")) {
RETURN(2);
UNAVAILABLE_IN(TOOLTYPE_NONNETWORK);
@@ -946,7 +1024,6 @@ int cmdline_process_param(const char *p, char *value,
!strcmp(p, "-restrictacl")) {
RETURN(1);
restrict_process_acl();
restricted_acl = true;
}
#endif
@@ -955,9 +1032,8 @@ int cmdline_process_param(const char *p, char *value,
void cmdline_run_saved(Conf *conf)
{
int pri, i;
for (pri = 0; pri < NPRIORITIES; pri++) {
for (i = 0; i < saves[pri].nsaved; i++) {
for (size_t pri = 0; pri < NPRIORITIES; pri++) {
for (size_t i = 0; i < saves[pri].nsaved; i++) {
cmdline_process_param(saves[pri].params[i].p,
saves[pri].params[i].value, 0, conf);
sfree(saves[pri].params[i].p);
File diff suppressed because it is too large Load Diff
+113
View File
@@ -0,0 +1,113 @@
/*
* Common pieces between the platform console frontend modules.
*/
#include <stdbool.h>
#include <stdarg.h>
#include "putty.h"
#include "misc.h"
#include "console.h"
const char hk_absentmsg_common_fmt[] =
"The server's host key is not cached. You have no guarantee\n"
"that the server is the computer you think it is.\n"
"The server's %s key fingerprint is:\n"
"%s\n";
const char hk_absentmsg_interactive_intro[] =
"If you trust this host, enter \"y\" to add the key to\n"
"PuTTY's cache and carry on connecting.\n"
"If you want to carry on connecting just once, without\n"
"adding the key to the cache, enter \"n\".\n"
"If you do not trust this host, press Return to abandon the\n"
"connection.\n";
const char hk_absentmsg_interactive_prompt[] =
"Store key in cache? (y/n, Return cancels connection, "
"i for more info) ";
const char hk_wrongmsg_common_fmt[] =
"WARNING - POTENTIAL SECURITY BREACH!\n"
"The server's host key does not match the one PuTTY has\n"
"cached. This means that either the server administrator\n"
"has changed the host key, or you have actually connected\n"
"to another computer pretending to be the server.\n"
"The new %s key fingerprint is:\n"
"%s\n";
const char hk_wrongmsg_interactive_intro[] =
"If you were expecting this change and trust the new key,\n"
"enter \"y\" to update PuTTY's cache and continue connecting.\n"
"If you want to carry on connecting but without updating\n"
"the cache, enter \"n\".\n"
"If you want to abandon the connection completely, press\n"
"Return to cancel. Pressing Return is the ONLY guaranteed\n"
"safe choice.\n";
const char hk_wrongmsg_interactive_prompt[] =
"Update cached key? (y/n, Return cancels connection, "
"i for more info) ";
const char weakcrypto_msg_common_fmt[] =
"The first %s supported by the server is\n"
"%s, which is below the configured warning threshold.\n";
const char weakhk_msg_common_fmt[] =
"The first host key type we have stored for this server\n"
"is %s, which is below the configured warning threshold.\n"
"The server also provides the following types of host key\n"
"above the threshold, which we do not have stored:\n"
"%s\n";
const char console_continue_prompt[] = "Continue with connection? (y/n) ";
const char console_abandoned_msg[] = "Connection abandoned.\n";
bool console_batch_mode = false;
/*
* Error message and/or fatal exit functions, all based on
* console_print_error_msg which the platform front end provides.
*/
void console_print_error_msg_fmt_v(
const char *prefix, const char *fmt, va_list ap)
{
char *msg = dupvprintf(fmt, ap);
console_print_error_msg(prefix, msg);
sfree(msg);
}
void console_print_error_msg_fmt(const char *prefix, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
console_print_error_msg_fmt_v(prefix, fmt, ap);
va_end(ap);
}
void modalfatalbox(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
console_print_error_msg_fmt_v("FATAL ERROR", fmt, ap);
va_end(ap);
cleanup_exit(1);
}
void nonfatal(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
console_print_error_msg_fmt_v("ERROR", fmt, ap);
va_end(ap);
}
void console_connection_fatal(Seat *seat, const char *msg)
{
console_print_error_msg("FATAL ERROR", msg);
cleanup_exit(1);
}
/*
* Console front ends redo their select() or equivalent every time, so
* they don't need separate timer handling.
*/
void timer_change_notify(unsigned long next)
{
}
+17
View File
@@ -0,0 +1,17 @@
/*
* Common pieces between the platform console frontend modules.
*/
extern const char hk_absentmsg_common_fmt[];
extern const char hk_absentmsg_interactive_intro[];
extern const char hk_absentmsg_interactive_prompt[];
extern const char hk_wrongmsg_common_fmt[];
extern const char hk_wrongmsg_interactive_intro[];
extern const char hk_wrongmsg_interactive_prompt[];
extern const char weakcrypto_msg_common_fmt[];
extern const char weakhk_msg_common_fmt[];
extern const char console_continue_prompt[];
extern const char console_abandoned_msg[];
+221 -189
View File
@@ -1,189 +1,221 @@
/*
* defs.h: initial definitions for PuTTY.
*
* The rule about this header file is that it can't depend on any
* other header file in this code base. This is where we define
* things, as much as we can, that other headers will want to refer
* to, such as opaque structure types and their associated typedefs,
* or macros that are used by other headers.
*/
#ifndef PUTTY_DEFS_H
#define PUTTY_DEFS_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#if defined _MSC_VER && _MSC_VER < 1800
/* Work around lack of inttypes.h and strtoumax in older MSVC */
#define PRIx32 "x"
#define PRIu64 "I64u"
#define PRIdMAX "I64d"
#define PRIXMAX "I64X"
#define SCNu64 "I64u"
uintmax_t strtoumax(const char *nptr, char **endptr, int base);
#else
#include <inttypes.h>
#endif
typedef struct conf_tag Conf;
typedef struct terminal_tag Terminal;
typedef struct term_utf8_decode term_utf8_decode;
typedef struct Filename Filename;
typedef struct FontSpec FontSpec;
typedef struct bufchain_tag bufchain;
typedef struct strbuf strbuf;
typedef struct RSAKey RSAKey;
typedef struct BinarySink BinarySink;
typedef struct BinarySource BinarySource;
typedef struct stdio_sink stdio_sink;
typedef struct bufchain_sink bufchain_sink;
typedef struct handle_sink handle_sink;
typedef struct IdempotentCallback IdempotentCallback;
typedef struct SockAddr SockAddr;
typedef struct Socket Socket;
typedef struct Plug Plug;
typedef struct SocketPeerInfo SocketPeerInfo;
typedef struct Backend Backend;
typedef struct BackendVtable BackendVtable;
typedef struct Ldisc_tag Ldisc;
typedef struct LogContext LogContext;
typedef struct LogPolicy LogPolicy;
typedef struct LogPolicyVtable LogPolicyVtable;
typedef struct Seat Seat;
typedef struct SeatVtable SeatVtable;
typedef struct TermWin TermWin;
typedef struct TermWinVtable TermWinVtable;
typedef struct Ssh Ssh;
typedef struct mp_int mp_int;
typedef struct MontyContext MontyContext;
typedef struct WeierstrassCurve WeierstrassCurve;
typedef struct WeierstrassPoint WeierstrassPoint;
typedef struct MontgomeryCurve MontgomeryCurve;
typedef struct MontgomeryPoint MontgomeryPoint;
typedef struct EdwardsCurve EdwardsCurve;
typedef struct EdwardsPoint EdwardsPoint;
typedef struct SshServerConfig SshServerConfig;
typedef struct SftpServer SftpServer;
typedef struct SftpServerVtable SftpServerVtable;
typedef struct Channel Channel;
typedef struct SshChannel SshChannel;
typedef struct mainchan mainchan;
typedef struct ssh_sharing_state ssh_sharing_state;
typedef struct ssh_sharing_connstate ssh_sharing_connstate;
typedef struct share_channel share_channel;
typedef struct PortFwdManager PortFwdManager;
typedef struct PortFwdRecord PortFwdRecord;
typedef struct ConnectionLayer ConnectionLayer;
typedef struct prng prng;
typedef struct ssh_hashalg ssh_hashalg;
typedef struct ssh_hash ssh_hash;
typedef struct ssh_kex ssh_kex;
typedef struct ssh_kexes ssh_kexes;
typedef struct ssh_keyalg ssh_keyalg;
typedef struct ssh_key ssh_key;
typedef struct ssh_compressor ssh_compressor;
typedef struct ssh_decompressor ssh_decompressor;
typedef struct ssh_compression_alg ssh_compression_alg;
typedef struct ssh2_userkey ssh2_userkey;
typedef struct ssh2_macalg ssh2_macalg;
typedef struct ssh2_mac ssh2_mac;
typedef struct ssh_cipheralg ssh_cipheralg;
typedef struct ssh_cipher ssh_cipher;
typedef struct ssh2_ciphers ssh2_ciphers;
typedef struct dh_ctx dh_ctx;
typedef struct ecdh_key ecdh_key;
typedef struct dlgparam dlgparam;
typedef struct settings_w settings_w;
typedef struct settings_r settings_r;
typedef struct settings_e settings_e;
typedef struct SessionSpecial SessionSpecial;
typedef struct StripCtrlChars StripCtrlChars;
/*
* A small structure wrapping up a (pointer, length) pair so that it
* can be conveniently passed to or from a function.
*/
typedef struct ptrlen {
const void *ptr;
size_t len;
} ptrlen;
typedef struct logblank_t logblank_t;
typedef struct BinaryPacketProtocol BinaryPacketProtocol;
typedef struct PacketProtocolLayer PacketProtocolLayer;
/* Do a compile-time type-check of 'to_check' (without evaluating it),
* as a side effect of returning the value 'to_return'. Note that
* although this macro double-*expands* to_return, it always
* *evaluates* exactly one copy of it, so it's side-effect safe. */
#define TYPECHECK(to_check, to_return) \
(sizeof(to_check) ? (to_return) : (to_return))
/* Return a pointer to the object of structure type 'type' whose field
* with name 'field' is pointed at by 'object'. */
#define container_of(object, type, field) \
TYPECHECK(object == &((type *)0)->field, \
((type *)(((char *)(object)) - offsetof(type, field))))
#if defined __GNUC__ || defined __clang__
#define NORETURN __attribute__((__noreturn__))
#else
#define NORETURN
#endif
/* ----------------------------------------------------------------------
* Platform-specific definitions.
*
* Most of these live in the per-platform header files, of which
* puttyps.h selects the appropriate one. But some of the sources
* (particularly standalone test applications) would prefer not to
* have to include a per-platform header at all, because that makes it
* more portable to platforms not supported by the code base as a
* whole (for example, compiling purely computational parts of the
* code for specialist platforms for test and analysis purposes). So
* any definition that has to affect even _those_ modules will have to
* go here, with the key constraint being that this code has to come
* to _some_ decision even if the compilation platform is not a
* recognised one at all.
*/
/* Purely computational code uses smemclr(), so we have to make the
* decision here about whether that's provided by utils.c or by a
* platform implementation. We define PLATFORM_HAS_SMEMCLR to suppress
* utils.c's definition. */
#ifdef _WINDOWS
/* Windows provides the API function 'SecureZeroMemory', which we use
* unless the user has told us not to by defining NO_SECUREZEROMEMORY. */
#ifndef NO_SECUREZEROMEMORY
#define PLATFORM_HAS_SMEMCLR
#endif
#endif
#endif /* PUTTY_DEFS_H */
/*
* defs.h: initial definitions for PuTTY.
*
* The rule about this header file is that it can't depend on any
* other header file in this code base. This is where we define
* things, as much as we can, that other headers will want to refer
* to, such as opaque structure types and their associated typedefs,
* or macros that are used by other headers.
*/
#ifndef PUTTY_DEFS_H
#define PUTTY_DEFS_H
#include <stddef.h>
#include <stdint.h>
#include <stdio.h> /* for __MINGW_PRINTF_FORMAT */
#include <stdbool.h>
#if defined _MSC_VER && _MSC_VER < 1800
/* Work around lack of inttypes.h and strtoumax in older MSVC */
#define PRIx32 "x"
#define PRIu32 "u"
#define PRIu64 "I64u"
#define PRIdMAX "I64d"
#define PRIXMAX "I64X"
#define SCNu64 "I64u"
#define SIZEx "Ix"
#define SIZEu "Iu"
uintmax_t strtoumax(const char *nptr, char **endptr, int base);
#else
#include <inttypes.h>
/* Because we still support older MSVC libraries which don't recognise the
* standard C "z" modifier for size_t-sized integers, we must use an
* inttypes.h-style macro for those */
#define SIZEx "zx"
#define SIZEu "zu"
#endif
#if defined __GNUC__ || defined __clang__
/*
* On MinGW, the correct compiler format checking for vsnprintf() etc
* can depend on compile-time flags; these control whether you get
* ISO C or Microsoft's non-standard format strings.
* We sometimes use __attribute__ ((format)) for our own printf-like
* functions, which are ultimately interpreted by the toolchain-chosen
* printf, so we need to take that into account to get correct warnings.
*/
#ifdef __MINGW_PRINTF_FORMAT
#define PRINTF_LIKE(fmt_index, ellipsis_index) \
__attribute__ ((format (__MINGW_PRINTF_FORMAT, fmt_index, ellipsis_index)))
#else
#define PRINTF_LIKE(fmt_index, ellipsis_index) \
__attribute__ ((format (printf, fmt_index, ellipsis_index)))
#endif
#else /* __GNUC__ */
#define PRINTF_LIKE(fmt_index, ellipsis_index)
#endif /* __GNUC__ */
typedef struct conf_tag Conf;
typedef struct terminal_tag Terminal;
typedef struct term_utf8_decode term_utf8_decode;
typedef struct Filename Filename;
typedef struct FontSpec FontSpec;
typedef struct bufchain_tag bufchain;
typedef struct strbuf strbuf;
typedef struct LoadedFile LoadedFile;
typedef struct RSAKey RSAKey;
typedef struct BinarySink BinarySink;
typedef struct BinarySource BinarySource;
typedef struct stdio_sink stdio_sink;
typedef struct bufchain_sink bufchain_sink;
typedef struct handle_sink handle_sink;
typedef struct IdempotentCallback IdempotentCallback;
typedef struct SockAddr SockAddr;
typedef struct Socket Socket;
typedef struct Plug Plug;
typedef struct SocketPeerInfo SocketPeerInfo;
typedef struct Backend Backend;
typedef struct BackendVtable BackendVtable;
typedef struct Ldisc_tag Ldisc;
typedef struct LogContext LogContext;
typedef struct LogPolicy LogPolicy;
typedef struct LogPolicyVtable LogPolicyVtable;
typedef struct Seat Seat;
typedef struct SeatVtable SeatVtable;
typedef struct TermWin TermWin;
typedef struct TermWinVtable TermWinVtable;
typedef struct Ssh Ssh;
typedef struct mp_int mp_int;
typedef struct MontyContext MontyContext;
typedef struct WeierstrassCurve WeierstrassCurve;
typedef struct WeierstrassPoint WeierstrassPoint;
typedef struct MontgomeryCurve MontgomeryCurve;
typedef struct MontgomeryPoint MontgomeryPoint;
typedef struct EdwardsCurve EdwardsCurve;
typedef struct EdwardsPoint EdwardsPoint;
typedef struct SshServerConfig SshServerConfig;
typedef struct SftpServer SftpServer;
typedef struct SftpServerVtable SftpServerVtable;
typedef struct Channel Channel;
typedef struct SshChannel SshChannel;
typedef struct mainchan mainchan;
typedef struct ssh_sharing_state ssh_sharing_state;
typedef struct ssh_sharing_connstate ssh_sharing_connstate;
typedef struct share_channel share_channel;
typedef struct PortFwdManager PortFwdManager;
typedef struct PortFwdRecord PortFwdRecord;
typedef struct ConnectionLayer ConnectionLayer;
typedef struct prng prng;
typedef struct ssh_hashalg ssh_hashalg;
typedef struct ssh_hash ssh_hash;
typedef struct ssh_kex ssh_kex;
typedef struct ssh_kexes ssh_kexes;
typedef struct ssh_keyalg ssh_keyalg;
typedef struct ssh_key ssh_key;
typedef struct ssh_compressor ssh_compressor;
typedef struct ssh_decompressor ssh_decompressor;
typedef struct ssh_compression_alg ssh_compression_alg;
typedef struct ssh2_userkey ssh2_userkey;
typedef struct ssh2_macalg ssh2_macalg;
typedef struct ssh2_mac ssh2_mac;
typedef struct ssh_cipheralg ssh_cipheralg;
typedef struct ssh_cipher ssh_cipher;
typedef struct ssh2_ciphers ssh2_ciphers;
typedef struct dh_ctx dh_ctx;
typedef struct ecdh_key ecdh_key;
typedef struct dlgparam dlgparam;
typedef struct settings_w settings_w;
typedef struct settings_r settings_r;
typedef struct settings_e settings_e;
typedef struct SessionSpecial SessionSpecial;
typedef struct StripCtrlChars StripCtrlChars;
/*
* A small structure wrapping up a (pointer, length) pair so that it
* can be conveniently passed to or from a function.
*/
typedef struct ptrlen {
const void *ptr;
size_t len;
} ptrlen;
typedef struct logblank_t logblank_t;
typedef struct BinaryPacketProtocol BinaryPacketProtocol;
typedef struct PacketProtocolLayer PacketProtocolLayer;
/* Do a compile-time type-check of 'to_check' (without evaluating it),
* as a side effect of returning the value 'to_return'. Note that
* although this macro double-*expands* to_return, it always
* *evaluates* exactly one copy of it, so it's side-effect safe. */
#define TYPECHECK(to_check, to_return) \
(sizeof(to_check) ? (to_return) : (to_return))
/* Return a pointer to the object of structure type 'type' whose field
* with name 'field' is pointed at by 'object'. */
#define container_of(object, type, field) \
TYPECHECK(object == &((type *)0)->field, \
((type *)(((char *)(object)) - offsetof(type, field))))
#if defined __GNUC__ || defined __clang__
#define NORETURN __attribute__((__noreturn__))
#elif defined _MSC_VER
#define NORETURN __declspec(noreturn)
#else
#define NORETURN
#endif
/* ----------------------------------------------------------------------
* Platform-specific definitions.
*
* Most of these live in the per-platform header files, of which
* puttyps.h selects the appropriate one. But some of the sources
* (particularly standalone test applications) would prefer not to
* have to include a per-platform header at all, because that makes it
* more portable to platforms not supported by the code base as a
* whole (for example, compiling purely computational parts of the
* code for specialist platforms for test and analysis purposes). So
* any definition that has to affect even _those_ modules will have to
* go here, with the key constraint being that this code has to come
* to _some_ decision even if the compilation platform is not a
* recognised one at all.
*/
/* Purely computational code uses smemclr(), so we have to make the
* decision here about whether that's provided by utils.c or by a
* platform implementation. We define PLATFORM_HAS_SMEMCLR to suppress
* utils.c's definition. */
#ifdef _WINDOWS
/* Windows provides the API function 'SecureZeroMemory', which we use
* unless the user has told us not to by defining NO_SECUREZEROMEMORY. */
#ifndef NO_SECUREZEROMEMORY
#define PLATFORM_HAS_SMEMCLR
#endif
#endif
#endif /* PUTTY_DEFS_H */
@@ -221,6 +221,7 @@ static union control *ctrl_new(struct controlset *s, int type,
c->generic.handler = handler;
c->generic.context = context;
c->generic.label = NULL;
c->generic.align_next_to = NULL;
return c;
}
@@ -352,7 +353,6 @@ union control *ctrl_listbox(struct controlset *s, const char *label,
c->listbox.percentwidth = 100;
c->listbox.ncols = 0;
c->listbox.percentages = NULL;
c->listbox.hscroll = true;
return c;
}
@@ -116,7 +116,8 @@ typedef void (*handler_fn)(union control *ctrl, dlgparam *dp,
int column; \
handler_fn handler; \
intorptr context; \
intorptr helpctx
intorptr helpctx; \
union control *align_next_to
union control {
/*
@@ -182,6 +183,18 @@ union control {
* to ensure it brings up the right piece of help text.
*/
intorptr helpctx;
/*
* Setting this to non-NULL coerces two controls to have their
* y-coordinates adjusted so that they can sit alongside each
* other and look nicely aligned, even if they're different
* heights.
*
* Set this field on the _second_ control of the pair (in
* terms of order in the data structure), so that when it's
* instantiated, the first one is already there to be referred
* to.
*/
union control *align_next_to;
} generic;
struct {
STANDARD_PREFIX;
File diff suppressed because it is too large Load Diff
+243 -238
View File
@@ -1,238 +1,243 @@
#ifndef PUTTY_ECC_H
#define PUTTY_ECC_H
/*
* Arithmetic functions for the various kinds of elliptic curves used
* by PuTTY's public-key cryptography.
*
* All of these elliptic curves are over the finite field whose order
* is a large prime p. (Elliptic curves over a field of order 2^n are
* also known, but PuTTY currently has no need of them.)
*/
/* ----------------------------------------------------------------------
* Weierstrass curves (or rather, 'short form' Weierstrass curves).
*
* A curve in this form is defined by two parameters a,b, and the
* non-identity points on the curve are represented by (x,y) (the
* 'affine coordinates') such that y^2 = x^3 + ax + b.
*
* The identity element of the curve's group is an additional 'point
* at infinity', which is considered to be the third point on the
* intersection of the curve with any vertical line. Hence, the
* inverse of the point (x,y) is (x,-y).
*/
/*
* Create and destroy Weierstrass curve data structures. The mandatory
* parameters to the constructor are the prime modulus p, and the
* curve parameters a,b.
*
* 'nonsquare_mod_p' is an optional extra parameter, only needed by
* ecc_edwards_point_new_from_y which has to take a modular square
* root. You can pass it as NULL if you don't need that function.
*/
WeierstrassCurve *ecc_weierstrass_curve(
mp_int *p, mp_int *a, mp_int *b, mp_int *nonsquare_mod_p);
void ecc_weierstrass_curve_free(WeierstrassCurve *);
/*
* Create points on a Weierstrass curve, given the curve.
*
* point_new_identity returns the special identity point.
* point_new(x,y) returns the non-identity point with the given affine
* coordinates.
*
* point_new_from_x constructs a non-identity point given only the
* x-coordinate, by using the curve equation to work out what y has to
* be. Of course the equation only tells you y^2, so it only
* determines y up to sign; the parameter desired_y_parity controls
* which of the two values of y you get, by saying whether you'd like
* its minimal non-negative residue mod p to be even or odd. (Of
* course, since p itself is odd, exactly one of y and p-y is odd.)
* This function has to take a modular square root, so it will only
* work if you passed in a non-square mod p when constructing the
* curve.
*/
WeierstrassPoint *ecc_weierstrass_point_new_identity(WeierstrassCurve *curve);
WeierstrassPoint *ecc_weierstrass_point_new(
WeierstrassCurve *curve, mp_int *x, mp_int *y);
WeierstrassPoint *ecc_weierstrass_point_new_from_x(
WeierstrassCurve *curve, mp_int *x, unsigned desired_y_parity);
/* Memory management: copy and free points. */
void ecc_weierstrass_point_copy_into(
WeierstrassPoint *dest, WeierstrassPoint *src);
WeierstrassPoint *ecc_weierstrass_point_copy(WeierstrassPoint *wc);
void ecc_weierstrass_point_free(WeierstrassPoint *point);
/* Check whether a point is actually on the curve. */
unsigned ecc_weierstrass_point_valid(WeierstrassPoint *);
/*
* Add two points and return their sum. This function is fully
* general: it should do the right thing if the two inputs are the
* same, or if either (or both) of the input points is the identity,
* or if the two input points are inverses so the output is the
* identity. However, it pays for that generality by being slower than
* the special-purpose functions below..
*/
WeierstrassPoint *ecc_weierstrass_add_general(
WeierstrassPoint *, WeierstrassPoint *);
/*
* Fast but less general arithmetic functions: add two points on the
* condition that they are not equal and neither is the identity, and
* add a point to itself.
*/
WeierstrassPoint *ecc_weierstrass_add(WeierstrassPoint *, WeierstrassPoint *);
WeierstrassPoint *ecc_weierstrass_double(WeierstrassPoint *);
/*
* Compute an integer multiple of a point. Not guaranteed to work
* unless the integer argument is less than the order of the point in
* the group (because it won't cope if an identity element shows up in
* any intermediate product).
*/
WeierstrassPoint *ecc_weierstrass_multiply(WeierstrassPoint *, mp_int *);
/*
* Query functions to get the value of a point back out. is_identity
* tells you whether the point is the identity; if it isn't, then
* get_affine will retrieve one or both of its affine coordinates.
* (You can pass NULL as either output pointer, if you don't need that
* coordinate as output.)
*/
unsigned ecc_weierstrass_is_identity(WeierstrassPoint *wp);
void ecc_weierstrass_get_affine(WeierstrassPoint *wp, mp_int **x, mp_int **y);
/* ----------------------------------------------------------------------
* Montgomery curves.
*
* A curve in this form is defined by two parameters a,b, and the
* curve equation is by^2 = x^3 + ax^2 + x.
*
* As with Weierstrass curves, there's an additional point at infinity
* that is the identity element, and the inverse of (x,y) is (x,-y).
*
* However, we don't actually work with full (x,y) pairs. We just
* store the x-coordinate (so what we're really representing is not a
* specific point on the curve but a two-point set {P,-P}). This means
* you can't quite do point addition, because if you're given {P,-P}
* and {Q,-Q} as input, you can work out a pair of x-coordinates that
* are those of P-Q and P+Q, but you don't know which is which.
*
* Instead, the basic operation is 'differential addition', in which
* you are given three parameters P, Q and P-Q and you return P+Q. (As
* well as disambiguating which of the possible answers you want, that
* extra input also enables a fast formulae for computing it. This
* fast formula is more or less why Montgomery curves are useful in
* the first place.)
*
* Doubling a point is still possible to do unambiguously, so you can
* still compute an integer multiple of P if you start by making 2P
* and then doing a series of differential additions.
*/
/*
* Create and destroy Montgomery curve data structures.
*/
MontgomeryCurve *ecc_montgomery_curve(mp_int *p, mp_int *a, mp_int *b);
void ecc_montgomery_curve_free(MontgomeryCurve *);
/*
* Create, copy and free points on the curve. We don't need to
* explicitly represent the identity for this application.
*/
MontgomeryPoint *ecc_montgomery_point_new(MontgomeryCurve *mc, mp_int *x);
void ecc_montgomery_point_copy_into(
MontgomeryPoint *dest, MontgomeryPoint *src);
MontgomeryPoint *ecc_montgomery_point_copy(MontgomeryPoint *orig);
void ecc_montgomery_point_free(MontgomeryPoint *mp);
/*
* Basic arithmetic routines: differential addition and point-
* doubling. Each of these assumes that no special cases come up - no
* input or output point should be the identity, and in diff_add, P
* and Q shouldn't be the same.
*/
MontgomeryPoint *ecc_montgomery_diff_add(
MontgomeryPoint *P, MontgomeryPoint *Q, MontgomeryPoint *PminusQ);
MontgomeryPoint *ecc_montgomery_double(MontgomeryPoint *P);
/*
* Compute an integer multiple of a point.
*/
MontgomeryPoint *ecc_montgomery_multiply(MontgomeryPoint *, mp_int *);
/*
* Return the affine x-coordinate of a point.
*/
void ecc_montgomery_get_affine(MontgomeryPoint *mp, mp_int **x);
/* ----------------------------------------------------------------------
* Twisted Edwards curves.
*
* A curve in this form is defined by two parameters d,a, and the
* curve equation is a x^2 + y^2 = 1 + d x^2 y^2.
*
* Apparently if you ask a proper algebraic geometer they'll tell you
* that this is technically not an actual elliptic curve. Certainly it
* doesn't work quite the same way as the other kinds: in this form,
* there is no need for a point at infinity, because the identity
* element is represented by the affine coordinates (0,1). And you
* invert a point by negating its x rather than y coordinate: the
* inverse of (x,y) is (-x,y).
*
* The usefulness of this representation is that the addition formula
* is 'strongly unified', meaning that the same formula works for any
* input and output points, without needing special cases for the
* identity or for doubling.
*/
/*
* Create and destroy Edwards curve data structures.
*
* Similarly to ecc_weierstrass_curve, you don't have to provide
* nonsquare_mod_p if you don't need ecc_edwards_point_new_from_y.
*/
EdwardsCurve *ecc_edwards_curve(
mp_int *p, mp_int *d, mp_int *a, mp_int *nonsquare_mod_p);
void ecc_edwards_curve_free(EdwardsCurve *);
/*
* Create points.
*
* There's no need to have a separate function to create the identity
* point, because you can just pass x=0 and y=1 to the usual function.
*
* Similarly to the Weierstrass curve, ecc_edwards_point_new_from_y
* creates a point given only its y-coordinate and the desired parity
* of its x-coordinate, and you can only call it if you provided the
* optional nonsquare_mod_p argument when creating the curve.
*/
EdwardsPoint *ecc_edwards_point_new(
EdwardsCurve *curve, mp_int *x, mp_int *y);
EdwardsPoint *ecc_edwards_point_new_from_y(
EdwardsCurve *curve, mp_int *y, unsigned desired_x_parity);
/* Copy and free points. */
void ecc_edwards_point_copy_into(EdwardsPoint *dest, EdwardsPoint *src);
EdwardsPoint *ecc_edwards_point_copy(EdwardsPoint *ec);
void ecc_edwards_point_free(EdwardsPoint *point);
/*
* Arithmetic: add two points, and calculate an integer multiple of a
* point.
*/
EdwardsPoint *ecc_edwards_add(EdwardsPoint *, EdwardsPoint *);
EdwardsPoint *ecc_edwards_multiply(EdwardsPoint *, mp_int *);
/*
* Query functions: compare two points for equality, and return the
* affine coordinates of a point.
*/
unsigned ecc_edwards_eq(EdwardsPoint *, EdwardsPoint *);
void ecc_edwards_get_affine(EdwardsPoint *wp, mp_int **x, mp_int **y);
#endif /* PUTTY_ECC_H */
#ifndef PUTTY_ECC_H
#define PUTTY_ECC_H
/*
* Arithmetic functions for the various kinds of elliptic curves used
* by PuTTY's public-key cryptography.
*
* All of these elliptic curves are over the finite field whose order
* is a large prime p. (Elliptic curves over a field of order 2^n are
* also known, but PuTTY currently has no need of them.)
*/
/* ----------------------------------------------------------------------
* Weierstrass curves (or rather, 'short form' Weierstrass curves).
*
* A curve in this form is defined by two parameters a,b, and the
* non-identity points on the curve are represented by (x,y) (the
* 'affine coordinates') such that y^2 = x^3 + ax + b.
*
* The identity element of the curve's group is an additional 'point
* at infinity', which is considered to be the third point on the
* intersection of the curve with any vertical line. Hence, the
* inverse of the point (x,y) is (x,-y).
*/
/*
* Create and destroy Weierstrass curve data structures. The mandatory
* parameters to the constructor are the prime modulus p, and the
* curve parameters a,b.
*
* 'nonsquare_mod_p' is an optional extra parameter, only needed by
* ecc_edwards_point_new_from_y which has to take a modular square
* root. You can pass it as NULL if you don't need that function.
*/
WeierstrassCurve *ecc_weierstrass_curve(
mp_int *p, mp_int *a, mp_int *b, mp_int *nonsquare_mod_p);
void ecc_weierstrass_curve_free(WeierstrassCurve *);
/*
* Create points on a Weierstrass curve, given the curve.
*
* point_new_identity returns the special identity point.
* point_new(x,y) returns the non-identity point with the given affine
* coordinates.
*
* point_new_from_x constructs a non-identity point given only the
* x-coordinate, by using the curve equation to work out what y has to
* be. Of course the equation only tells you y^2, so it only
* determines y up to sign; the parameter desired_y_parity controls
* which of the two values of y you get, by saying whether you'd like
* its minimal non-negative residue mod p to be even or odd. (Of
* course, since p itself is odd, exactly one of y and p-y is odd.)
* This function has to take a modular square root, so it will only
* work if you passed in a non-square mod p when constructing the
* curve.
*/
WeierstrassPoint *ecc_weierstrass_point_new_identity(WeierstrassCurve *curve);
WeierstrassPoint *ecc_weierstrass_point_new(
WeierstrassCurve *curve, mp_int *x, mp_int *y);
WeierstrassPoint *ecc_weierstrass_point_new_from_x(
WeierstrassCurve *curve, mp_int *x, unsigned desired_y_parity);
/* Memory management: copy and free points. */
void ecc_weierstrass_point_copy_into(
WeierstrassPoint *dest, WeierstrassPoint *src);
WeierstrassPoint *ecc_weierstrass_point_copy(WeierstrassPoint *wc);
void ecc_weierstrass_point_free(WeierstrassPoint *point);
/* Check whether a point is actually on the curve. */
unsigned ecc_weierstrass_point_valid(WeierstrassPoint *);
/*
* Add two points and return their sum. This function is fully
* general: it should do the right thing if the two inputs are the
* same, or if either (or both) of the input points is the identity,
* or if the two input points are inverses so the output is the
* identity. However, it pays for that generality by being slower than
* the special-purpose functions below..
*/
WeierstrassPoint *ecc_weierstrass_add_general(
WeierstrassPoint *, WeierstrassPoint *);
/*
* Fast but less general arithmetic functions: add two points on the
* condition that they are not equal and neither is the identity, and
* add a point to itself.
*/
WeierstrassPoint *ecc_weierstrass_add(WeierstrassPoint *, WeierstrassPoint *);
WeierstrassPoint *ecc_weierstrass_double(WeierstrassPoint *);
/*
* Compute an integer multiple of a point. Not guaranteed to work
* unless the integer argument is less than the order of the point in
* the group (because it won't cope if an identity element shows up in
* any intermediate product).
*/
WeierstrassPoint *ecc_weierstrass_multiply(WeierstrassPoint *, mp_int *);
/*
* Query functions to get the value of a point back out. is_identity
* tells you whether the point is the identity; if it isn't, then
* get_affine will retrieve one or both of its affine coordinates.
* (You can pass NULL as either output pointer, if you don't need that
* coordinate as output.)
*/
unsigned ecc_weierstrass_is_identity(WeierstrassPoint *wp);
void ecc_weierstrass_get_affine(WeierstrassPoint *wp, mp_int **x, mp_int **y);
/* ----------------------------------------------------------------------
* Montgomery curves.
*
* A curve in this form is defined by two parameters a,b, and the
* curve equation is by^2 = x^3 + ax^2 + x.
*
* As with Weierstrass curves, there's an additional point at infinity
* that is the identity element, and the inverse of (x,y) is (x,-y).
*
* However, we don't actually work with full (x,y) pairs. We just
* store the x-coordinate (so what we're really representing is not a
* specific point on the curve but a two-point set {P,-P}). This means
* you can't quite do point addition, because if you're given {P,-P}
* and {Q,-Q} as input, you can work out a pair of x-coordinates that
* are those of P-Q and P+Q, but you don't know which is which.
*
* Instead, the basic operation is 'differential addition', in which
* you are given three parameters P, Q and P-Q and you return P+Q. (As
* well as disambiguating which of the possible answers you want, that
* extra input also enables a fast formulae for computing it. This
* fast formula is more or less why Montgomery curves are useful in
* the first place.)
*
* Doubling a point is still possible to do unambiguously, so you can
* still compute an integer multiple of P if you start by making 2P
* and then doing a series of differential additions.
*/
/*
* Create and destroy Montgomery curve data structures.
*/
MontgomeryCurve *ecc_montgomery_curve(mp_int *p, mp_int *a, mp_int *b);
void ecc_montgomery_curve_free(MontgomeryCurve *);
/*
* Create, copy and free points on the curve. We don't need to
* explicitly represent the identity for this application.
*/
MontgomeryPoint *ecc_montgomery_point_new(MontgomeryCurve *mc, mp_int *x);
void ecc_montgomery_point_copy_into(
MontgomeryPoint *dest, MontgomeryPoint *src);
MontgomeryPoint *ecc_montgomery_point_copy(MontgomeryPoint *orig);
void ecc_montgomery_point_free(MontgomeryPoint *mp);
/*
* Basic arithmetic routines: differential addition and point-
* doubling. Each of these assumes that no special cases come up - no
* input or output point should be the identity, and in diff_add, P
* and Q shouldn't be the same.
*/
MontgomeryPoint *ecc_montgomery_diff_add(
MontgomeryPoint *P, MontgomeryPoint *Q, MontgomeryPoint *PminusQ);
MontgomeryPoint *ecc_montgomery_double(MontgomeryPoint *P);
/*
* Compute an integer multiple of a point.
*/
MontgomeryPoint *ecc_montgomery_multiply(MontgomeryPoint *, mp_int *);
/*
* Return the affine x-coordinate of a point.
*/
void ecc_montgomery_get_affine(MontgomeryPoint *mp, mp_int **x);
/*
* Test whether a point is the curve identity.
*/
unsigned ecc_montgomery_is_identity(MontgomeryPoint *mp);
/* ----------------------------------------------------------------------
* Twisted Edwards curves.
*
* A curve in this form is defined by two parameters d,a, and the
* curve equation is a x^2 + y^2 = 1 + d x^2 y^2.
*
* Apparently if you ask a proper algebraic geometer they'll tell you
* that this is technically not an actual elliptic curve. Certainly it
* doesn't work quite the same way as the other kinds: in this form,
* there is no need for a point at infinity, because the identity
* element is represented by the affine coordinates (0,1). And you
* invert a point by negating its x rather than y coordinate: the
* inverse of (x,y) is (-x,y).
*
* The usefulness of this representation is that the addition formula
* is 'strongly unified', meaning that the same formula works for any
* input and output points, without needing special cases for the
* identity or for doubling.
*/
/*
* Create and destroy Edwards curve data structures.
*
* Similarly to ecc_weierstrass_curve, you don't have to provide
* nonsquare_mod_p if you don't need ecc_edwards_point_new_from_y.
*/
EdwardsCurve *ecc_edwards_curve(
mp_int *p, mp_int *d, mp_int *a, mp_int *nonsquare_mod_p);
void ecc_edwards_curve_free(EdwardsCurve *);
/*
* Create points.
*
* There's no need to have a separate function to create the identity
* point, because you can just pass x=0 and y=1 to the usual function.
*
* Similarly to the Weierstrass curve, ecc_edwards_point_new_from_y
* creates a point given only its y-coordinate and the desired parity
* of its x-coordinate, and you can only call it if you provided the
* optional nonsquare_mod_p argument when creating the curve.
*/
EdwardsPoint *ecc_edwards_point_new(
EdwardsCurve *curve, mp_int *x, mp_int *y);
EdwardsPoint *ecc_edwards_point_new_from_y(
EdwardsCurve *curve, mp_int *y, unsigned desired_x_parity);
/* Copy and free points. */
void ecc_edwards_point_copy_into(EdwardsPoint *dest, EdwardsPoint *src);
EdwardsPoint *ecc_edwards_point_copy(EdwardsPoint *ec);
void ecc_edwards_point_free(EdwardsPoint *point);
/*
* Arithmetic: add two points, and calculate an integer multiple of a
* point.
*/
EdwardsPoint *ecc_edwards_add(EdwardsPoint *, EdwardsPoint *);
EdwardsPoint *ecc_edwards_multiply(EdwardsPoint *, mp_int *);
/*
* Query functions: compare two points for equality, and return the
* affine coordinates of a point.
*/
unsigned ecc_edwards_eq(EdwardsPoint *, EdwardsPoint *);
void ecc_edwards_get_affine(EdwardsPoint *wp, mp_int **x, mp_int **y);
#endif /* PUTTY_ECC_H */
@@ -1,77 +1,74 @@
/*
* A dummy Socket implementation which just holds an error message.
*/
#include <stdio.h>
#include <assert.h>
#include "tree234.h"
#include "putty.h"
#include "network.h"
typedef struct {
char *error;
Plug *plug;
Socket sock;
} ErrorSocket;
static Plug *sk_error_plug(Socket *s, Plug *p)
{
ErrorSocket *es = container_of(s, ErrorSocket, sock);
Plug *ret = es->plug;
if (p)
es->plug = p;
return ret;
}
static void sk_error_close(Socket *s)
{
ErrorSocket *es = container_of(s, ErrorSocket, sock);
sfree(es->error);
sfree(es);
}
static const char *sk_error_socket_error(Socket *s)
{
ErrorSocket *es = container_of(s, ErrorSocket, sock);
return es->error;
}
static SocketPeerInfo *sk_error_peer_info(Socket *s)
{
return NULL;
}
static const SocketVtable ErrorSocket_sockvt = {
sk_error_plug,
sk_error_close,
NULL /* write */,
NULL /* write_oob */,
NULL /* write_eof */,
NULL /* set_frozen */,
sk_error_socket_error,
sk_error_peer_info,
};
static Socket *new_error_socket_internal(char *errmsg, Plug *plug)
{
ErrorSocket *es = snew(ErrorSocket);
es->sock.vt = &ErrorSocket_sockvt;
es->plug = plug;
es->error = errmsg;
return &es->sock;
}
Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...)
{
va_list ap;
char *msg;
va_start(ap, fmt);
msg = dupvprintf(fmt, ap);
va_end(ap);
return new_error_socket_internal(msg, plug);
}
/*
* A dummy Socket implementation which just holds an error message.
*/
#include <stdio.h>
#include <assert.h>
#include "tree234.h"
#include "putty.h"
#include "network.h"
typedef struct {
char *error;
Plug *plug;
Socket sock;
} ErrorSocket;
static Plug *sk_error_plug(Socket *s, Plug *p)
{
ErrorSocket *es = container_of(s, ErrorSocket, sock);
Plug *ret = es->plug;
if (p)
es->plug = p;
return ret;
}
static void sk_error_close(Socket *s)
{
ErrorSocket *es = container_of(s, ErrorSocket, sock);
sfree(es->error);
sfree(es);
}
static const char *sk_error_socket_error(Socket *s)
{
ErrorSocket *es = container_of(s, ErrorSocket, sock);
return es->error;
}
static SocketPeerInfo *sk_error_peer_info(Socket *s)
{
return NULL;
}
static const SocketVtable ErrorSocket_sockvt = {
.plug = sk_error_plug,
.close = sk_error_close,
.socket_error = sk_error_socket_error,
.peer_info = sk_error_peer_info,
/* other methods are NULL */
};
Socket *new_error_socket_consume_string(Plug *plug, char *errmsg)
{
ErrorSocket *es = snew(ErrorSocket);
es->sock.vt = &ErrorSocket_sockvt;
es->plug = plug;
es->error = errmsg;
return &es->sock;
}
Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...)
{
va_list ap;
char *msg;
va_start(ap, fmt);
msg = dupvprintf(fmt, ap);
va_end(ap);
return new_error_socket_consume_string(plug, msg);
}
+215
View File
@@ -0,0 +1,215 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include "putty.h"
#include "dialog.h"
#include "terminal.h"
/* For Unix in particular, but harmless if this main() is reused elsewhere */
const bool buildinfo_gtk_relevant = false;
static const TermWinVtable fuzz_termwin_vt;
int main(int argc, char **argv)
{
char blk[512];
size_t len;
Terminal *term;
Conf *conf;
struct unicode_data ucsdata;
TermWin termwin;
termwin.vt = &fuzz_termwin_vt;
conf = conf_new();
do_defaults(NULL, conf);
init_ucs(&ucsdata, conf_get_str(conf, CONF_line_codepage),
conf_get_bool(conf, CONF_utf8_override),
CS_NONE, conf_get_int(conf, CONF_vtmode));
term = term_init(conf, &ucsdata, &termwin);
term_size(term, 24, 80, 10000);
term->ldisc = NULL;
/* Tell american fuzzy lop that this is a good place to fork. */
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif
while (!feof(stdin)) {
len = fread(blk, 1, sizeof(blk), stdin);
term_data(term, false, blk, len);
}
term_update(term);
return 0;
}
/* functions required by terminal.c */
static bool fuzz_setup_draw_ctx(TermWin *tw) { return true; }
static void fuzz_draw_text(
TermWin *tw, int x, int y, wchar_t *text, int len,
unsigned long attr, int lattr, truecolour tc)
{
int i;
printf("TEXT[attr=%08lx,lattr=%02x]@(%d,%d):", attr, lattr, x, y);
for (i = 0; i < len; i++) {
printf(" %x", (unsigned)text[i]);
}
printf("\n");
}
static void fuzz_draw_cursor(
TermWin *tw, int x, int y, wchar_t *text, int len,
unsigned long attr, int lattr, truecolour tc)
{
int i;
printf("CURS[attr=%08lx,lattr=%02x]@(%d,%d):", attr, lattr, x, y);
for (i = 0; i < len; i++) {
printf(" %x", (unsigned)text[i]);
}
printf("\n");
}
static void fuzz_draw_trust_sigil(TermWin *tw, int x, int y)
{
printf("TRUST@(%d,%d)\n", x, y);
}
static int fuzz_char_width(TermWin *tw, int uc) { return 1; }
static void fuzz_free_draw_ctx(TermWin *tw) {}
static void fuzz_set_cursor_pos(TermWin *tw, int x, int y) {}
static void fuzz_set_raw_mouse_mode(TermWin *tw, bool enable) {}
static void fuzz_set_scrollbar(TermWin *tw, int total, int start, int page) {}
static void fuzz_bell(TermWin *tw, int mode) {}
static void fuzz_clip_write(
TermWin *tw, int clipboard, wchar_t *text, int *attrs,
truecolour *colours, int len, bool must_deselect) {}
static void fuzz_clip_request_paste(TermWin *tw, int clipboard) {}
static void fuzz_refresh(TermWin *tw) {}
static void fuzz_request_resize(TermWin *tw, int w, int h) {}
static void fuzz_set_title(TermWin *tw, const char *title) {}
static void fuzz_set_icon_title(TermWin *tw, const char *icontitle) {}
static void fuzz_set_minimised(TermWin *tw, bool minimised) {}
static void fuzz_set_maximised(TermWin *tw, bool maximised) {}
static void fuzz_move(TermWin *tw, int x, int y) {}
static void fuzz_set_zorder(TermWin *tw, bool top) {}
static void fuzz_palette_set(TermWin *tw, unsigned start, unsigned ncolours,
const rgb *colours) {}
static void fuzz_palette_get_overrides(TermWin *tw, Terminal *term) {}
static const TermWinVtable fuzz_termwin_vt = {
.setup_draw_ctx = fuzz_setup_draw_ctx,
.draw_text = fuzz_draw_text,
.draw_cursor = fuzz_draw_cursor,
.draw_trust_sigil = fuzz_draw_trust_sigil,
.char_width = fuzz_char_width,
.free_draw_ctx = fuzz_free_draw_ctx,
.set_cursor_pos = fuzz_set_cursor_pos,
.set_raw_mouse_mode = fuzz_set_raw_mouse_mode,
.set_scrollbar = fuzz_set_scrollbar,
.bell = fuzz_bell,
.clip_write = fuzz_clip_write,
.clip_request_paste = fuzz_clip_request_paste,
.refresh = fuzz_refresh,
.request_resize = fuzz_request_resize,
.set_title = fuzz_set_title,
.set_icon_title = fuzz_set_icon_title,
.set_minimised = fuzz_set_minimised,
.set_maximised = fuzz_set_maximised,
.move = fuzz_move,
.set_zorder = fuzz_set_zorder,
.palette_set = fuzz_palette_set,
.palette_get_overrides = fuzz_palette_get_overrides,
};
void ldisc_send(Ldisc *ldisc, const void *buf, int len, bool interactive) {}
void ldisc_echoedit_update(Ldisc *ldisc) {}
void modalfatalbox(const char *fmt, ...) { exit(0); }
void nonfatal(const char *fmt, ...) { }
/* needed by timing.c */
void timer_change_notify(unsigned long next) { }
/* needed by config.c and sercfg.c */
void dlg_radiobutton_set(union control *ctrl, dlgparam *dp, int whichbutton) { }
int dlg_radiobutton_get(union control *ctrl, dlgparam *dp) { return 0; }
void dlg_checkbox_set(union control *ctrl, dlgparam *dp, bool checked) { }
bool dlg_checkbox_get(union control *ctrl, dlgparam *dp) { return false; }
void dlg_editbox_set(union control *ctrl, dlgparam *dp, char const *text) { }
char *dlg_editbox_get(union control *ctrl, dlgparam *dp)
{ return dupstr("moo"); }
void dlg_listbox_clear(union control *ctrl, dlgparam *dp) { }
void dlg_listbox_del(union control *ctrl, dlgparam *dp, int index) { }
void dlg_listbox_add(union control *ctrl, dlgparam *dp, char const *text) { }
void dlg_listbox_addwithid(union control *ctrl, dlgparam *dp,
char const *text, int id) { }
int dlg_listbox_getid(union control *ctrl, dlgparam *dp, int index)
{ return 0; }
int dlg_listbox_index(union control *ctrl, dlgparam *dp) { return -1; }
bool dlg_listbox_issel(union control *ctrl, dlgparam *dp, int index)
{ return false; }
void dlg_listbox_select(union control *ctrl, dlgparam *dp, int index) { }
void dlg_text_set(union control *ctrl, dlgparam *dp, char const *text) { }
void dlg_filesel_set(union control *ctrl, dlgparam *dp, Filename *fn) { }
Filename *dlg_filesel_get(union control *ctrl, dlgparam *dp) { return NULL; }
void dlg_fontsel_set(union control *ctrl, dlgparam *dp, FontSpec *fn) { }
FontSpec *dlg_fontsel_get(union control *ctrl, dlgparam *dp) { return NULL; }
void dlg_update_start(union control *ctrl, dlgparam *dp) { }
void dlg_update_done(union control *ctrl, dlgparam *dp) { }
void dlg_set_focus(union control *ctrl, dlgparam *dp) { }
void dlg_label_change(union control *ctrl, dlgparam *dp, char const *text) { }
union control *dlg_last_focused(union control *ctrl, dlgparam *dp)
{ return NULL; }
void dlg_beep(dlgparam *dp) { }
void dlg_error_msg(dlgparam *dp, const char *msg) { }
void dlg_end(dlgparam *dp, int value) { }
void dlg_coloursel_start(union control *ctrl, dlgparam *dp,
int r, int g, int b) { }
bool dlg_coloursel_results(union control *ctrl, dlgparam *dp,
int *r, int *g, int *b) { return false; }
void dlg_refresh(union control *ctrl, dlgparam *dp) { }
bool dlg_is_visible(union control *ctrl, dlgparam *dp) { return false; }
const char *const appname = "FuZZterm";
const int ngsslibs = 0;
const char *const gsslibnames[0] = { };
const struct keyvalwhere gsslibkeywords[0] = { };
/*
* Default settings that are specific to Unix plink.
*/
char *platform_default_s(const char *name)
{
if (!strcmp(name, "TermType"))
return dupstr(getenv("TERM"));
if (!strcmp(name, "SerialLine"))
return dupstr("/dev/ttyS0");
return NULL;
}
bool platform_default_b(const char *name, bool def)
{
return def;
}
int platform_default_i(const char *name, int def)
{
return def;
}
FontSpec *platform_default_fontspec(const char *name)
{
return fontspec_new("");
}
Filename *platform_default_filename(const char *name)
{
if (!strcmp(name, "LogFileName"))
return filename_from_str("putty.log");
else
return filename_from_str("");
}
char *x_get_default(const char *key)
{
return NULL; /* this is a stub */
}
File diff suppressed because it is too large Load Diff
@@ -157,9 +157,6 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, bool interactive)
int keyflag = 0;
assert(ldisc->term);
#ifndef MOD_PERSO
assert(len);
#endif
/* rutty: */
#ifdef MOD_RUTTY
@@ -6,9 +6,9 @@
*/
#define LICENCE_TEXT(parsep) \
"PuTTY is copyright 1997-2020 Simon Tatham." \
"PuTTY is copyright 1997-2021 Simon Tatham." \
parsep \
"Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn, Colin Watson, Christopher Staite, Lorenz Diener, Christian Brabandt, Jeff Smith, Pavel Kryukov, Maxim Kuznetsov, Svyatoslav Kuzmich, Nico Williams, Viktor Dukhovni, and CORE SDI S.A." \
"Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn, Colin Watson, Christopher Staite, Lorenz Diener, Christian Brabandt, Jeff Smith, Pavel Kryukov, Maxim Kuznetsov, Svyatoslav Kuzmich, Nico Williams, Viktor Dukhovni, Josh Dersch, Lars Brinkhoff, and CORE SDI S.A." \
parsep \
"Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:" \
parsep \
@@ -16,4 +16,4 @@
parsep \
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
#define SHORT_COPYRIGHT_DETAILS "1997-2020 Simon Tatham"
#define SHORT_COPYRIGHT_DETAILS "1997-2021 Simon Tatham"
@@ -191,7 +191,7 @@ static void logwrite(LogContext *ctx, ptrlen data)
* Convenience wrapper on logwrite() which printf-formats the
* string.
*/
static void logprintf(LogContext *ctx, const char *fmt, ...)
static PRINTF_LIKE(2, 3) void logprintf(LogContext *ctx, const char *fmt, ...)
{
va_list ap;
char *data;
@@ -481,7 +481,7 @@ void log_packet(LogContext *ctx, int direction, int type,
/* If we're about to stop omitting, it's time to say how
* much we omitted. */
if ((blktype != PKTLOG_OMIT) && omitted) {
logprintf(ctx, " (%d byte%s omitted)\r\n",
logprintf(ctx, " (%"SIZEu" byte%s omitted)\r\n",
omitted, (omitted==1?"":"s"));
omitted = 0;
}
@@ -489,7 +489,8 @@ void log_packet(LogContext *ctx, int direction, int type,
/* (Re-)initialise dumpdata as necessary
* (start of row, or if we've just stopped omitting) */
if (!output_pos && !omitted)
sprintf(dumpdata, " %08zx%*s\r\n", p-(p%16), 1+3*16+2+16, "");
sprintf(dumpdata, " %08"SIZEx"%*s\r\n",
p-(p%16), 1+3*16+2+16, "");
/* Deal with the current byte. */
if (blktype == PKTLOG_OMIT) {
@@ -500,7 +501,7 @@ void log_packet(LogContext *ctx, int direction, int type,
c = 'X';
sprintf(smalldata, "XX");
} else { /* PKTLOG_EMIT */
c = ((unsigned char *)data)[p];
c = ((const unsigned char *)data)[p];
sprintf(smalldata, "%02x", c);
}
dumpdata[10+2+3*(p%16)] = smalldata[0];
@@ -524,7 +525,7 @@ void log_packet(LogContext *ctx, int direction, int type,
/* Tidy up */
if (omitted)
logprintf(ctx, " (%d byte%s omitted)\r\n",
logprintf(ctx, " (%"SIZEu" byte%s omitted)\r\n",
omitted, (omitted==1?"":"s"));
logflush(ctx);
}
File diff suppressed because it is too large Load Diff
@@ -1,260 +1,318 @@
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include "marshal.h"
#include "misc.h"
void BinarySink_put_data(BinarySink *bs, const void *data, size_t len)
{
bs->write(bs, data, len);
}
void BinarySink_put_datapl(BinarySink *bs, ptrlen pl)
{
BinarySink_put_data(bs, pl.ptr, pl.len);
}
void BinarySink_put_padding(BinarySink *bs, size_t len, unsigned char padbyte)
{
char buf[16];
memset(buf, padbyte, sizeof(buf));
while (len > 0) {
size_t thislen = len < sizeof(buf) ? len : sizeof(buf);
bs->write(bs, buf, thislen);
len -= thislen;
}
}
void BinarySink_put_byte(BinarySink *bs, unsigned char val)
{
bs->write(bs, &val, 1);
}
void BinarySink_put_bool(BinarySink *bs, bool val)
{
unsigned char cval = val ? 1 : 0;
bs->write(bs, &cval, 1);
}
void BinarySink_put_uint16(BinarySink *bs, unsigned long val)
{
unsigned char data[2];
PUT_16BIT_MSB_FIRST(data, val);
bs->write(bs, data, sizeof(data));
}
void BinarySink_put_uint32(BinarySink *bs, unsigned long val)
{
unsigned char data[4];
PUT_32BIT_MSB_FIRST(data, val);
bs->write(bs, data, sizeof(data));
}
void BinarySink_put_uint64(BinarySink *bs, uint64_t val)
{
unsigned char data[8];
PUT_64BIT_MSB_FIRST(data, val);
bs->write(bs, data, sizeof(data));
}
void BinarySink_put_string(BinarySink *bs, const void *data, size_t len)
{
/* Check that the string length fits in a uint32, without doing a
* potentially implementation-defined shift of more than 31 bits */
assert((len >> 31) < 2);
BinarySink_put_uint32(bs, len);
bs->write(bs, data, len);
}
void BinarySink_put_stringpl(BinarySink *bs, ptrlen pl)
{
BinarySink_put_string(bs, pl.ptr, pl.len);
}
void BinarySink_put_stringz(BinarySink *bs, const char *str)
{
BinarySink_put_string(bs, str, strlen(str));
}
void BinarySink_put_stringsb(BinarySink *bs, struct strbuf *buf)
{
BinarySink_put_string(bs, buf->s, buf->len);
strbuf_free(buf);
}
void BinarySink_put_asciz(BinarySink *bs, const char *str)
{
bs->write(bs, str, strlen(str) + 1);
}
bool BinarySink_put_pstring(BinarySink *bs, const char *str)
{
size_t len = strlen(str);
if (len > 255)
return false; /* can't write a Pascal-style string this long */
BinarySink_put_byte(bs, len);
bs->write(bs, str, len);
return true;
}
/* ---------------------------------------------------------------------- */
static bool BinarySource_data_avail(BinarySource *src, size_t wanted)
{
if (src->err)
return false;
if (wanted <= src->len - src->pos)
return true;
src->err = BSE_OUT_OF_DATA;
return false;
}
#define avail(wanted) BinarySource_data_avail(src, wanted)
#define advance(dist) (src->pos += dist)
#define here ((const void *)((const unsigned char *)src->data + src->pos))
#define consume(dist) \
((const void *)((const unsigned char *)src->data + \
((src->pos += dist) - dist)))
ptrlen BinarySource_get_data(BinarySource *src, size_t wanted)
{
if (!avail(wanted))
return make_ptrlen("", 0);
return make_ptrlen(consume(wanted), wanted);
}
unsigned char BinarySource_get_byte(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(1))
return 0;
ucp = consume(1);
return *ucp;
}
bool BinarySource_get_bool(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(1))
return false;
ucp = consume(1);
return *ucp != 0;
}
unsigned BinarySource_get_uint16(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(2))
return 0;
ucp = consume(2);
return GET_16BIT_MSB_FIRST(ucp);
}
unsigned long BinarySource_get_uint32(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(4))
return 0;
ucp = consume(4);
return GET_32BIT_MSB_FIRST(ucp);
}
uint64_t BinarySource_get_uint64(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(8))
return 0;
ucp = consume(8);
return GET_64BIT_MSB_FIRST(ucp);
}
ptrlen BinarySource_get_string(BinarySource *src)
{
const unsigned char *ucp;
size_t len;
if (!avail(4))
return make_ptrlen("", 0);
ucp = consume(4);
len = GET_32BIT_MSB_FIRST(ucp);
if (!avail(len))
return make_ptrlen("", 0);
return make_ptrlen(consume(len), len);
}
const char *BinarySource_get_asciz(BinarySource *src)
{
const char *start, *end;
if (src->err)
return "";
start = here;
end = memchr(start, '\0', src->len - src->pos);
if (!end) {
src->err = BSE_OUT_OF_DATA;
return "";
}
advance(end + 1 - start);
return start;
}
ptrlen BinarySource_get_pstring(BinarySource *src)
{
const unsigned char *ucp;
size_t len;
if (!avail(1))
return make_ptrlen("", 0);
ucp = consume(1);
len = *ucp;
if (!avail(len))
return make_ptrlen("", 0);
return make_ptrlen(consume(len), len);
}
static void stdio_sink_write(BinarySink *bs, const void *data, size_t len)
{
stdio_sink *sink = BinarySink_DOWNCAST(bs, stdio_sink);
fwrite(data, 1, len, sink->fp);
}
void stdio_sink_init(stdio_sink *sink, FILE *fp)
{
sink->fp = fp;
BinarySink_INIT(sink, stdio_sink_write);
}
static void bufchain_sink_write(BinarySink *bs, const void *data, size_t len)
{
bufchain_sink *sink = BinarySink_DOWNCAST(bs, bufchain_sink);
bufchain_add(sink->ch, data, len);
}
void bufchain_sink_init(bufchain_sink *sink, bufchain *ch)
{
sink->ch = ch;
BinarySink_INIT(sink, bufchain_sink_write);
}
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include "marshal.h"
#include "misc.h"
void BinarySink_put_data(BinarySink *bs, const void *data, size_t len)
{
bs->write(bs, data, len);
}
void BinarySink_put_datapl(BinarySink *bs, ptrlen pl)
{
BinarySink_put_data(bs, pl.ptr, pl.len);
}
void BinarySink_put_padding(BinarySink *bs, size_t len, unsigned char padbyte)
{
char buf[16];
memset(buf, padbyte, sizeof(buf));
while (len > 0) {
size_t thislen = len < sizeof(buf) ? len : sizeof(buf);
bs->write(bs, buf, thislen);
len -= thislen;
}
}
void BinarySink_put_byte(BinarySink *bs, unsigned char val)
{
bs->write(bs, &val, 1);
}
void BinarySink_put_bool(BinarySink *bs, bool val)
{
unsigned char cval = val ? 1 : 0;
bs->write(bs, &cval, 1);
}
void BinarySink_put_uint16(BinarySink *bs, unsigned long val)
{
unsigned char data[2];
PUT_16BIT_MSB_FIRST(data, val);
bs->write(bs, data, sizeof(data));
}
void BinarySink_put_uint32(BinarySink *bs, unsigned long val)
{
unsigned char data[4];
PUT_32BIT_MSB_FIRST(data, val);
bs->write(bs, data, sizeof(data));
}
void BinarySink_put_uint64(BinarySink *bs, uint64_t val)
{
unsigned char data[8];
PUT_64BIT_MSB_FIRST(data, val);
bs->write(bs, data, sizeof(data));
}
void BinarySink_put_string(BinarySink *bs, const void *data, size_t len)
{
/* Check that the string length fits in a uint32, without doing a
* potentially implementation-defined shift of more than 31 bits */
assert((len >> 31) < 2);
BinarySink_put_uint32(bs, len);
bs->write(bs, data, len);
}
void BinarySink_put_stringpl(BinarySink *bs, ptrlen pl)
{
BinarySink_put_string(bs, pl.ptr, pl.len);
}
void BinarySink_put_stringz(BinarySink *bs, const char *str)
{
BinarySink_put_string(bs, str, strlen(str));
}
void BinarySink_put_stringsb(BinarySink *bs, struct strbuf *buf)
{
BinarySink_put_string(bs, buf->s, buf->len);
strbuf_free(buf);
}
void BinarySink_put_asciz(BinarySink *bs, const char *str)
{
bs->write(bs, str, strlen(str) + 1);
}
bool BinarySink_put_pstring(BinarySink *bs, const char *str)
{
size_t len = strlen(str);
if (len > 255)
return false; /* can't write a Pascal-style string this long */
BinarySink_put_byte(bs, len);
bs->write(bs, str, len);
return true;
}
/* ---------------------------------------------------------------------- */
static bool BinarySource_data_avail(BinarySource *src, size_t wanted)
{
if (src->err)
return false;
if (wanted <= src->len - src->pos)
return true;
src->err = BSE_OUT_OF_DATA;
return false;
}
#define avail(wanted) BinarySource_data_avail(src, wanted)
#define advance(dist) (src->pos += dist)
#define here ((const void *)((const unsigned char *)src->data + src->pos))
#define consume(dist) \
((const void *)((const unsigned char *)src->data + \
((src->pos += dist) - dist)))
ptrlen BinarySource_get_data(BinarySource *src, size_t wanted)
{
if (!avail(wanted))
return make_ptrlen("", 0);
return make_ptrlen(consume(wanted), wanted);
}
unsigned char BinarySource_get_byte(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(1))
return 0;
ucp = consume(1);
return *ucp;
}
bool BinarySource_get_bool(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(1))
return false;
ucp = consume(1);
return *ucp != 0;
}
unsigned BinarySource_get_uint16(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(2))
return 0;
ucp = consume(2);
return GET_16BIT_MSB_FIRST(ucp);
}
unsigned long BinarySource_get_uint32(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(4))
return 0;
ucp = consume(4);
return GET_32BIT_MSB_FIRST(ucp);
}
uint64_t BinarySource_get_uint64(BinarySource *src)
{
const unsigned char *ucp;
if (!avail(8))
return 0;
ucp = consume(8);
return GET_64BIT_MSB_FIRST(ucp);
}
ptrlen BinarySource_get_string(BinarySource *src)
{
const unsigned char *ucp;
size_t len;
if (!avail(4))
return make_ptrlen("", 0);
ucp = consume(4);
len = GET_32BIT_MSB_FIRST(ucp);
if (!avail(len))
return make_ptrlen("", 0);
return make_ptrlen(consume(len), len);
}
const char *BinarySource_get_asciz(BinarySource *src)
{
const char *start, *end;
if (src->err)
return "";
start = here;
end = memchr(start, '\0', src->len - src->pos);
if (!end) {
src->err = BSE_OUT_OF_DATA;
return "";
}
advance(end + 1 - start);
return start;
}
static ptrlen BinarySource_get_chars_internal(
BinarySource *src, const char *set, bool include)
{
const char *start = here;
while (avail(1)) {
bool present = NULL != strchr(set, *(const char *)consume(0));
if (present != include)
break;
(void) consume(1);
}
const char *end = here;
return make_ptrlen(start, end - start);
}
ptrlen BinarySource_get_chars(BinarySource *src, const char *include_set)
{
return BinarySource_get_chars_internal(src, include_set, true);
}
ptrlen BinarySource_get_nonchars(BinarySource *src, const char *exclude_set)
{
return BinarySource_get_chars_internal(src, exclude_set, false);
}
ptrlen BinarySource_get_chomped_line(BinarySource *src)
{
const char *start, *end;
if (src->err)
return make_ptrlen(here, 0);
start = here;
end = memchr(start, '\n', src->len - src->pos);
if (end)
advance(end + 1 - start);
else
advance(src->len - src->pos);
end = here;
if (end > start && end[-1] == '\n')
end--;
if (end > start && end[-1] == '\r')
end--;
return make_ptrlen(start, end - start);
}
ptrlen BinarySource_get_pstring(BinarySource *src)
{
const unsigned char *ucp;
size_t len;
if (!avail(1))
return make_ptrlen("", 0);
ucp = consume(1);
len = *ucp;
if (!avail(len))
return make_ptrlen("", 0);
return make_ptrlen(consume(len), len);
}
void BinarySource_REWIND_TO__(BinarySource *src, size_t pos)
{
if (pos <= src->len) {
src->pos = pos;
src->err = BSE_NO_ERROR; /* clear any existing error */
} else {
src->pos = src->len;
src->err = BSE_OUT_OF_DATA; /* new error if we rewind out of range */
}
}
static void stdio_sink_write(BinarySink *bs, const void *data, size_t len)
{
stdio_sink *sink = BinarySink_DOWNCAST(bs, stdio_sink);
fwrite(data, 1, len, sink->fp);
}
void stdio_sink_init(stdio_sink *sink, FILE *fp)
{
sink->fp = fp;
BinarySink_INIT(sink, stdio_sink_write);
}
static void bufchain_sink_write(BinarySink *bs, const void *data, size_t len)
{
bufchain_sink *sink = BinarySink_DOWNCAST(bs, bufchain_sink);
bufchain_add(sink->ch, data, len);
}
void bufchain_sink_init(bufchain_sink *sink, bufchain *ch)
{
sink->ch = ch;
BinarySink_INIT(sink, bufchain_sink_write);
}
@@ -1,323 +1,340 @@
#ifndef PUTTY_MARSHAL_H
#define PUTTY_MARSHAL_H
#include "defs.h"
#include <stdio.h>
/*
* A sort of 'abstract base class' or 'interface' or 'trait' which is
* the common feature of all types that want to accept data formatted
* using the SSH binary conventions of uint32, string, mpint etc.
*/
struct BinarySink {
void (*write)(BinarySink *sink, const void *data, size_t len);
BinarySink *binarysink_;
};
/*
* To define a structure type as a valid target for binary formatted
* data, put 'BinarySink_IMPLEMENTATION' in its declaration, and when
* an instance is set up, use 'BinarySink_INIT' to initialise the
* 'base class' state, providing a function pointer to be the
* implementation of the write() call above.
*/
#define BinarySink_IMPLEMENTATION BinarySink binarysink_[1]
#define BinarySink_INIT(obj, writefn) \
((obj)->binarysink_->write = (writefn), \
(obj)->binarysink_->binarysink_ = (obj)->binarysink_)
/*
* To define a larger structure type as a valid BinarySink in such a
* way that it will delegate the write method to some other object,
* put 'BinarySink_DELEGATE_IMPLEMENTATION' in its declaration, and
* when an instance is set up, use 'BinarySink_DELEGATE_INIT' to point
* at the object it wants to delegate to.
*
* In such a delegated structure, you might sometimes want to have the
* delegation stop being valid (e.g. it might be delegating to an
* object that only sometimes exists). You can null out the delegate
* pointer using BinarySink_DELEGATE_CLEAR.
*/
#define BinarySink_DELEGATE_IMPLEMENTATION BinarySink *binarysink_
#define BinarySink_DELEGATE_INIT(obj, othersink) \
((obj)->binarysink_ = BinarySink_UPCAST(othersink))
#define BinarySink_DELEGATE_CLEAR(obj) ((obj)->binarysink_ = NULL)
/*
* The implementing type's write function will want to downcast its
* 'BinarySink *' parameter back to the more specific type. Also,
* sometimes you'll want to upcast a pointer to a particular
* implementing type into an abstract 'BinarySink *' to pass to
* generic subroutines not defined in this file. These macros do that
* job.
*
* Importantly, BinarySink_UPCAST can also be applied to a BinarySink
* * itself (and leaves it unchanged). That's achieved by a small
* piece of C trickery: implementing structures and the BinarySink
* structure itself both contain a field called binarysink_, but in
* implementing objects it's a BinarySink[1] whereas in the abstract
* type it's a 'BinarySink *' pointing back to the same structure,
* meaning that you can say 'foo->binarysink_' in either case and get
* a pointer type by different methods.
*/
#define BinarySink_DOWNCAST(object, type) \
TYPECHECK((object) == ((type *)0)->binarysink_, \
((type *)(((char *)(object)) - offsetof(type, binarysink_))))
#define BinarySink_UPCAST(object) \
TYPECHECK((object)->binarysink_ == (BinarySink *)0, \
(object)->binarysink_)
/*
* If you structure-copy an object that's implementing BinarySink,
* then that tricky self-pointer in its trait subobject will point to
* the wrong place. You could call BinarySink_INIT again, but this
* macro is terser and does all that's needed to fix up the copied
* object.
*/
#define BinarySink_COPIED(obj) \
((obj)->binarysink_->binarysink_ = (obj)->binarysink_)
/*
* The put_* macros are the main client to this system. Any structure
* which implements the BinarySink 'trait' is valid for use as the
* first parameter of any of these put_* macros.
*/
/* Basic big-endian integer types. */
#define put_byte(bs, val) \
BinarySink_put_byte(BinarySink_UPCAST(bs), val)
#define put_uint16(bs, val) \
BinarySink_put_uint16(BinarySink_UPCAST(bs), val)
#define put_uint32(bs, val) \
BinarySink_put_uint32(BinarySink_UPCAST(bs), val)
#define put_uint64(bs, val) \
BinarySink_put_uint64(BinarySink_UPCAST(bs), val)
/* SSH booleans, encoded as a single byte storing either 0 or 1. */
#define put_bool(bs, val) \
BinarySink_put_bool(BinarySink_UPCAST(bs), val)
/* SSH strings, with a leading uint32 length field. 'stringz' is a
* convenience function that takes an ordinary C zero-terminated
* string as input. 'stringsb' takes a strbuf * as input, and
* finalises it as a side effect (handy for multi-level marshalling in
* which you use these same functions to format an inner blob of data
* that then gets wrapped into a string container in an outer one). */
#define put_string(bs, val, len) \
BinarySink_put_string(BinarySink_UPCAST(bs),val,len)
#define put_stringpl(bs, ptrlen) \
BinarySink_put_stringpl(BinarySink_UPCAST(bs),ptrlen)
#define put_stringz(bs, val) \
BinarySink_put_stringz(BinarySink_UPCAST(bs), val)
#define put_stringsb(bs, val) \
BinarySink_put_stringsb(BinarySink_UPCAST(bs), val)
/* Other string outputs: 'asciz' emits the string data directly into
* the output including the terminating \0, and 'pstring' emits the
* string in Pascal style with a leading _one_-byte length field.
* pstring can fail if the string is too long. */
#define put_asciz(bs, val) \
BinarySink_put_asciz(BinarySink_UPCAST(bs), val)
#define put_pstring(bs, val) \
BinarySink_put_pstring(BinarySink_UPCAST(bs), val)
/* Multiprecision integers, in both the SSH-1 and SSH-2 formats. */
#define put_mp_ssh1(bs, val) \
BinarySink_put_mp_ssh1(BinarySink_UPCAST(bs), val)
#define put_mp_ssh2(bs, val) \
BinarySink_put_mp_ssh2(BinarySink_UPCAST(bs), val)
/* Padding with a specified byte. */
#define put_padding(bs, len, padbyte) \
BinarySink_put_padding(BinarySink_UPCAST(bs), len, padbyte)
/* Fallback: just emit raw data bytes, using a syntax that matches the
* rest of these macros. */
#define put_data(bs, val, len) \
BinarySink_put_data(BinarySink_UPCAST(bs), val, len)
#define put_datapl(bs, pl) \
BinarySink_put_datapl(BinarySink_UPCAST(bs), pl)
/*
* The underlying real C functions that implement most of those
* macros. Generally you won't want to call these directly, because
* they have such cumbersome names; you call the wrapper macros above
* instead.
*
* A few functions whose wrapper macros are defined above are actually
* declared in other headers, so as to guarantee that the
* declaration(s) of their other parameter type(s) are in scope.
*/
void BinarySink_put_data(BinarySink *, const void *data, size_t len);
void BinarySink_put_datapl(BinarySink *, ptrlen);
void BinarySink_put_padding(BinarySink *, size_t len, unsigned char padbyte);
void BinarySink_put_byte(BinarySink *, unsigned char);
void BinarySink_put_bool(BinarySink *, bool);
void BinarySink_put_uint16(BinarySink *, unsigned long);
void BinarySink_put_uint32(BinarySink *, unsigned long);
void BinarySink_put_uint64(BinarySink *, uint64_t);
void BinarySink_put_string(BinarySink *, const void *data, size_t len);
void BinarySink_put_stringpl(BinarySink *, ptrlen);
void BinarySink_put_stringz(BinarySink *, const char *str);
struct strbuf;
void BinarySink_put_stringsb(BinarySink *, struct strbuf *);
void BinarySink_put_asciz(BinarySink *, const char *str);
bool BinarySink_put_pstring(BinarySink *, const char *str);
void BinarySink_put_mp_ssh1(BinarySink *bs, mp_int *x);
void BinarySink_put_mp_ssh2(BinarySink *bs, mp_int *x);
/* ---------------------------------------------------------------------- */
/*
* A complementary trait structure for _un_-marshalling.
*
* This structure contains client-visible data fields rather than
* methods, because that seemed more useful than leaving it totally
* opaque. But it's still got the self-pointer system that will allow
* the set of get_* macros to target one of these itself or any other
* type that 'derives' from it. So, for example, an SSH packet
* structure can act as a BinarySource while also having additional
* fields like the packet type.
*/
typedef enum BinarySourceError {
BSE_NO_ERROR,
BSE_OUT_OF_DATA,
BSE_INVALID
} BinarySourceError;
struct BinarySource {
/*
* (data, len) is the data block being decoded. pos is the current
* position within the block.
*/
const void *data;
size_t pos, len;
/*
* 'err' indicates whether a decoding error has happened at any
* point. Once this has been set to something other than
* BSE_NO_ERROR, it shouldn't be changed by any unmarshalling
* function. So you can safely do a long sequence of get_foo()
* operations and then test err just once at the end, rather than
* having to conditionalise every single get.
*
* The unmarshalling functions should always return some value,
* even if a decoding error occurs. Generally on error they'll
* return zero (if numeric) or the empty string (if string-based),
* or some other appropriate default value for more complicated
* types.
*
* If the usual return value is dynamically allocated (e.g. a
* bignum, or a normal C 'char *' string), then the error value is
* also dynamic in the same way. So you have to free exactly the
* same set of things whether or not there was a decoding error,
* which simplifies exit paths - for example, you could call a big
* pile of get_foo functions, then put the actual handling of the
* results under 'if (!get_err(src))', and then free everything
* outside that if.
*/
BinarySourceError err;
/*
* Self-pointer for the implicit derivation trick, same as
* BinarySink above.
*/
BinarySource *binarysource_;
};
/*
* Implementation macros, similar to BinarySink.
*/
#define BinarySource_IMPLEMENTATION BinarySource binarysource_[1]
static inline void BinarySource_INIT__(BinarySource *src, ptrlen data)
{
src->data = data.ptr;
src->len = data.len;
src->pos = 0;
src->err = BSE_NO_ERROR;
src->binarysource_ = src;
}
#define BinarySource_BARE_INIT_PL(obj, pl) \
TYPECHECK(&(obj)->binarysource_ == (BinarySource **)0, \
BinarySource_INIT__(obj, pl))
#define BinarySource_BARE_INIT(obj, data_, len_) \
BinarySource_BARE_INIT_PL(obj, make_ptrlen(data_, len_))
#define BinarySource_INIT_PL(obj, pl) \
TYPECHECK(&(obj)->binarysource_ == (BinarySource (*)[1])0, \
BinarySource_INIT__(BinarySource_UPCAST(obj), pl))
#define BinarySource_INIT(obj, data_, len_) \
BinarySource_INIT_PL(obj, make_ptrlen(data_, len_))
#define BinarySource_DOWNCAST(object, type) \
TYPECHECK((object) == ((type *)0)->binarysource_, \
((type *)(((char *)(object)) - offsetof(type, binarysource_))))
#define BinarySource_UPCAST(object) \
TYPECHECK((object)->binarysource_ == (BinarySource *)0, \
(object)->binarysource_)
#define BinarySource_COPIED(obj) \
((obj)->binarysource_->binarysource_ = (obj)->binarysource_)
#define get_data(src, len) \
BinarySource_get_data(BinarySource_UPCAST(src), len)
#define get_byte(src) \
BinarySource_get_byte(BinarySource_UPCAST(src))
#define get_bool(src) \
BinarySource_get_bool(BinarySource_UPCAST(src))
#define get_uint16(src) \
BinarySource_get_uint16(BinarySource_UPCAST(src))
#define get_uint32(src) \
BinarySource_get_uint32(BinarySource_UPCAST(src))
#define get_uint64(src) \
BinarySource_get_uint64(BinarySource_UPCAST(src))
#define get_string(src) \
BinarySource_get_string(BinarySource_UPCAST(src))
#define get_asciz(src) \
BinarySource_get_asciz(BinarySource_UPCAST(src))
#define get_pstring(src) \
BinarySource_get_pstring(BinarySource_UPCAST(src))
#define get_mp_ssh1(src) \
BinarySource_get_mp_ssh1(BinarySource_UPCAST(src))
#define get_mp_ssh2(src) \
BinarySource_get_mp_ssh2(BinarySource_UPCAST(src))
#define get_rsa_ssh1_pub(src, rsa, order) \
BinarySource_get_rsa_ssh1_pub(BinarySource_UPCAST(src), rsa, order)
#define get_rsa_ssh1_priv(src, rsa) \
BinarySource_get_rsa_ssh1_priv(BinarySource_UPCAST(src), rsa)
#define get_err(src) (BinarySource_UPCAST(src)->err)
#define get_avail(src) (BinarySource_UPCAST(src)->len - \
BinarySource_UPCAST(src)->pos)
#define get_ptr(src) \
((const void *)( \
(const unsigned char *)(BinarySource_UPCAST(src)->data) + \
BinarySource_UPCAST(src)->pos))
ptrlen BinarySource_get_data(BinarySource *, size_t);
unsigned char BinarySource_get_byte(BinarySource *);
bool BinarySource_get_bool(BinarySource *);
unsigned BinarySource_get_uint16(BinarySource *);
unsigned long BinarySource_get_uint32(BinarySource *);
uint64_t BinarySource_get_uint64(BinarySource *);
ptrlen BinarySource_get_string(BinarySource *);
const char *BinarySource_get_asciz(BinarySource *);
ptrlen BinarySource_get_pstring(BinarySource *);
mp_int *BinarySource_get_mp_ssh1(BinarySource *src);
mp_int *BinarySource_get_mp_ssh2(BinarySource *src);
/*
* A couple of useful standard BinarySink implementations, which live
* as sensibly here as anywhere else: one that makes a BinarySink
* whose effect is to write to a stdio stream, and one whose effect is
* to append to a bufchain.
*/
struct stdio_sink {
FILE *fp;
BinarySink_IMPLEMENTATION;
};
struct bufchain_sink {
bufchain *ch;
BinarySink_IMPLEMENTATION;
};
void stdio_sink_init(stdio_sink *sink, FILE *fp);
void bufchain_sink_init(bufchain_sink *sink, bufchain *ch);
#endif /* PUTTY_MARSHAL_H */
#ifndef PUTTY_MARSHAL_H
#define PUTTY_MARSHAL_H
#include "defs.h"
#include <stdio.h>
/*
* A sort of 'abstract base class' or 'interface' or 'trait' which is
* the common feature of all types that want to accept data formatted
* using the SSH binary conventions of uint32, string, mpint etc.
*/
struct BinarySink {
void (*write)(BinarySink *sink, const void *data, size_t len);
BinarySink *binarysink_;
};
/*
* To define a structure type as a valid target for binary formatted
* data, put 'BinarySink_IMPLEMENTATION' in its declaration, and when
* an instance is set up, use 'BinarySink_INIT' to initialise the
* 'base class' state, providing a function pointer to be the
* implementation of the write() call above.
*/
#define BinarySink_IMPLEMENTATION BinarySink binarysink_[1]
#define BinarySink_INIT(obj, writefn) \
((obj)->binarysink_->write = (writefn), \
(obj)->binarysink_->binarysink_ = (obj)->binarysink_)
/*
* To define a larger structure type as a valid BinarySink in such a
* way that it will delegate the write method to some other object,
* put 'BinarySink_DELEGATE_IMPLEMENTATION' in its declaration, and
* when an instance is set up, use 'BinarySink_DELEGATE_INIT' to point
* at the object it wants to delegate to.
*
* In such a delegated structure, you might sometimes want to have the
* delegation stop being valid (e.g. it might be delegating to an
* object that only sometimes exists). You can null out the delegate
* pointer using BinarySink_DELEGATE_CLEAR.
*/
#define BinarySink_DELEGATE_IMPLEMENTATION BinarySink *binarysink_
#define BinarySink_DELEGATE_INIT(obj, othersink) \
((obj)->binarysink_ = BinarySink_UPCAST(othersink))
#define BinarySink_DELEGATE_CLEAR(obj) ((obj)->binarysink_ = NULL)
/*
* The implementing type's write function will want to downcast its
* 'BinarySink *' parameter back to the more specific type. Also,
* sometimes you'll want to upcast a pointer to a particular
* implementing type into an abstract 'BinarySink *' to pass to
* generic subroutines not defined in this file. These macros do that
* job.
*
* Importantly, BinarySink_UPCAST can also be applied to a BinarySink
* * itself (and leaves it unchanged). That's achieved by a small
* piece of C trickery: implementing structures and the BinarySink
* structure itself both contain a field called binarysink_, but in
* implementing objects it's a BinarySink[1] whereas in the abstract
* type it's a 'BinarySink *' pointing back to the same structure,
* meaning that you can say 'foo->binarysink_' in either case and get
* a pointer type by different methods.
*/
#define BinarySink_DOWNCAST(object, type) \
TYPECHECK((object) == ((type *)0)->binarysink_, \
((type *)(((char *)(object)) - offsetof(type, binarysink_))))
#define BinarySink_UPCAST(object) \
TYPECHECK((object)->binarysink_ == (BinarySink *)0, \
(object)->binarysink_)
/*
* If you structure-copy an object that's implementing BinarySink,
* then that tricky self-pointer in its trait subobject will point to
* the wrong place. You could call BinarySink_INIT again, but this
* macro is terser and does all that's needed to fix up the copied
* object.
*/
#define BinarySink_COPIED(obj) \
((obj)->binarysink_->binarysink_ = (obj)->binarysink_)
/*
* The put_* macros are the main client to this system. Any structure
* which implements the BinarySink 'trait' is valid for use as the
* first parameter of any of these put_* macros.
*/
/* Basic big-endian integer types. */
#define put_byte(bs, val) \
BinarySink_put_byte(BinarySink_UPCAST(bs), val)
#define put_uint16(bs, val) \
BinarySink_put_uint16(BinarySink_UPCAST(bs), val)
#define put_uint32(bs, val) \
BinarySink_put_uint32(BinarySink_UPCAST(bs), val)
#define put_uint64(bs, val) \
BinarySink_put_uint64(BinarySink_UPCAST(bs), val)
/* SSH booleans, encoded as a single byte storing either 0 or 1. */
#define put_bool(bs, val) \
BinarySink_put_bool(BinarySink_UPCAST(bs), val)
/* SSH strings, with a leading uint32 length field. 'stringz' is a
* convenience function that takes an ordinary C zero-terminated
* string as input. 'stringsb' takes a strbuf * as input, and
* finalises it as a side effect (handy for multi-level marshalling in
* which you use these same functions to format an inner blob of data
* that then gets wrapped into a string container in an outer one). */
#define put_string(bs, val, len) \
BinarySink_put_string(BinarySink_UPCAST(bs),val,len)
#define put_stringpl(bs, ptrlen) \
BinarySink_put_stringpl(BinarySink_UPCAST(bs),ptrlen)
#define put_stringz(bs, val) \
BinarySink_put_stringz(BinarySink_UPCAST(bs), val)
#define put_stringsb(bs, val) \
BinarySink_put_stringsb(BinarySink_UPCAST(bs), val)
/* Other string outputs: 'asciz' emits the string data directly into
* the output including the terminating \0, and 'pstring' emits the
* string in Pascal style with a leading _one_-byte length field.
* pstring can fail if the string is too long. */
#define put_asciz(bs, val) \
BinarySink_put_asciz(BinarySink_UPCAST(bs), val)
#define put_pstring(bs, val) \
BinarySink_put_pstring(BinarySink_UPCAST(bs), val)
/* Multiprecision integers, in both the SSH-1 and SSH-2 formats. */
#define put_mp_ssh1(bs, val) \
BinarySink_put_mp_ssh1(BinarySink_UPCAST(bs), val)
#define put_mp_ssh2(bs, val) \
BinarySink_put_mp_ssh2(BinarySink_UPCAST(bs), val)
/* Padding with a specified byte. */
#define put_padding(bs, len, padbyte) \
BinarySink_put_padding(BinarySink_UPCAST(bs), len, padbyte)
/* Fallback: just emit raw data bytes, using a syntax that matches the
* rest of these macros. */
#define put_data(bs, val, len) \
BinarySink_put_data(BinarySink_UPCAST(bs), val, len)
#define put_datapl(bs, pl) \
BinarySink_put_datapl(BinarySink_UPCAST(bs), pl)
/*
* The underlying real C functions that implement most of those
* macros. Generally you won't want to call these directly, because
* they have such cumbersome names; you call the wrapper macros above
* instead.
*
* A few functions whose wrapper macros are defined above are actually
* declared in other headers, so as to guarantee that the
* declaration(s) of their other parameter type(s) are in scope.
*/
void BinarySink_put_data(BinarySink *, const void *data, size_t len);
void BinarySink_put_datapl(BinarySink *, ptrlen);
void BinarySink_put_padding(BinarySink *, size_t len, unsigned char padbyte);
void BinarySink_put_byte(BinarySink *, unsigned char);
void BinarySink_put_bool(BinarySink *, bool);
void BinarySink_put_uint16(BinarySink *, unsigned long);
void BinarySink_put_uint32(BinarySink *, unsigned long);
void BinarySink_put_uint64(BinarySink *, uint64_t);
void BinarySink_put_string(BinarySink *, const void *data, size_t len);
void BinarySink_put_stringpl(BinarySink *, ptrlen);
void BinarySink_put_stringz(BinarySink *, const char *str);
struct strbuf;
void BinarySink_put_stringsb(BinarySink *, struct strbuf *);
void BinarySink_put_asciz(BinarySink *, const char *str);
bool BinarySink_put_pstring(BinarySink *, const char *str);
void BinarySink_put_mp_ssh1(BinarySink *bs, mp_int *x);
void BinarySink_put_mp_ssh2(BinarySink *bs, mp_int *x);
/* ---------------------------------------------------------------------- */
/*
* A complementary trait structure for _un_-marshalling.
*
* This structure contains client-visible data fields rather than
* methods, because that seemed more useful than leaving it totally
* opaque. But it's still got the self-pointer system that will allow
* the set of get_* macros to target one of these itself or any other
* type that 'derives' from it. So, for example, an SSH packet
* structure can act as a BinarySource while also having additional
* fields like the packet type.
*/
typedef enum BinarySourceError {
BSE_NO_ERROR,
BSE_OUT_OF_DATA,
BSE_INVALID
} BinarySourceError;
struct BinarySource {
/*
* (data, len) is the data block being decoded. pos is the current
* position within the block.
*/
const void *data;
size_t pos, len;
/*
* 'err' indicates whether a decoding error has happened at any
* point. Once this has been set to something other than
* BSE_NO_ERROR, it shouldn't be changed by any unmarshalling
* function. So you can safely do a long sequence of get_foo()
* operations and then test err just once at the end, rather than
* having to conditionalise every single get.
*
* The unmarshalling functions should always return some value,
* even if a decoding error occurs. Generally on error they'll
* return zero (if numeric) or the empty string (if string-based),
* or some other appropriate default value for more complicated
* types.
*
* If the usual return value is dynamically allocated (e.g. a
* bignum, or a normal C 'char *' string), then the error value is
* also dynamic in the same way. So you have to free exactly the
* same set of things whether or not there was a decoding error,
* which simplifies exit paths - for example, you could call a big
* pile of get_foo functions, then put the actual handling of the
* results under 'if (!get_err(src))', and then free everything
* outside that if.
*/
BinarySourceError err;
/*
* Self-pointer for the implicit derivation trick, same as
* BinarySink above.
*/
BinarySource *binarysource_;
};
/*
* Implementation macros, similar to BinarySink.
*/
#define BinarySource_IMPLEMENTATION BinarySource binarysource_[1]
static inline void BinarySource_INIT__(BinarySource *src, ptrlen data)
{
src->data = data.ptr;
src->len = data.len;
src->pos = 0;
src->err = BSE_NO_ERROR;
src->binarysource_ = src;
}
#define BinarySource_BARE_INIT_PL(obj, pl) \
TYPECHECK(&(obj)->binarysource_ == (BinarySource **)0, \
BinarySource_INIT__(obj, pl))
#define BinarySource_BARE_INIT(obj, data_, len_) \
BinarySource_BARE_INIT_PL(obj, make_ptrlen(data_, len_))
#define BinarySource_INIT_PL(obj, pl) \
TYPECHECK(&(obj)->binarysource_ == (BinarySource (*)[1])0, \
BinarySource_INIT__(BinarySource_UPCAST(obj), pl))
#define BinarySource_INIT(obj, data_, len_) \
BinarySource_INIT_PL(obj, make_ptrlen(data_, len_))
#define BinarySource_DOWNCAST(object, type) \
TYPECHECK((object) == ((type *)0)->binarysource_, \
((type *)(((char *)(object)) - offsetof(type, binarysource_))))
#define BinarySource_UPCAST(object) \
TYPECHECK((object)->binarysource_ == (BinarySource *)0, \
(object)->binarysource_)
#define BinarySource_COPIED(obj) \
((obj)->binarysource_->binarysource_ = (obj)->binarysource_)
#define BinarySource_REWIND_TO(src, pos) \
BinarySource_REWIND_TO__((src)->binarysource_, pos)
#define BinarySource_REWIND(src) \
BinarySource_REWIND_TO__((src)->binarysource_, 0)
#define get_data(src, len) \
BinarySource_get_data(BinarySource_UPCAST(src), len)
#define get_byte(src) \
BinarySource_get_byte(BinarySource_UPCAST(src))
#define get_bool(src) \
BinarySource_get_bool(BinarySource_UPCAST(src))
#define get_uint16(src) \
BinarySource_get_uint16(BinarySource_UPCAST(src))
#define get_uint32(src) \
BinarySource_get_uint32(BinarySource_UPCAST(src))
#define get_uint64(src) \
BinarySource_get_uint64(BinarySource_UPCAST(src))
#define get_string(src) \
BinarySource_get_string(BinarySource_UPCAST(src))
#define get_asciz(src) \
BinarySource_get_asciz(BinarySource_UPCAST(src))
#define get_chars(src, include) \
BinarySource_get_chars(BinarySource_UPCAST(src), include)
#define get_nonchars(src, exclude) \
BinarySource_get_nonchars(BinarySource_UPCAST(src), exclude)
#define get_chomped_line(src) \
BinarySource_get_chomped_line(BinarySource_UPCAST(src))
#define get_pstring(src) \
BinarySource_get_pstring(BinarySource_UPCAST(src))
#define get_mp_ssh1(src) \
BinarySource_get_mp_ssh1(BinarySource_UPCAST(src))
#define get_mp_ssh2(src) \
BinarySource_get_mp_ssh2(BinarySource_UPCAST(src))
#define get_rsa_ssh1_pub(src, rsa, order) \
BinarySource_get_rsa_ssh1_pub(BinarySource_UPCAST(src), rsa, order)
#define get_rsa_ssh1_priv(src, rsa) \
BinarySource_get_rsa_ssh1_priv(BinarySource_UPCAST(src), rsa)
#define get_rsa_ssh1_priv_agent(src) \
BinarySource_get_rsa_ssh1_priv_agent(BinarySource_UPCAST(src))
#define get_err(src) (BinarySource_UPCAST(src)->err)
#define get_avail(src) (BinarySource_UPCAST(src)->len - \
BinarySource_UPCAST(src)->pos)
#define get_ptr(src) \
((const void *)( \
(const unsigned char *)(BinarySource_UPCAST(src)->data) + \
BinarySource_UPCAST(src)->pos))
ptrlen BinarySource_get_data(BinarySource *, size_t);
unsigned char BinarySource_get_byte(BinarySource *);
bool BinarySource_get_bool(BinarySource *);
unsigned BinarySource_get_uint16(BinarySource *);
unsigned long BinarySource_get_uint32(BinarySource *);
uint64_t BinarySource_get_uint64(BinarySource *);
ptrlen BinarySource_get_string(BinarySource *);
const char *BinarySource_get_asciz(BinarySource *);
ptrlen BinarySource_get_chars(BinarySource *, const char *include_set);
ptrlen BinarySource_get_nonchars(BinarySource *, const char *exclude_set);
ptrlen BinarySource_get_chomped_line(BinarySource *);
ptrlen BinarySource_get_pstring(BinarySource *);
mp_int *BinarySource_get_mp_ssh1(BinarySource *src);
mp_int *BinarySource_get_mp_ssh2(BinarySource *src);
void BinarySource_REWIND_TO__(BinarySource *src, size_t pos);
/*
* A couple of useful standard BinarySink implementations, which live
* as sensibly here as anywhere else: one that makes a BinarySink
* whose effect is to write to a stdio stream, and one whose effect is
* to append to a bufchain.
*/
struct stdio_sink {
FILE *fp;
BinarySink_IMPLEMENTATION;
};
struct bufchain_sink {
bufchain *ch;
BinarySink_IMPLEMENTATION;
};
void stdio_sink_init(stdio_sink *sink, FILE *fp);
void bufchain_sink_init(bufchain_sink *sink, bufchain *ch);
#endif /* PUTTY_MARSHAL_H */
@@ -46,22 +46,22 @@ void *saferealloc(void *ptr, size_t n, size_t size)
void *p;
if (n > INT_MAX / size) {
p = NULL;
p = NULL;
} else {
size *= n;
if (!ptr) {
size *= n;
if (!ptr) {
#ifdef MINEFIELD
p = minefield_c_malloc(size);
p = minefield_c_malloc(size);
#else
p = malloc(size);
p = malloc(size);
#endif
} else {
} else {
#ifdef MINEFIELD
p = minefield_c_realloc(ptr, size);
p = minefield_c_realloc(ptr, size);
#else
p = realloc(ptr, size);
p = realloc(ptr, size);
#endif
}
}
}
if (!p)
@@ -74,9 +74,9 @@ void safefree(void *ptr)
{
if (ptr) {
#ifdef MINEFIELD
minefield_c_free(ptr);
minefield_c_free(ptr);
#else
free(ptr);
free(ptr);
#endif
}
}
@@ -121,9 +121,11 @@ void *safegrowarray(void *ptr, size_t *allocated, size_t eltsize,
void *toret;
if (secret) {
toret = safemalloc(newsize, eltsize, 0);
memcpy(toret, ptr, oldsize * eltsize);
smemclr(ptr, oldsize * eltsize);
sfree(ptr);
if (oldsize) {
memcpy(toret, ptr, oldsize * eltsize);
smemclr(ptr, oldsize * eltsize);
sfree(ptr);
}
} else {
toret = saferealloc(ptr, newsize, eltsize);
}
+214
View File
@@ -0,0 +1,214 @@
/*
* millerrabin.c: Miller-Rabin probabilistic primality testing, as
* declared in sshkeygen.h.
*/
#include <assert.h>
#include "ssh.h"
#include "sshkeygen.h"
#include "mpint.h"
#include "mpunsafe.h"
/*
* The Miller-Rabin primality test is an extension to the Fermat
* test. The Fermat test just checks that a^(p-1) == 1 mod p; this
* is vulnerable to Carmichael numbers. Miller-Rabin considers how
* that 1 is derived as well.
*
* Lemma: if a^2 == 1 (mod p), and p is prime, then either a == 1
* or a == -1 (mod p).
*
* Proof: p divides a^2-1, i.e. p divides (a+1)(a-1). Hence,
* since p is prime, either p divides (a+1) or p divides (a-1).
* But this is the same as saying that either a is congruent to
* -1 mod p or a is congruent to +1 mod p. []
*
* Comment: This fails when p is not prime. Consider p=mn, so
* that mn divides (a+1)(a-1). Now we could have m dividing (a+1)
* and n dividing (a-1), without the whole of mn dividing either.
* For example, consider a=10 and p=99. 99 = 9 * 11; 9 divides
* 10-1 and 11 divides 10+1, so a^2 is congruent to 1 mod p
* without a having to be congruent to either 1 or -1.
*
* So the Miller-Rabin test, as well as considering a^(p-1),
* considers a^((p-1)/2), a^((p-1)/4), and so on as far as it can
* go. In other words. we write p-1 as q * 2^k, with k as large as
* possible (i.e. q must be odd), and we consider the powers
*
* a^(q*2^0) a^(q*2^1) ... a^(q*2^(k-1)) a^(q*2^k)
* i.e. a^((n-1)/2^k) a^((n-1)/2^(k-1)) ... a^((n-1)/2) a^(n-1)
*
* If p is to be prime, the last of these must be 1. Therefore, by
* the above lemma, the one before it must be either 1 or -1. And
* _if_ it's 1, then the one before that must be either 1 or -1,
* and so on ... In other words, we expect to see a trailing chain
* of 1s preceded by a -1. (If we're unlucky, our trailing chain of
* 1s will be as long as the list so we'll never get to see what
* lies before it. This doesn't count as a test failure because it
* hasn't _proved_ that p is not prime.)
*
* For example, consider a=2 and p=1729. 1729 is a Carmichael
* number: although it's not prime, it satisfies a^(p-1) == 1 mod p
* for any a coprime to it. So the Fermat test wouldn't have a
* problem with it at all, unless we happened to stumble on an a
* which had a common factor.
*
* So. 1729 - 1 equals 27 * 2^6. So we look at
*
* 2^27 mod 1729 == 645
* 2^108 mod 1729 == 1065
* 2^216 mod 1729 == 1
* 2^432 mod 1729 == 1
* 2^864 mod 1729 == 1
* 2^1728 mod 1729 == 1
*
* We do have a trailing string of 1s, so the Fermat test would
* have been happy. But this trailing string of 1s is preceded by
* 1065; whereas if 1729 were prime, we'd expect to see it preceded
* by -1 (i.e. 1728.). Guards! Seize this impostor.
*
* (If we were unlucky, we might have tried a=16 instead of a=2;
* now 16^27 mod 1729 == 1, so we would have seen a long string of
* 1s and wouldn't have seen the thing _before_ the 1s. So, just
* like the Fermat test, for a given p there may well exist values
* of a which fail to show up its compositeness. So we try several,
* just like the Fermat test. The difference is that Miller-Rabin
* is not _in general_ fooled by Carmichael numbers.)
*
* Put simply, then, the Miller-Rabin test requires us to:
*
* 1. write p-1 as q * 2^k, with q odd
* 2. compute z = (a^q) mod p.
* 3. report success if z == 1 or z == -1.
* 4. square z at most k-1 times, and report success if it becomes
* -1 at any point.
* 5. report failure otherwise.
*
* (We expect z to become -1 after at most k-1 squarings, because
* if it became -1 after k squarings then a^(p-1) would fail to be
* 1. And we don't need to investigate what happens after we see a
* -1, because we _know_ that -1 squared is 1 modulo anything at
* all, so after we've seen a -1 we can be sure of seeing nothing
* but 1s.)
*/
struct MillerRabin {
MontyContext *mc;
size_t k;
mp_int *q;
mp_int *two, *pm1, *m_pm1;
};
MillerRabin *miller_rabin_new(mp_int *p)
{
MillerRabin *mr = snew(MillerRabin);
assert(mp_hs_integer(p, 2));
assert(mp_get_bit(p, 0) == 1);
mr->k = 1;
while (!mp_get_bit(p, mr->k))
mr->k++;
mr->q = mp_rshift_safe(p, mr->k);
mr->two = mp_from_integer(2);
mr->pm1 = mp_unsafe_copy(p);
mp_sub_integer_into(mr->pm1, mr->pm1, 1);
mr->mc = monty_new(p);
mr->m_pm1 = monty_import(mr->mc, mr->pm1);
return mr;
}
void miller_rabin_free(MillerRabin *mr)
{
mp_free(mr->q);
mp_free(mr->two);
mp_free(mr->pm1);
mp_free(mr->m_pm1);
monty_free(mr->mc);
smemclr(mr, sizeof(*mr));
sfree(mr);
}
struct mr_result {
bool passed;
bool potential_primitive_root;
};
static struct mr_result miller_rabin_test_inner(MillerRabin *mr, mp_int *w)
{
/*
* Compute w^q mod p.
*/
mp_int *wqp = monty_pow(mr->mc, w, mr->q);
/*
* See if this is 1, or if it is -1, or if it becomes -1
* when squared at most k-1 times.
*/
struct mr_result result;
result.passed = false;
result.potential_primitive_root = false;
if (mp_cmp_eq(wqp, monty_identity(mr->mc))) {
result.passed = true;
} else {
for (size_t i = 0; i < mr->k; i++) {
if (mp_cmp_eq(wqp, mr->m_pm1)) {
result.passed = true;
result.potential_primitive_root = (i == mr->k - 1);
break;
}
if (i == mr->k - 1)
break;
monty_mul_into(mr->mc, wqp, wqp, wqp);
}
}
mp_free(wqp);
return result;
}
bool miller_rabin_test_random(MillerRabin *mr)
{
mp_int *mw = mp_random_in_range(mr->two, mr->pm1);
struct mr_result result = miller_rabin_test_inner(mr, mw);
mp_free(mw);
return result.passed;
}
mp_int *miller_rabin_find_potential_primitive_root(MillerRabin *mr)
{
while (true) {
mp_int *mw = mp_unsafe_shrink(mp_random_in_range(mr->two, mr->pm1));
struct mr_result result = miller_rabin_test_inner(mr, mw);
if (result.passed && result.potential_primitive_root) {
mp_int *pr = monty_export(mr->mc, mw);
mp_free(mw);
return pr;
}
mp_free(mw);
if (!result.passed) {
return NULL;
}
}
}
unsigned miller_rabin_checks_needed(unsigned bits)
{
/* Table 4.4 from Handbook of Applied Cryptography */
return (bits >= 1300 ? 2 : bits >= 850 ? 3 : bits >= 650 ? 4 :
bits >= 550 ? 5 : bits >= 450 ? 6 : bits >= 400 ? 7 :
bits >= 350 ? 8 : bits >= 300 ? 9 : bits >= 250 ? 12 :
bits >= 200 ? 15 : bits >= 150 ? 18 : 27);
}
File diff suppressed because it is too large Load Diff
+422 -389
View File
@@ -1,389 +1,422 @@
/*
* Platform-independent routines shared between all PuTTY programs.
*
* This file contains functions that use the kind of infrastructure
* like conf.c that tends to only live in the main applications, or
* that do things that only something like a main PuTTY application
* would need. So standalone test programs should generally be able to
* avoid linking against it.
*
* More standalone functions that depend on nothing but the C library
* live in utils.c.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>
#include "defs.h"
#include "putty.h"
#include "misc.h"
void seat_connection_fatal(Seat *seat, const char *fmt, ...)
{
va_list ap;
char *msg;
va_start(ap, fmt);
msg = dupvprintf(fmt, ap);
va_end(ap);
seat->vt->connection_fatal(seat, msg);
sfree(msg); /* if we return */
}
prompts_t *new_prompts(void)
{
prompts_t *p = snew(prompts_t);
p->prompts = NULL;
p->n_prompts = p->prompts_size = 0;
p->data = NULL;
p->to_server = true; /* to be on the safe side */
p->name = p->instruction = NULL;
p->name_reqd = p->instr_reqd = false;
return p;
}
void add_prompt(prompts_t *p, char *promptstr, bool echo)
{
prompt_t *pr = snew(prompt_t);
pr->prompt = promptstr;
pr->echo = echo;
pr->result = NULL;
pr->resultsize = 0;
sgrowarray(p->prompts, p->prompts_size, p->n_prompts);
p->prompts[p->n_prompts++] = pr;
}
void prompt_ensure_result_size(prompt_t *pr, int newlen)
{
if ((int)pr->resultsize < newlen) {
char *newbuf;
newlen = newlen * 5 / 4 + 512; /* avoid too many small allocs */
/*
* We don't use sresize / realloc here, because we will be
* storing sensitive stuff like passwords in here, and we want
* to make sure that the data doesn't get copied around in
* memory without the old copy being destroyed.
*/
newbuf = snewn(newlen, char);
memcpy(newbuf, pr->result, pr->resultsize);
smemclr(pr->result, pr->resultsize);
sfree(pr->result);
pr->result = newbuf;
pr->resultsize = newlen;
}
}
void prompt_set_result(prompt_t *pr, const char *newstr)
{
prompt_ensure_result_size(pr, strlen(newstr) + 1);
strcpy(pr->result, newstr);
}
void free_prompts(prompts_t *p)
{
size_t i;
for (i=0; i < p->n_prompts; i++) {
prompt_t *pr = p->prompts[i];
smemclr(pr->result, pr->resultsize); /* burn the evidence */
sfree(pr->result);
sfree(pr->prompt);
sfree(pr);
}
sfree(p->prompts);
sfree(p->name);
sfree(p->instruction);
sfree(p);
}
/*
* Determine whether or not a Conf represents a session which can
* sensibly be launched right now.
*/
bool conf_launchable(Conf *conf)
{
if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
return conf_get_str(conf, CONF_serline)[0] != 0;
else
return conf_get_str(conf, CONF_host)[0] != 0;
}
char const *conf_dest(Conf *conf)
{
if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
return conf_get_str(conf, CONF_serline);
else
return conf_get_str(conf, CONF_host);
}
/*
* Validate a manual host key specification (either entered in the
* GUI, or via -hostkey). If valid, we return true, and update 'key'
* to contain a canonicalised version of the key string in 'key'
* (which is guaranteed to take up at most as much space as the
* original version), suitable for putting into the Conf. If not
* valid, we return false.
*/
bool validate_manual_hostkey(char *key)
{
char *p, *q, *r, *s;
/*
* Step through the string word by word, looking for a word that's
* in one of the formats we like.
*/
p = key;
while ((p += strspn(p, " \t"))[0]) {
q = p;
p += strcspn(p, " \t");
if (*p) *p++ = '\0';
/*
* Now q is our word.
*/
if (strlen(q) == 16*3 - 1 &&
q[strspn(q, "0123456789abcdefABCDEF:")] == 0) {
/*
* Might be a key fingerprint. Check the colons are in the
* right places, and if so, return the same fingerprint
* canonicalised into lowercase.
*/
int i;
for (i = 0; i < 16; i++)
if (q[3*i] == ':' || q[3*i+1] == ':')
goto not_fingerprint; /* sorry */
for (i = 0; i < 15; i++)
if (q[3*i+2] != ':')
goto not_fingerprint; /* sorry */
for (i = 0; i < 16*3 - 1; i++)
key[i] = tolower(q[i]);
key[16*3 - 1] = '\0';
return true;
}
not_fingerprint:;
/*
* Before we check for a public-key blob, trim newlines out of
* the middle of the word, in case someone's managed to paste
* in a public-key blob _with_ them.
*/
for (r = s = q; *r; r++)
if (*r != '\n' && *r != '\r')
*s++ = *r;
*s = '\0';
if (strlen(q) % 4 == 0 && strlen(q) > 2*4 &&
q[strspn(q, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz+/=")] == 0) {
/*
* Might be a base64-encoded SSH-2 public key blob. Check
* that it starts with a sensible algorithm string. No
* canonicalisation is necessary for this string type.
*
* The algorithm string must be at most 64 characters long
* (RFC 4251 section 6).
*/
unsigned char decoded[6];
unsigned alglen;
int minlen;
int len = 0;
len += base64_decode_atom(q, decoded+len);
if (len < 3)
goto not_ssh2_blob; /* sorry */
len += base64_decode_atom(q+4, decoded+len);
if (len < 4)
goto not_ssh2_blob; /* sorry */
alglen = GET_32BIT_MSB_FIRST(decoded);
if (alglen > 64)
goto not_ssh2_blob; /* sorry */
minlen = ((alglen + 4) + 2) / 3;
if (strlen(q) < minlen)
goto not_ssh2_blob; /* sorry */
strcpy(key, q);
return true;
}
not_ssh2_blob:;
}
return false;
}
char *buildinfo(const char *newline)
{
strbuf *buf = strbuf_new();
strbuf_catf(buf, "Build platform: %d-bit %s",
(int)(CHAR_BIT * sizeof(void *)),
BUILDINFO_PLATFORM);
#ifdef __clang_version__
#define FOUND_COMPILER
strbuf_catf(buf, "%sCompiler: clang %s", newline, __clang_version__);
#elif defined __GNUC__ && defined __VERSION__
#define FOUND_COMPILER
strbuf_catf(buf, "%sCompiler: gcc %s", newline, __VERSION__);
#endif
#if defined _MSC_VER
#ifndef FOUND_COMPILER
#define FOUND_COMPILER
strbuf_catf(buf, "%sCompiler: ", newline);
#else
strbuf_catf(buf, ", emulating ");
#endif
strbuf_catf(buf, "Visual Studio", newline);
#if 0
/*
* List of _MSC_VER values and their translations taken from
* https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
* except for 1920, which is not yet listed on that page as of
* 2019-03-22, and was determined experimentally by Sean Kain.
*
* The pointless #if 0 branch containing this comment is there so
* that every real clause can start with #elif and there's no
* anomalous first clause. That way the patch looks nicer when you
* add extra ones.
*/
#elif _MSC_VER == 1920
strbuf_catf(buf, " 2019 (16.x)");
#elif _MSC_VER == 1916
strbuf_catf(buf, " 2017 version 15.9");
#elif _MSC_VER == 1915
strbuf_catf(buf, " 2017 version 15.8");
#elif _MSC_VER == 1914
strbuf_catf(buf, " 2017 version 15.7");
#elif _MSC_VER == 1913
strbuf_catf(buf, " 2017 version 15.6");
#elif _MSC_VER == 1912
strbuf_catf(buf, " 2017 version 15.5");
#elif _MSC_VER == 1911
strbuf_catf(buf, " 2017 version 15.3");
#elif _MSC_VER == 1910
strbuf_catf(buf, " 2017 RTW (15.0)");
#elif _MSC_VER == 1900
strbuf_catf(buf, " 2015 (14.0)");
#elif _MSC_VER == 1800
strbuf_catf(buf, " 2013 (12.0)");
#elif _MSC_VER == 1700
strbuf_catf(buf, " 2012 (11.0)");
#elif _MSC_VER == 1600
strbuf_catf(buf, " 2010 (10.0)");
#elif _MSC_VER == 1500
strbuf_catf(buf, " 2008 (9.0)");
#elif _MSC_VER == 1400
strbuf_catf(buf, " 2005 (8.0)");
#elif _MSC_VER == 1310
strbuf_catf(buf, " .NET 2003 (7.1)");
#elif _MSC_VER == 1300
strbuf_catf(buf, " .NET 2002 (7.0)");
#elif _MSC_VER == 1200
strbuf_catf(buf, " 6.0");
#else
strbuf_catf(buf, ", unrecognised version");
#endif
strbuf_catf(buf, ", _MSC_VER=%d", (int)_MSC_VER);
#endif
#ifdef BUILDINFO_GTK
{
char *gtk_buildinfo = buildinfo_gtk_version();
if (gtk_buildinfo) {
strbuf_catf(buf, "%sCompiled against GTK version %s",
newline, gtk_buildinfo);
sfree(gtk_buildinfo);
}
}
#endif
#if defined _WINDOWS
{
int echm = has_embedded_chm();
if (echm >= 0)
strbuf_catf(buf, "%sEmbedded HTML Help file: %s", newline,
echm ? "yes" : "no");
}
#endif
#if defined _WINDOWS && defined MINEFIELD
strbuf_catf(buf, "%sBuild option: MINEFIELD", newline);
#endif
#ifdef NO_SECURITY
strbuf_catf(buf, "%sBuild option: NO_SECURITY", newline);
#endif
#ifdef NO_SECUREZEROMEMORY
strbuf_catf(buf, "%sBuild option: NO_SECUREZEROMEMORY", newline);
#endif
#ifdef NO_IPV6
strbuf_catf(buf, "%sBuild option: NO_IPV6", newline);
#endif
#ifdef NO_GSSAPI
strbuf_catf(buf, "%sBuild option: NO_GSSAPI", newline);
#endif
#ifdef STATIC_GSSAPI
strbuf_catf(buf, "%sBuild option: STATIC_GSSAPI", newline);
#endif
#ifdef UNPROTECT
strbuf_catf(buf, "%sBuild option: UNPROTECT", newline);
#endif
#ifdef FUZZING
strbuf_catf(buf, "%sBuild option: FUZZING", newline);
#endif
#ifdef DEBUG
strbuf_catf(buf, "%sBuild option: DEBUG", newline);
#endif
strbuf_catf(buf, "%sSource commit: %s", newline, commitid);
return strbuf_to_str(buf);
}
size_t nullseat_output(
Seat *seat, bool is_stderr, const void *data, size_t len) { return 0; }
bool nullseat_eof(Seat *seat) { return true; }
int nullseat_get_userpass_input(
Seat *seat, prompts_t *p, bufchain *input) { return 0; }
void nullseat_notify_remote_exit(Seat *seat) {}
void nullseat_connection_fatal(Seat *seat, const char *message) {}
void nullseat_update_specials_menu(Seat *seat) {}
char *nullseat_get_ttymode(Seat *seat, const char *mode) { return NULL; }
void nullseat_set_busy_status(Seat *seat, BusyStatus status) {}
int nullseat_verify_ssh_host_key(
Seat *seat, const char *host, int port,
const char *keytype, char *keystr, char *key_fingerprint,
void (*callback)(void *ctx, int result), void *ctx) { return 0; }
int nullseat_confirm_weak_crypto_primitive(
Seat *seat, const char *algtype, const char *algname,
void (*callback)(void *ctx, int result), void *ctx) { return 0; }
int nullseat_confirm_weak_cached_hostkey(
Seat *seat, const char *algname, const char *betteralgs,
void (*callback)(void *ctx, int result), void *ctx) { return 0; }
bool nullseat_is_never_utf8(Seat *seat) { return false; }
bool nullseat_is_always_utf8(Seat *seat) { return true; }
void nullseat_echoedit_update(Seat *seat, bool echoing, bool editing) {}
const char *nullseat_get_x_display(Seat *seat) { return NULL; }
bool nullseat_get_windowid(Seat *seat, long *id_out) { return false; }
bool nullseat_get_window_pixel_size(
Seat *seat, int *width, int *height) { return false; }
StripCtrlChars *nullseat_stripctrl_new(
Seat *seat, BinarySink *bs_out, SeatInteractionContext sic) {return NULL;}
bool nullseat_set_trust_status(Seat *seat, bool tr) { return false; }
bool nullseat_set_trust_status_vacuously(Seat *seat, bool tr) { return true; }
void sk_free_peer_info(SocketPeerInfo *pi)
{
if (pi) {
sfree((char *)pi->addr_text);
sfree((char *)pi->log_text);
sfree(pi);
}
}
void out_of_memory(void)
{
modalfatalbox("Out of memory");
}
/*
* Platform-independent routines shared between all PuTTY programs.
*
* This file contains functions that use the kind of infrastructure
* like conf.c that tends to only live in the main applications, or
* that do things that only something like a main PuTTY application
* would need. So standalone test programs should generally be able to
* avoid linking against it.
*
* More standalone functions that depend on nothing but the C library
* live in utils.c.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>
#include "defs.h"
#include "putty.h"
#include "misc.h"
#define BASE64_CHARS_NOEQ \
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
#define BASE64_CHARS_ALL BASE64_CHARS_NOEQ "="
void seat_connection_fatal(Seat *seat, const char *fmt, ...)
{
va_list ap;
char *msg;
va_start(ap, fmt);
msg = dupvprintf(fmt, ap);
va_end(ap);
seat->vt->connection_fatal(seat, msg);
sfree(msg); /* if we return */
}
prompts_t *new_prompts(void)
{
prompts_t *p = snew(prompts_t);
p->prompts = NULL;
p->n_prompts = p->prompts_size = 0;
p->data = NULL;
p->to_server = true; /* to be on the safe side */
p->name = p->instruction = NULL;
p->name_reqd = p->instr_reqd = false;
return p;
}
void add_prompt(prompts_t *p, char *promptstr, bool echo)
{
prompt_t *pr = snew(prompt_t);
pr->prompt = promptstr;
pr->echo = echo;
pr->result = strbuf_new_nm();
sgrowarray(p->prompts, p->prompts_size, p->n_prompts);
p->prompts[p->n_prompts++] = pr;
}
void prompt_set_result(prompt_t *pr, const char *newstr)
{
strbuf_clear(pr->result);
put_datapl(pr->result, ptrlen_from_asciz(newstr));
}
const char *prompt_get_result_ref(prompt_t *pr)
{
return pr->result->s;
}
char *prompt_get_result(prompt_t *pr)
{
return dupstr(pr->result->s);
}
void free_prompts(prompts_t *p)
{
size_t i;
for (i=0; i < p->n_prompts; i++) {
prompt_t *pr = p->prompts[i];
strbuf_free(pr->result);
sfree(pr->prompt);
sfree(pr);
}
sfree(p->prompts);
sfree(p->name);
sfree(p->instruction);
sfree(p);
}
/*
* Determine whether or not a Conf represents a session which can
* sensibly be launched right now.
*/
bool conf_launchable(Conf *conf)
{
if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
return conf_get_str(conf, CONF_serline)[0] != 0;
else
return conf_get_str(conf, CONF_host)[0] != 0;
}
char const *conf_dest(Conf *conf)
{
if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
return conf_get_str(conf, CONF_serline);
else
return conf_get_str(conf, CONF_host);
}
/*
* Validate a manual host key specification (either entered in the
* GUI, or via -hostkey). If valid, we return true, and update 'key'
* to contain a canonicalised version of the key string in 'key'
* (which is guaranteed to take up at most as much space as the
* original version), suitable for putting into the Conf. If not
* valid, we return false.
*/
bool validate_manual_hostkey(char *key)
{
char *p, *q, *r, *s;
/*
* Step through the string word by word, looking for a word that's
* in one of the formats we like.
*/
p = key;
while ((p += strspn(p, " \t"))[0]) {
q = p;
p += strcspn(p, " \t");
if (*p) *p++ = '\0';
/*
* Now q is our word.
*/
if (strstartswith(q, "SHA256:")) {
/* Test for a valid SHA256 key fingerprint. */
r = q + 7;
if (strlen(r) == 43 && r[strspn(r, BASE64_CHARS_NOEQ)] == 0)
return true;
}
r = q;
if (strstartswith(r, "MD5:"))
r += 4;
if (strlen(r) == 16*3 - 1 &&
r[strspn(r, "0123456789abcdefABCDEF:")] == 0) {
/*
* Test for a valid MD5 key fingerprint. Check the colons
* are in the right places, and if so, return the same
* fingerprint canonicalised into lowercase.
*/
int i;
for (i = 0; i < 16; i++)
if (r[3*i] == ':' || r[3*i+1] == ':')
goto not_fingerprint; /* sorry */
for (i = 0; i < 15; i++)
if (r[3*i+2] != ':')
goto not_fingerprint; /* sorry */
for (i = 0; i < 16*3 - 1; i++)
key[i] = tolower(r[i]);
key[16*3 - 1] = '\0';
return true;
}
not_fingerprint:;
/*
* Before we check for a public-key blob, trim newlines out of
* the middle of the word, in case someone's managed to paste
* in a public-key blob _with_ them.
*/
for (r = s = q; *r; r++)
if (*r != '\n' && *r != '\r')
*s++ = *r;
*s = '\0';
if (strlen(q) % 4 == 0 && strlen(q) > 2*4 &&
q[strspn(q, BASE64_CHARS_ALL)] == 0) {
/*
* Might be a base64-encoded SSH-2 public key blob. Check
* that it starts with a sensible algorithm string. No
* canonicalisation is necessary for this string type.
*
* The algorithm string must be at most 64 characters long
* (RFC 4251 section 6).
*/
unsigned char decoded[6];
unsigned alglen;
int minlen;
int len = 0;
len += base64_decode_atom(q, decoded+len);
if (len < 3)
goto not_ssh2_blob; /* sorry */
len += base64_decode_atom(q+4, decoded+len);
if (len < 4)
goto not_ssh2_blob; /* sorry */
alglen = GET_32BIT_MSB_FIRST(decoded);
if (alglen > 64)
goto not_ssh2_blob; /* sorry */
minlen = ((alglen + 4) + 2) / 3;
if (strlen(q) < minlen)
goto not_ssh2_blob; /* sorry */
strcpy(key, q);
return true;
}
not_ssh2_blob:;
}
return false;
}
char *buildinfo(const char *newline)
{
strbuf *buf = strbuf_new();
strbuf_catf(buf, "Build platform: %d-bit %s",
(int)(CHAR_BIT * sizeof(void *)),
BUILDINFO_PLATFORM);
#ifdef __clang_version__
#define FOUND_COMPILER
strbuf_catf(buf, "%sCompiler: clang %s", newline, __clang_version__);
#elif defined __GNUC__ && defined __VERSION__
#define FOUND_COMPILER
strbuf_catf(buf, "%sCompiler: gcc %s", newline, __VERSION__);
#endif
#if defined _MSC_VER
#ifndef FOUND_COMPILER
#define FOUND_COMPILER
strbuf_catf(buf, "%sCompiler: ", newline);
#else
strbuf_catf(buf, ", emulating ");
#endif
strbuf_catf(buf, "Visual Studio");
#if 0
/*
* List of _MSC_VER values and their translations taken from
* https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
*
* The pointless #if 0 branch containing this comment is there so
* that every real clause can start with #elif and there's no
* anomalous first clause. That way the patch looks nicer when you
* add extra ones.
*/
#elif _MSC_VER == 1928 && _MSC_FULL_VER >= 192829500
/*
* 16.9 and 16.8 have the same _MSC_VER value, and have to be
* distinguished by _MSC_FULL_VER. As of 2021-03-04 that is not
* mentioned on the above page, but see e.g.
* https://developercommunity.visualstudio.com/t/the-169-cc-compiler-still-uses-the-same-version-nu/1335194#T-N1337120
* which says that 16.9 builds will have versions starting at
* 19.28.29500.* and going up. Hence, 19 28 29500 is what we
* compare _MSC_FULL_VER against above.
*/
strbuf_catf(buf, " 2019 (16.9)");
#elif _MSC_VER == 1928
strbuf_catf(buf, " 2019 (16.8)");
#elif _MSC_VER == 1927
strbuf_catf(buf, " 2019 (16.7)");
#elif _MSC_VER == 1926
strbuf_catf(buf, " 2019 (16.6)");
#elif _MSC_VER == 1925
strbuf_catf(buf, " 2019 (16.5)");
#elif _MSC_VER == 1924
strbuf_catf(buf, " 2019 (16.4)");
#elif _MSC_VER == 1923
strbuf_catf(buf, " 2019 (16.3)");
#elif _MSC_VER == 1922
strbuf_catf(buf, " 2019 (16.2)");
#elif _MSC_VER == 1921
strbuf_catf(buf, " 2019 (16.1)");
#elif _MSC_VER == 1920
strbuf_catf(buf, " 2019 (16.0)");
#elif _MSC_VER == 1916
strbuf_catf(buf, " 2017 version 15.9");
#elif _MSC_VER == 1915
strbuf_catf(buf, " 2017 version 15.8");
#elif _MSC_VER == 1914
strbuf_catf(buf, " 2017 version 15.7");
#elif _MSC_VER == 1913
strbuf_catf(buf, " 2017 version 15.6");
#elif _MSC_VER == 1912
strbuf_catf(buf, " 2017 version 15.5");
#elif _MSC_VER == 1911
strbuf_catf(buf, " 2017 version 15.3");
#elif _MSC_VER == 1910
strbuf_catf(buf, " 2017 RTW (15.0)");
#elif _MSC_VER == 1900
strbuf_catf(buf, " 2015 (14.0)");
#elif _MSC_VER == 1800
strbuf_catf(buf, " 2013 (12.0)");
#elif _MSC_VER == 1700
strbuf_catf(buf, " 2012 (11.0)");
#elif _MSC_VER == 1600
strbuf_catf(buf, " 2010 (10.0)");
#elif _MSC_VER == 1500
strbuf_catf(buf, " 2008 (9.0)");
#elif _MSC_VER == 1400
strbuf_catf(buf, " 2005 (8.0)");
#elif _MSC_VER == 1310
strbuf_catf(buf, " .NET 2003 (7.1)");
#elif _MSC_VER == 1300
strbuf_catf(buf, " .NET 2002 (7.0)");
#elif _MSC_VER == 1200
strbuf_catf(buf, " 6.0");
#else
strbuf_catf(buf, ", unrecognised version");
#endif
strbuf_catf(buf, ", _MSC_VER=%d", (int)_MSC_VER);
#endif
#ifdef BUILDINFO_GTK
{
char *gtk_buildinfo = buildinfo_gtk_version();
if (gtk_buildinfo) {
strbuf_catf(buf, "%sCompiled against GTK version %s",
newline, gtk_buildinfo);
sfree(gtk_buildinfo);
}
}
#endif
#if defined _WINDOWS
{
int echm = has_embedded_chm();
if (echm >= 0)
strbuf_catf(buf, "%sEmbedded HTML Help file: %s", newline,
echm ? "yes" : "no");
}
#endif
#if defined _WINDOWS && defined MINEFIELD
strbuf_catf(buf, "%sBuild option: MINEFIELD", newline);
#endif
#ifdef NO_SECURITY
strbuf_catf(buf, "%sBuild option: NO_SECURITY", newline);
#endif
#ifdef NO_SECUREZEROMEMORY
strbuf_catf(buf, "%sBuild option: NO_SECUREZEROMEMORY", newline);
#endif
#ifdef NO_IPV6
strbuf_catf(buf, "%sBuild option: NO_IPV6", newline);
#endif
#ifdef NO_GSSAPI
strbuf_catf(buf, "%sBuild option: NO_GSSAPI", newline);
#endif
#ifdef STATIC_GSSAPI
strbuf_catf(buf, "%sBuild option: STATIC_GSSAPI", newline);
#endif
#ifdef UNPROTECT
strbuf_catf(buf, "%sBuild option: UNPROTECT", newline);
#endif
#ifdef FUZZING
strbuf_catf(buf, "%sBuild option: FUZZING", newline);
#endif
#ifdef DEBUG
strbuf_catf(buf, "%sBuild option: DEBUG", newline);
#endif
strbuf_catf(buf, "%sSource commit: %s", newline, commitid);
return strbuf_to_str(buf);
}
size_t nullseat_output(
Seat *seat, bool is_stderr, const void *data, size_t len) { return 0; }
bool nullseat_eof(Seat *seat) { return true; }
int nullseat_get_userpass_input(
Seat *seat, prompts_t *p, bufchain *input) { return 0; }
void nullseat_notify_remote_exit(Seat *seat) {}
void nullseat_connection_fatal(Seat *seat, const char *message) {}
void nullseat_update_specials_menu(Seat *seat) {}
char *nullseat_get_ttymode(Seat *seat, const char *mode) { return NULL; }
void nullseat_set_busy_status(Seat *seat, BusyStatus status) {}
int nullseat_verify_ssh_host_key(
Seat *seat, const char *host, int port, const char *keytype,
char *keystr, const char *keydisp, char **key_fingerprints,
void (*callback)(void *ctx, int result), void *ctx) { return 0; }
int nullseat_confirm_weak_crypto_primitive(
Seat *seat, const char *algtype, const char *algname,
void (*callback)(void *ctx, int result), void *ctx) { return 0; }
int nullseat_confirm_weak_cached_hostkey(
Seat *seat, const char *algname, const char *betteralgs,
void (*callback)(void *ctx, int result), void *ctx) { return 0; }
bool nullseat_is_never_utf8(Seat *seat) { return false; }
bool nullseat_is_always_utf8(Seat *seat) { return true; }
void nullseat_echoedit_update(Seat *seat, bool echoing, bool editing) {}
const char *nullseat_get_x_display(Seat *seat) { return NULL; }
bool nullseat_get_windowid(Seat *seat, long *id_out) { return false; }
bool nullseat_get_window_pixel_size(
Seat *seat, int *width, int *height) { return false; }
StripCtrlChars *nullseat_stripctrl_new(
Seat *seat, BinarySink *bs_out, SeatInteractionContext sic) {return NULL;}
bool nullseat_set_trust_status(Seat *seat, bool tr) { return false; }
bool nullseat_set_trust_status_vacuously(Seat *seat, bool tr) { return true; }
bool nullseat_verbose_no(Seat *seat) { return false; }
bool nullseat_verbose_yes(Seat *seat) { return true; }
bool nullseat_interactive_no(Seat *seat) { return false; }
bool nullseat_interactive_yes(Seat *seat) { return true; }
bool nullseat_get_cursor_position(Seat *seat, int *x, int *y) { return false; }
bool null_lp_verbose_no(LogPolicy *lp) { return false; }
bool null_lp_verbose_yes(LogPolicy *lp) { return true; }
void sk_free_peer_info(SocketPeerInfo *pi)
{
if (pi) {
sfree((char *)pi->addr_text);
sfree((char *)pi->log_text);
sfree(pi);
}
}
void out_of_memory(void)
{
modalfatalbox("Out of memory");
}
+442 -420
View File
@@ -1,420 +1,442 @@
/*
* Header for misc.c.
*/
#ifndef PUTTY_MISC_H
#define PUTTY_MISC_H
#include "defs.h"
#include "puttymem.h"
#include "marshal.h"
#include <stdio.h> /* for FILE * */
#include <stdarg.h> /* for va_list */
#include <stdlib.h> /* for abort */
#include <time.h> /* for struct tm */
#include <limits.h> /* for INT_MAX/MIN */
#include <assert.h> /* for assert (obviously) */
unsigned long parse_blocksize(const char *bs);
char ctrlparse(char *s, char **next);
size_t host_strcspn(const char *s, const char *set);
char *host_strchr(const char *s, int c);
char *host_strrchr(const char *s, int c);
char *host_strduptrim(const char *s);
#ifdef __GNUC__
/*
* On MinGW, the correct compiler format checking for vsnprintf() etc
* can depend on compile-time flags; these control whether you get
* ISO C or Microsoft's non-standard format strings.
* We sometimes use __attribute__ ((format)) for our own printf-like
* functions, which are ultimately interpreted by the toolchain-chosen
* printf, so we need to take that into account to get correct warnings.
*/
#ifdef __MINGW_PRINTF_FORMAT
#define PUTTY_PRINTF_ARCHETYPE __MINGW_PRINTF_FORMAT
#else
#define PUTTY_PRINTF_ARCHETYPE printf
#endif
#endif /* __GNUC__ */
char *dupstr(const char *s);
char *dupcat(const char *s1, ...);
char *dupprintf(const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (PUTTY_PRINTF_ARCHETYPE, 1, 2)))
#endif
;
char *dupvprintf(const char *fmt, va_list ap);
void burnstr(char *string);
/*
* The visible part of a strbuf structure. There's a surrounding
* implementation struct in misc.c, which isn't exposed to client
* code.
*/
struct strbuf {
char *s;
unsigned char *u;
size_t len;
BinarySink_IMPLEMENTATION;
};
/* strbuf constructors: strbuf_new_nm and strbuf_new differ in that a
* strbuf constructed using the _nm version will resize itself by
* alloc/copy/smemclr/free instead of realloc. Use that version for
* data sensitive enough that it's worth costing performance to
* avoid copies of it lingering in process memory. */
strbuf *strbuf_new(void);
strbuf *strbuf_new_nm(void);
void strbuf_free(strbuf *buf);
void *strbuf_append(strbuf *buf, size_t len);
char *strbuf_to_str(strbuf *buf); /* does free buf, but you must free result */
void strbuf_catf(strbuf *buf, const char *fmt, ...);
void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap);
strbuf *strbuf_new_for_agent_query(void);
void strbuf_finalise_agent_query(strbuf *buf);
/* String-to-Unicode converters that auto-allocate the destination and
* work around the rather deficient interface of mb_to_wc.
*
* These actually live in miscucs.c, not misc.c (the distinction being
* that the former is only linked into tools that also have the main
* Unicode support). */
wchar_t *dup_mb_to_wc_c(int codepage, int flags, const char *string, int len);
wchar_t *dup_mb_to_wc(int codepage, int flags, const char *string);
static inline int toint(unsigned u)
{
/*
* Convert an unsigned to an int, without running into the
* undefined behaviour which happens by the strict C standard if
* the value overflows. You'd hope that sensible compilers would
* do the sensible thing in response to a cast, but actually I
* don't trust modern compilers not to do silly things like
* assuming that _obviously_ you wouldn't have caused an overflow
* and so they can elide an 'if (i < 0)' test immediately after
* the cast.
*
* Sensible compilers ought of course to optimise this entire
* function into 'just return the input value', and since it's
* also declared inline, elide it completely in their output.
*/
if (u <= (unsigned)INT_MAX)
return (int)u;
else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */
return INT_MIN + (int)(u - (unsigned)INT_MIN);
else
return INT_MIN; /* fallback; should never occur on binary machines */
}
char *fgetline(FILE *fp);
bool read_file_into(BinarySink *bs, FILE *fp);
char *chomp(char *str);
bool strstartswith(const char *s, const char *t);
bool strendswith(const char *s, const char *t);
void base64_encode_atom(const unsigned char *data, int n, char *out);
int base64_decode_atom(const char *atom, unsigned char *out);
struct bufchain_granule;
struct bufchain_tag {
struct bufchain_granule *head, *tail;
size_t buffersize; /* current amount of buffered data */
void (*queue_idempotent_callback)(IdempotentCallback *ic);
IdempotentCallback *ic;
};
void bufchain_init(bufchain *ch);
void bufchain_clear(bufchain *ch);
size_t bufchain_size(bufchain *ch);
void bufchain_add(bufchain *ch, const void *data, size_t len);
ptrlen bufchain_prefix(bufchain *ch);
void bufchain_consume(bufchain *ch, size_t len);
void bufchain_fetch(bufchain *ch, void *data, size_t len);
void bufchain_fetch_consume(bufchain *ch, void *data, size_t len);
bool bufchain_try_fetch_consume(bufchain *ch, void *data, size_t len);
size_t bufchain_fetch_consume_up_to(bufchain *ch, void *data, size_t len);
void bufchain_set_callback_inner(
bufchain *ch, IdempotentCallback *ic,
void (*queue_idempotent_callback)(IdempotentCallback *ic));
static inline void bufchain_set_callback(bufchain *ch, IdempotentCallback *ic)
{
extern void queue_idempotent_callback(struct IdempotentCallback *ic);
/* Wrapper that puts in the standard queue_idempotent_callback
* function. Lives here rather than in utils.c so that standalone
* programs can use the bufchain facility without this optional
* callback feature and not need to provide a stub of
* queue_idempotent_callback. */
bufchain_set_callback_inner(ch, ic, queue_idempotent_callback);
}
bool validate_manual_hostkey(char *key);
struct tm ltime(void);
/*
* Special form of strcmp which can cope with NULL inputs. NULL is
* defined to sort before even the empty string.
*/
int nullstrcmp(const char *a, const char *b);
static inline ptrlen make_ptrlen(const void *ptr, size_t len)
{
ptrlen pl;
pl.ptr = ptr;
pl.len = len;
return pl;
}
static inline ptrlen ptrlen_from_asciz(const char *str)
{
return make_ptrlen(str, strlen(str));
}
static inline ptrlen ptrlen_from_strbuf(strbuf *sb)
{
return make_ptrlen(sb->u, sb->len);
}
bool ptrlen_eq_string(ptrlen pl, const char *str);
bool ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2);
int ptrlen_strcmp(ptrlen pl1, ptrlen pl2);
/* ptrlen_startswith and ptrlen_endswith write through their 'tail'
* argument if and only if it is non-NULL and they return true. Hence
* you can write ptrlen_startswith(thing, prefix, &thing), writing
* back to the same ptrlen it read from, to remove a prefix if present
* and say whether it did so. */
bool ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail);
bool ptrlen_endswith(ptrlen whole, ptrlen suffix, ptrlen *tail);
ptrlen ptrlen_get_word(ptrlen *input, const char *separators);
char *mkstr(ptrlen pl);
int string_length_for_printf(size_t);
/* Derive two printf arguments from a ptrlen, suitable for "%.*s" */
#define PTRLEN_PRINTF(pl) \
string_length_for_printf((pl).len), (const char *)(pl).ptr
/* Make a ptrlen out of a compile-time string literal. We try to
* enforce that it _is_ a string literal by token-pasting "" on to it,
* which should provoke a compile error if it's any other kind of
* string. */
#define PTRLEN_LITERAL(stringlit) \
TYPECHECK("" stringlit "", make_ptrlen(stringlit, sizeof(stringlit)-1))
/* Make a ptrlen out of a constant byte array. */
#define PTRLEN_FROM_CONST_BYTES(a) make_ptrlen(a, sizeof(a))
/* Wipe sensitive data out of memory that's about to be freed. Simpler
* than memset because we don't need the fill char parameter; also
* attempts (by fiddly use of volatile) to inhibit the compiler from
* over-cleverly trying to optimise the memset away because it knows
* the variable is going out of scope. */
void smemclr(void *b, size_t len);
/* Compare two fixed-length chunks of memory for equality, without
* data-dependent control flow (so an attacker with a very accurate
* stopwatch can't try to guess where the first mismatching byte was).
* Returns false for mismatch or true for equality (unlike memcmp),
* hinted at by the 'eq' in the name. */
bool smemeq(const void *av, const void *bv, size_t len);
/* Encode a single UTF-8 character. Assumes that illegal characters
* (such as things in the surrogate range, or > 0x10FFFF) have already
* been removed. */
size_t encode_utf8(void *output, unsigned long ch);
char *buildinfo(const char *newline);
/*
* A function you can put at points in the code where execution should
* never reach in the first place. Better than assert(false), or even
* assert(false && "some explanatory message"), because some compilers
* don't interpret assert(false) as a declaration of unreachability,
* so they may still warn about pointless things like some variable
* not being initialised on the unreachable code path.
*
* I follow the assertion with a call to abort() just in case someone
* compiles with -DNDEBUG, and I wrap that abort inside my own
* function labelled NORETURN just in case some unusual kind of system
* header wasn't foresighted enough to label abort() itself that way.
*/
static inline NORETURN void unreachable_internal(void) { abort(); }
#define unreachable(msg) (assert(false && msg), unreachable_internal())
/*
* Debugging functions.
*
* Output goes to debug.log
*
* debug() is like printf().
*
* dmemdump() and dmemdumpl() both do memory dumps. The difference
* is that dmemdumpl() is more suited for when the memory address is
* important (say because you'll be recording pointer values later
* on). dmemdump() is more concise.
*/
#ifdef DEBUG
void debug_printf(const char *fmt, ...);
void debug_memdump(const void *buf, int len, bool L);
#define debug(...) (debug_printf(__VA_ARGS__))
#define dmemdump(buf,len) (debug_memdump(buf, len, false))
#define dmemdumpl(buf,len) (debug_memdump(buf, len, true))
#else
#define debug(...) ((void)0)
#define dmemdump(buf,len) ((void)0)
#define dmemdumpl(buf,len) ((void)0)
#endif
#ifndef lenof
#define lenof(x) ( (sizeof((x))) / (sizeof(*(x))))
#endif
#ifndef min
#define min(x,y) ( (x) < (y) ? (x) : (y) )
#endif
#ifndef max
#define max(x,y) ( (x) > (y) ? (x) : (y) )
#endif
static inline uint64_t GET_64BIT_LSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint64_t)p[0] ) | ((uint64_t)p[1] << 8) |
((uint64_t)p[2] << 16) | ((uint64_t)p[3] << 24) |
((uint64_t)p[4] << 32) | ((uint64_t)p[5] << 40) |
((uint64_t)p[6] << 48) | ((uint64_t)p[7] << 56));
}
static inline void PUT_64BIT_LSB_FIRST(void *vp, uint64_t value)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (uint8_t)(value);
p[1] = (uint8_t)(value >> 8);
p[2] = (uint8_t)(value >> 16);
p[3] = (uint8_t)(value >> 24);
p[4] = (uint8_t)(value >> 32);
p[5] = (uint8_t)(value >> 40);
p[6] = (uint8_t)(value >> 48);
p[7] = (uint8_t)(value >> 56);
}
static inline uint32_t GET_32BIT_LSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint32_t)p[0] ) | ((uint32_t)p[1] << 8) |
((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24));
}
static inline void PUT_32BIT_LSB_FIRST(void *vp, uint32_t value)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (uint8_t)(value);
p[1] = (uint8_t)(value >> 8);
p[2] = (uint8_t)(value >> 16);
p[3] = (uint8_t)(value >> 24);
}
static inline uint16_t GET_16BIT_LSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint16_t)p[0] ) | ((uint16_t)p[1] << 8));
}
static inline void PUT_16BIT_LSB_FIRST(void *vp, uint16_t value)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (uint8_t)(value);
p[1] = (uint8_t)(value >> 8);
}
static inline uint64_t GET_64BIT_MSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint64_t)p[7] ) | ((uint64_t)p[6] << 8) |
((uint64_t)p[5] << 16) | ((uint64_t)p[4] << 24) |
((uint64_t)p[3] << 32) | ((uint64_t)p[2] << 40) |
((uint64_t)p[1] << 48) | ((uint64_t)p[0] << 56));
}
static inline void PUT_64BIT_MSB_FIRST(void *vp, uint64_t value)
{
uint8_t *p = (uint8_t *)vp;
p[7] = (uint8_t)(value);
p[6] = (uint8_t)(value >> 8);
p[5] = (uint8_t)(value >> 16);
p[4] = (uint8_t)(value >> 24);
p[3] = (uint8_t)(value >> 32);
p[2] = (uint8_t)(value >> 40);
p[1] = (uint8_t)(value >> 48);
p[0] = (uint8_t)(value >> 56);
}
static inline uint32_t GET_32BIT_MSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint32_t)p[3] ) | ((uint32_t)p[2] << 8) |
((uint32_t)p[1] << 16) | ((uint32_t)p[0] << 24));
}
static inline void PUT_32BIT_MSB_FIRST(void *vp, uint32_t value)
{
uint8_t *p = (uint8_t *)vp;
p[3] = (uint8_t)(value);
p[2] = (uint8_t)(value >> 8);
p[1] = (uint8_t)(value >> 16);
p[0] = (uint8_t)(value >> 24);
}
static inline uint16_t GET_16BIT_MSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint16_t)p[1] ) | ((uint16_t)p[0] << 8));
}
static inline void PUT_16BIT_MSB_FIRST(void *vp, uint16_t value)
{
uint8_t *p = (uint8_t *)vp;
p[1] = (uint8_t)(value);
p[0] = (uint8_t)(value >> 8);
}
/* Replace NULL with the empty string, permitting an idiom in which we
* get a string (pointer,length) pair that might be NULL,0 and can
* then safely say things like printf("%.*s", length, NULLTOEMPTY(ptr)) */
static inline const char *NULLTOEMPTY(const char *s)
{
return s ? s : "";
}
/* StripCtrlChars, defined in stripctrl.c: an adapter you can put on
* the front of one BinarySink and which functions as one in turn.
* Interprets its input as a stream of multibyte characters in the
* system locale, and removes any that are not either printable
* characters or newlines. */
struct StripCtrlChars {
BinarySink_IMPLEMENTATION;
/* and this is contained in a larger structure */
};
StripCtrlChars *stripctrl_new(
BinarySink *bs_out, bool permit_cr, wchar_t substitution);
StripCtrlChars *stripctrl_new_term_fn(
BinarySink *bs_out, bool permit_cr, wchar_t substitution,
Terminal *term, unsigned long (*translate)(
Terminal *, term_utf8_decode *, unsigned char));
#define stripctrl_new_term(bs, cr, sub, term) \
stripctrl_new_term_fn(bs, cr, sub, term, term_translate)
void stripctrl_retarget(StripCtrlChars *sccpub, BinarySink *new_bs_out);
void stripctrl_reset(StripCtrlChars *sccpub);
void stripctrl_free(StripCtrlChars *sanpub);
void stripctrl_enable_line_limiting(StripCtrlChars *sccpub);
char *stripctrl_string_ptrlen(StripCtrlChars *sccpub, ptrlen str);
static inline char *stripctrl_string(StripCtrlChars *sccpub, const char *str)
{
return stripctrl_string_ptrlen(sccpub, ptrlen_from_asciz(str));
}
#endif
/*
* Header for misc.c.
*/
#ifndef PUTTY_MISC_H
#define PUTTY_MISC_H
#include "defs.h"
#include "puttymem.h"
#include "marshal.h"
#include <stdio.h> /* for FILE * */
#include <stdarg.h> /* for va_list */
#include <stdlib.h> /* for abort */
#include <time.h> /* for struct tm */
#include <limits.h> /* for INT_MAX/MIN */
#include <assert.h> /* for assert (obviously) */
unsigned long parse_blocksize(const char *bs);
char ctrlparse(char *s, char **next);
size_t host_strcspn(const char *s, const char *set);
char *host_strchr(const char *s, int c);
char *host_strrchr(const char *s, int c);
char *host_strduptrim(const char *s);
char *dupstr(const char *s);
char *dupcat_fn(const char *s1, ...);
#define dupcat(...) dupcat_fn(__VA_ARGS__, (const char *)NULL)
char *dupprintf(const char *fmt, ...) PRINTF_LIKE(1, 2);
char *dupvprintf(const char *fmt, va_list ap);
void burnstr(char *string);
/*
* The visible part of a strbuf structure. There's a surrounding
* implementation struct in misc.c, which isn't exposed to client
* code.
*/
struct strbuf {
char *s;
unsigned char *u;
size_t len;
BinarySink_IMPLEMENTATION;
};
/* strbuf constructors: strbuf_new_nm and strbuf_new differ in that a
* strbuf constructed using the _nm version will resize itself by
* alloc/copy/smemclr/free instead of realloc. Use that version for
* data sensitive enough that it's worth costing performance to
* avoid copies of it lingering in process memory. */
strbuf *strbuf_new(void);
strbuf *strbuf_new_nm(void);
void strbuf_free(strbuf *buf);
void *strbuf_append(strbuf *buf, size_t len);
void strbuf_shrink_to(strbuf *buf, size_t new_len);
void strbuf_shrink_by(strbuf *buf, size_t amount_to_remove);
char *strbuf_to_str(strbuf *buf); /* does free buf, but you must free result */
void strbuf_catf(strbuf *buf, const char *fmt, ...) PRINTF_LIKE(2, 3);
void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap);
static inline void strbuf_clear(strbuf *buf) { strbuf_shrink_to(buf, 0); }
bool strbuf_chomp(strbuf *buf, char char_to_remove);
strbuf *strbuf_new_for_agent_query(void);
void strbuf_finalise_agent_query(strbuf *buf);
/* String-to-Unicode converters that auto-allocate the destination and
* work around the rather deficient interface of mb_to_wc.
*
* These actually live in miscucs.c, not misc.c (the distinction being
* that the former is only linked into tools that also have the main
* Unicode support). */
wchar_t *dup_mb_to_wc_c(int codepage, int flags, const char *string, int len);
wchar_t *dup_mb_to_wc(int codepage, int flags, const char *string);
static inline int toint(unsigned u)
{
/*
* Convert an unsigned to an int, without running into the
* undefined behaviour which happens by the strict C standard if
* the value overflows. You'd hope that sensible compilers would
* do the sensible thing in response to a cast, but actually I
* don't trust modern compilers not to do silly things like
* assuming that _obviously_ you wouldn't have caused an overflow
* and so they can elide an 'if (i < 0)' test immediately after
* the cast.
*
* Sensible compilers ought of course to optimise this entire
* function into 'just return the input value', and since it's
* also declared inline, elide it completely in their output.
*/
if (u <= (unsigned)INT_MAX)
return (int)u;
else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */
return INT_MIN + (int)(u - (unsigned)INT_MIN);
else
return INT_MIN; /* fallback; should never occur on binary machines */
}
char *fgetline(FILE *fp);
bool read_file_into(BinarySink *bs, FILE *fp);
char *chomp(char *str);
bool strstartswith(const char *s, const char *t);
bool strendswith(const char *s, const char *t);
void base64_encode_atom(const unsigned char *data, int n, char *out);
int base64_decode_atom(const char *atom, unsigned char *out);
struct bufchain_granule;
struct bufchain_tag {
struct bufchain_granule *head, *tail;
size_t buffersize; /* current amount of buffered data */
void (*queue_idempotent_callback)(IdempotentCallback *ic);
IdempotentCallback *ic;
};
void bufchain_init(bufchain *ch);
void bufchain_clear(bufchain *ch);
size_t bufchain_size(bufchain *ch);
void bufchain_add(bufchain *ch, const void *data, size_t len);
ptrlen bufchain_prefix(bufchain *ch);
void bufchain_consume(bufchain *ch, size_t len);
void bufchain_fetch(bufchain *ch, void *data, size_t len);
void bufchain_fetch_consume(bufchain *ch, void *data, size_t len);
bool bufchain_try_fetch_consume(bufchain *ch, void *data, size_t len);
size_t bufchain_fetch_consume_up_to(bufchain *ch, void *data, size_t len);
void bufchain_set_callback_inner(
bufchain *ch, IdempotentCallback *ic,
void (*queue_idempotent_callback)(IdempotentCallback *ic));
static inline void bufchain_set_callback(bufchain *ch, IdempotentCallback *ic)
{
extern void queue_idempotent_callback(struct IdempotentCallback *ic);
/* Wrapper that puts in the standard queue_idempotent_callback
* function. Lives here rather than in utils.c so that standalone
* programs can use the bufchain facility without this optional
* callback feature and not need to provide a stub of
* queue_idempotent_callback. */
bufchain_set_callback_inner(ch, ic, queue_idempotent_callback);
}
bool validate_manual_hostkey(char *key);
struct tm ltime(void);
/*
* Special form of strcmp which can cope with NULL inputs. NULL is
* defined to sort before even the empty string.
*/
int nullstrcmp(const char *a, const char *b);
static inline ptrlen make_ptrlen(const void *ptr, size_t len)
{
ptrlen pl;
pl.ptr = ptr;
pl.len = len;
return pl;
}
static inline ptrlen ptrlen_from_asciz(const char *str)
{
return make_ptrlen(str, strlen(str));
}
static inline ptrlen ptrlen_from_strbuf(strbuf *sb)
{
return make_ptrlen(sb->u, sb->len);
}
bool ptrlen_eq_string(ptrlen pl, const char *str);
bool ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2);
int ptrlen_strcmp(ptrlen pl1, ptrlen pl2);
/* ptrlen_startswith and ptrlen_endswith write through their 'tail'
* argument if and only if it is non-NULL and they return true. Hence
* you can write ptrlen_startswith(thing, prefix, &thing), writing
* back to the same ptrlen it read from, to remove a prefix if present
* and say whether it did so. */
bool ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail);
bool ptrlen_endswith(ptrlen whole, ptrlen suffix, ptrlen *tail);
ptrlen ptrlen_get_word(ptrlen *input, const char *separators);
char *mkstr(ptrlen pl);
int string_length_for_printf(size_t);
/* Derive two printf arguments from a ptrlen, suitable for "%.*s" */
#define PTRLEN_PRINTF(pl) \
string_length_for_printf((pl).len), (const char *)(pl).ptr
/* Make a ptrlen out of a compile-time string literal. We try to
* enforce that it _is_ a string literal by token-pasting "" on to it,
* which should provoke a compile error if it's any other kind of
* string. */
#define PTRLEN_LITERAL(stringlit) \
TYPECHECK("" stringlit "", make_ptrlen(stringlit, sizeof(stringlit)-1))
/* Make a ptrlen out of a compile-time string literal in a way that
* allows you to declare the ptrlen itself as a compile-time initialiser. */
#define PTRLEN_DECL_LITERAL(stringlit) \
{ TYPECHECK("" stringlit "", stringlit), sizeof(stringlit)-1 }
/* Make a ptrlen out of a constant byte array. */
#define PTRLEN_FROM_CONST_BYTES(a) make_ptrlen(a, sizeof(a))
/* Wipe sensitive data out of memory that's about to be freed. Simpler
* than memset because we don't need the fill char parameter; also
* attempts (by fiddly use of volatile) to inhibit the compiler from
* over-cleverly trying to optimise the memset away because it knows
* the variable is going out of scope. */
void smemclr(void *b, size_t len);
/* Compare two fixed-length chunks of memory for equality, without
* data-dependent control flow (so an attacker with a very accurate
* stopwatch can't try to guess where the first mismatching byte was).
* Returns false for mismatch or true for equality (unlike memcmp),
* hinted at by the 'eq' in the name. */
bool smemeq(const void *av, const void *bv, size_t len);
/* Encode a single UTF-8 character. Assumes that illegal characters
* (such as things in the surrogate range, or > 0x10FFFF) have already
* been removed. */
size_t encode_utf8(void *output, unsigned long ch);
/* Write a string out in C string-literal format. */
void write_c_string_literal(FILE *fp, ptrlen str);
char *buildinfo(const char *newline);
/*
* A function you can put at points in the code where execution should
* never reach in the first place. Better than assert(false), or even
* assert(false && "some explanatory message"), because some compilers
* don't interpret assert(false) as a declaration of unreachability,
* so they may still warn about pointless things like some variable
* not being initialised on the unreachable code path.
*
* I follow the assertion with a call to abort() just in case someone
* compiles with -DNDEBUG, and I wrap that abort inside my own
* function labelled NORETURN just in case some unusual kind of system
* header wasn't foresighted enough to label abort() itself that way.
*/
static inline NORETURN void unreachable_internal(void) { abort(); }
#define unreachable(msg) (assert(false && msg), unreachable_internal())
/*
* Debugging functions.
*
* Output goes to debug.log
*
* debug() is like printf().
*
* dmemdump() and dmemdumpl() both do memory dumps. The difference
* is that dmemdumpl() is more suited for when the memory address is
* important (say because you'll be recording pointer values later
* on). dmemdump() is more concise.
*/
#ifdef DEBUG
void debug_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);
void debug_memdump(const void *buf, int len, bool L);
#define debug(...) (debug_printf(__VA_ARGS__))
#define dmemdump(buf,len) (debug_memdump(buf, len, false))
#define dmemdumpl(buf,len) (debug_memdump(buf, len, true))
#else
#define debug(...) ((void)0)
#define dmemdump(buf,len) ((void)0)
#define dmemdumpl(buf,len) ((void)0)
#endif
#ifndef lenof
#define lenof(x) ( (sizeof((x))) / (sizeof(*(x))))
#endif
#ifndef min
#define min(x,y) ( (x) < (y) ? (x) : (y) )
#endif
#ifndef max
#define max(x,y) ( (x) > (y) ? (x) : (y) )
#endif
static inline uint64_t GET_64BIT_LSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint64_t)p[0] ) | ((uint64_t)p[1] << 8) |
((uint64_t)p[2] << 16) | ((uint64_t)p[3] << 24) |
((uint64_t)p[4] << 32) | ((uint64_t)p[5] << 40) |
((uint64_t)p[6] << 48) | ((uint64_t)p[7] << 56));
}
static inline void PUT_64BIT_LSB_FIRST(void *vp, uint64_t value)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (uint8_t)(value);
p[1] = (uint8_t)(value >> 8);
p[2] = (uint8_t)(value >> 16);
p[3] = (uint8_t)(value >> 24);
p[4] = (uint8_t)(value >> 32);
p[5] = (uint8_t)(value >> 40);
p[6] = (uint8_t)(value >> 48);
p[7] = (uint8_t)(value >> 56);
}
static inline uint32_t GET_32BIT_LSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint32_t)p[0] ) | ((uint32_t)p[1] << 8) |
((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24));
}
static inline void PUT_32BIT_LSB_FIRST(void *vp, uint32_t value)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (uint8_t)(value);
p[1] = (uint8_t)(value >> 8);
p[2] = (uint8_t)(value >> 16);
p[3] = (uint8_t)(value >> 24);
}
static inline uint16_t GET_16BIT_LSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint16_t)p[0] ) | ((uint16_t)p[1] << 8));
}
static inline void PUT_16BIT_LSB_FIRST(void *vp, uint16_t value)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (uint8_t)(value);
p[1] = (uint8_t)(value >> 8);
}
static inline uint64_t GET_64BIT_MSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint64_t)p[7] ) | ((uint64_t)p[6] << 8) |
((uint64_t)p[5] << 16) | ((uint64_t)p[4] << 24) |
((uint64_t)p[3] << 32) | ((uint64_t)p[2] << 40) |
((uint64_t)p[1] << 48) | ((uint64_t)p[0] << 56));
}
static inline void PUT_64BIT_MSB_FIRST(void *vp, uint64_t value)
{
uint8_t *p = (uint8_t *)vp;
p[7] = (uint8_t)(value);
p[6] = (uint8_t)(value >> 8);
p[5] = (uint8_t)(value >> 16);
p[4] = (uint8_t)(value >> 24);
p[3] = (uint8_t)(value >> 32);
p[2] = (uint8_t)(value >> 40);
p[1] = (uint8_t)(value >> 48);
p[0] = (uint8_t)(value >> 56);
}
static inline uint32_t GET_32BIT_MSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint32_t)p[3] ) | ((uint32_t)p[2] << 8) |
((uint32_t)p[1] << 16) | ((uint32_t)p[0] << 24));
}
static inline void PUT_32BIT_MSB_FIRST(void *vp, uint32_t value)
{
uint8_t *p = (uint8_t *)vp;
p[3] = (uint8_t)(value);
p[2] = (uint8_t)(value >> 8);
p[1] = (uint8_t)(value >> 16);
p[0] = (uint8_t)(value >> 24);
}
static inline uint16_t GET_16BIT_MSB_FIRST(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (((uint16_t)p[1] ) | ((uint16_t)p[0] << 8));
}
static inline void PUT_16BIT_MSB_FIRST(void *vp, uint16_t value)
{
uint8_t *p = (uint8_t *)vp;
p[1] = (uint8_t)(value);
p[0] = (uint8_t)(value >> 8);
}
/* Replace NULL with the empty string, permitting an idiom in which we
* get a string (pointer,length) pair that might be NULL,0 and can
* then safely say things like printf("%.*s", length, NULLTOEMPTY(ptr)) */
static inline const char *NULLTOEMPTY(const char *s)
{
return s ? s : "";
}
/* StripCtrlChars, defined in stripctrl.c: an adapter you can put on
* the front of one BinarySink and which functions as one in turn.
* Interprets its input as a stream of multibyte characters in the
* system locale, and removes any that are not either printable
* characters or newlines. */
struct StripCtrlChars {
BinarySink_IMPLEMENTATION;
/* and this is contained in a larger structure */
};
StripCtrlChars *stripctrl_new(
BinarySink *bs_out, bool permit_cr, wchar_t substitution);
StripCtrlChars *stripctrl_new_term_fn(
BinarySink *bs_out, bool permit_cr, wchar_t substitution,
Terminal *term, unsigned long (*translate)(
Terminal *, term_utf8_decode *, unsigned char));
#define stripctrl_new_term(bs, cr, sub, term) \
stripctrl_new_term_fn(bs, cr, sub, term, term_translate)
void stripctrl_retarget(StripCtrlChars *sccpub, BinarySink *new_bs_out);
void stripctrl_reset(StripCtrlChars *sccpub);
void stripctrl_free(StripCtrlChars *sanpub);
void stripctrl_enable_line_limiting(StripCtrlChars *sccpub);
char *stripctrl_string_ptrlen(StripCtrlChars *sccpub, ptrlen str);
static inline char *stripctrl_string(StripCtrlChars *sccpub, const char *str)
{
return stripctrl_string_ptrlen(sccpub, ptrlen_from_asciz(str));
}
/*
* A mechanism for loading a file from disk into a memory buffer where
* it can be picked apart as a BinarySource.
*/
struct LoadedFile {
char *data;
size_t len, max_size;
BinarySource_IMPLEMENTATION;
};
typedef enum {
LF_OK, /* file loaded successfully */
LF_TOO_BIG, /* file didn't fit in buffer */
LF_ERROR, /* error from stdio layer */
} LoadFileStatus;
LoadedFile *lf_new(size_t max_size);
void lf_free(LoadedFile *lf);
LoadFileStatus lf_load_fp(LoadedFile *lf, FILE *fp);
LoadFileStatus lf_load(LoadedFile *lf, const Filename *filename);
static inline ptrlen ptrlen_from_lf(LoadedFile *lf)
{ return make_ptrlen(lf->data, lf->len); }
/* Set the memory block of 'size' bytes at 'out' to the bitwise XOR of
* the two blocks of the same size at 'in1' and 'in2'.
*
* 'out' may point to exactly the same address as one of the inputs,
* but if the input and output blocks overlap in any other way, the
* result of this function is not guaranteed. No memmove-style effort
* is made to handle difficult overlap cases. */
void memxor(uint8_t *out, const uint8_t *in1, const uint8_t *in2, size_t size);
#endif
+389 -138
View File
@@ -33,7 +33,36 @@ static inline BignumInt mp_word(mp_int *x, size_t i)
return i < x->nw ? x->w[i] : 0;
}
static mp_int *mp_make_sized(size_t nw)
/*
* Shift an ordinary C integer by BIGNUM_INT_BITS, in a way that
* avoids writing a shift operator whose RHS is greater or equal to
* the size of the type, because that's undefined behaviour in C.
*
* In fact we must avoid even writing it in a definitely-untaken
* branch of an if, because compilers will sometimes warn about
* that. So you can't just write 'shift too big ? 0 : n >> shift',
* because even if 'shift too big' is a constant-expression
* evaluating to false, you can still get complaints about the
* else clause of the ?:.
*
* So we have to re-check _inside_ that clause, so that the shift
* count is reset to something nonsensical but safe in the case
* where the clause wasn't going to be taken anyway.
*/
static uintmax_t shift_right_by_one_word(uintmax_t n)
{
bool shift_too_big = BIGNUM_INT_BYTES >= sizeof(n);
return shift_too_big ? 0 :
n >> (shift_too_big ? 0 : BIGNUM_INT_BITS);
}
static uintmax_t shift_left_by_one_word(uintmax_t n)
{
bool shift_too_big = BIGNUM_INT_BYTES >= sizeof(n);
return shift_too_big ? 0 :
n << (shift_too_big ? 0 : BIGNUM_INT_BITS);
}
mp_int *mp_make_sized(size_t nw)
{
mp_int *x = snew_plus(mp_int, nw * sizeof(BignumInt));
assert(nw); /* we outlaw the zero-word mp_int */
@@ -90,6 +119,14 @@ void mp_copy_into(mp_int *dest, mp_int *src)
smemclr(dest->w + copy_nw, (dest->nw - copy_nw) * sizeof(BignumInt));
}
void mp_copy_integer_into(mp_int *r, uintmax_t n)
{
for (size_t i = 0; i < r->nw; i++) {
r->w[i] = n;
n = shift_right_by_one_word(n);
}
}
/*
* Conditional selection is done by negating 'which', to give a mask
* word which is all 1s if which==1 and all 0s if which==0. Then you
@@ -187,7 +224,7 @@ mp_int *mp_from_decimal_pl(ptrlen decimal)
mp_int *x = mp_make_sized(words);
for (size_t i = 0; i < decimal.len; i++) {
mp_add_integer_into(x, x, ((char *)decimal.ptr)[i] - '0');
mp_add_integer_into(x, x, ((const char *)decimal.ptr)[i] - '0');
if (i+1 == decimal.len)
break;
@@ -216,7 +253,7 @@ mp_int *mp_from_hex_pl(ptrlen hex)
words = size_t_max(words, 1);
mp_int *x = mp_make_sized(words);
for (size_t nibble = 0; nibble < hex.len; nibble++) {
BignumInt digit = ((char *)hex.ptr)[hex.len-1 - nibble];
BignumInt digit = ((const char *)hex.ptr)[hex.len-1 - nibble];
BignumInt lmask = ~-((BignumInt)((digit-'a')|('f'-digit))
>> (BIGNUM_INT_BITS-1));
@@ -260,12 +297,8 @@ unsigned mp_get_bit(mp_int *x, size_t bit)
uintmax_t mp_get_integer(mp_int *x)
{
uintmax_t toret = 0;
for (size_t i = x->nw; i-- > 0 ;) {
/* Shift in two stages to avoid undefined behaviour if the
* shift count equals the integer width */
toret = (toret << (BIGNUM_INT_BITS/2)) << (BIGNUM_INT_BITS/2);
toret |= x->w[i];
}
for (size_t i = x->nw; i-- > 0 ;)
toret = shift_left_by_one_word(toret) | x->w[i];
return toret;
}
@@ -757,8 +790,8 @@ static BignumCarry mp_add_masked_integer_into(
{
for (size_t i = 0; i < rw; i++) {
BignumInt aword = mp_word(a, i);
size_t shift = i * BIGNUM_INT_BITS;
BignumInt bword = shift < BIGNUM_INT_BYTES ? b >> shift : 0;
BignumInt bword = b;
b = shift_right_by_one_word(b);
BignumInt out;
bword = (bword ^ b_xor) & b_and;
BignumADC(out, carry, aword, bword, carry);
@@ -799,7 +832,7 @@ static void mp_add_integer_into_shifted_by_words(
* shift n down. If it's 0, we add zero bits into r, and
* leave n alone. */
BignumInt bword = n & -(BignumInt)indicator;
uintmax_t new_n = (BIGNUM_INT_BITS < 64 ? n >> BIGNUM_INT_BITS : 0);
uintmax_t new_n = shift_right_by_one_word(n);
n ^= (n ^ new_n) & -(uintmax_t)indicator;
BignumInt aword = mp_word(a, i);
@@ -844,11 +877,12 @@ unsigned mp_cmp_hs(mp_int *a, mp_int *b)
unsigned mp_hs_integer(mp_int *x, uintmax_t n)
{
BignumInt carry = 1;
for (size_t i = 0; i < x->nw; i++) {
size_t shift = i * BIGNUM_INT_BITS;
BignumInt nword = shift < CHAR_BIT*sizeof(n) ? n >> shift : 0;
size_t nwords = sizeof(n)/BIGNUM_INT_BYTES;
for (size_t i = 0, e = size_t_max(x->nw, nwords); i < e; i++) {
BignumInt nword = n;
n = shift_right_by_one_word(n);
BignumInt dummy_out;
BignumADC(dummy_out, carry, x->w[i], ~nword, carry);
BignumADC(dummy_out, carry, mp_word(x, i), ~nword, carry);
(void)dummy_out;
}
return carry;
@@ -870,15 +904,16 @@ unsigned mp_cmp_eq(mp_int *a, mp_int *b)
unsigned mp_eq_integer(mp_int *x, uintmax_t n)
{
BignumInt diff = 0;
for (size_t i = 0; i < x->nw; i++) {
size_t shift = i * BIGNUM_INT_BITS;
BignumInt nword = shift < CHAR_BIT*sizeof(n) ? n >> shift : 0;
diff |= x->w[i] ^ nword;
size_t nwords = sizeof(n)/BIGNUM_INT_BYTES;
for (size_t i = 0, e = size_t_max(x->nw, nwords); i < e; i++) {
BignumInt nword = n;
n = shift_right_by_one_word(n);
diff |= mp_word(x, i) ^ nword;
}
return 1 ^ normalise_to_1(diff); /* return 1 if diff _is_ zero */
}
void mp_neg_into(mp_int *r, mp_int *a)
static void mp_neg_into(mp_int *r, mp_int *a)
{
mp_int zero;
zero.nw = 0;
@@ -899,13 +934,6 @@ mp_int *mp_sub(mp_int *x, mp_int *y)
return r;
}
mp_int *mp_neg(mp_int *a)
{
mp_int *r = mp_make_sized(a->nw);
mp_neg_into(r, a);
return r;
}
/*
* Internal routine: multiply and accumulate in the trivial O(N^2)
* way. Sets r <- r + a*b.
@@ -1121,6 +1149,14 @@ void mp_rshift_fixed_into(mp_int *r, mp_int *a, size_t bits)
}
}
mp_int *mp_lshift_fixed(mp_int *x, size_t bits)
{
size_t words = (bits + BIGNUM_INT_BITS - 1) / BIGNUM_INT_BITS;
mp_int *r = mp_make_sized(x->nw + words);
mp_lshift_fixed_into(r, x, bits);
return r;
}
mp_int *mp_rshift_fixed(mp_int *x, size_t bits)
{
size_t words = bits / BIGNUM_INT_BITS;
@@ -1138,18 +1174,16 @@ mp_int *mp_rshift_fixed(mp_int *x, size_t bits)
* by a power of 2 words, using the usual bit twiddling to make the
* whole shift conditional on the appropriate bit of n.
*/
mp_int *mp_rshift_safe(mp_int *x, size_t bits)
static void mp_rshift_safe_in_place(mp_int *r, size_t bits)
{
size_t wordshift = bits / BIGNUM_INT_BITS;
size_t bitshift = bits % BIGNUM_INT_BITS;
mp_int *r = mp_copy(x);
unsigned clear = (r->nw - wordshift) >> (CHAR_BIT * sizeof(size_t) - 1);
mp_cond_clear(r, clear);
for (unsigned bit = 0; r->nw >> bit; bit++) {
size_t word_offset = 1 << bit;
size_t word_offset = (size_t)1 << bit;
BignumInt mask = -(BignumInt)((wordshift >> bit) & 1);
for (size_t i = 0; i < r->nw; i++) {
BignumInt w = mp_word(r, i + word_offset);
@@ -1169,10 +1203,60 @@ mp_int *mp_rshift_safe(mp_int *x, size_t bits)
r->w[i] ^= (r->w[i] ^ w) & mask;
}
}
}
mp_int *mp_rshift_safe(mp_int *x, size_t bits)
{
mp_int *r = mp_copy(x);
mp_rshift_safe_in_place(r, bits);
return r;
}
void mp_rshift_safe_into(mp_int *r, mp_int *x, size_t bits)
{
mp_copy_into(r, x);
mp_rshift_safe_in_place(r, bits);
}
static void mp_lshift_safe_in_place(mp_int *r, size_t bits)
{
size_t wordshift = bits / BIGNUM_INT_BITS;
size_t bitshift = bits % BIGNUM_INT_BITS;
/*
* Same strategy as mp_rshift_safe_in_place, but of course the
* other way up.
*/
unsigned clear = (r->nw - wordshift) >> (CHAR_BIT * sizeof(size_t) - 1);
mp_cond_clear(r, clear);
for (unsigned bit = 0; r->nw >> bit; bit++) {
size_t word_offset = (size_t)1 << bit;
BignumInt mask = -(BignumInt)((wordshift >> bit) & 1);
for (size_t i = r->nw; i-- > 0 ;) {
BignumInt w = mp_word(r, i - word_offset);
r->w[i] ^= (r->w[i] ^ w) & mask;
}
}
size_t downshift = BIGNUM_INT_BITS - bitshift;
size_t no_shift = (downshift >> BIGNUM_INT_BITS_BITS);
downshift &= ~-(size_t)no_shift;
BignumInt downshifted_mask = ~-(BignumInt)no_shift;
for (size_t i = r->nw; i-- > 0 ;) {
r->w[i] = (r->w[i] << bitshift) |
((mp_word(r, i-1) >> downshift) & downshifted_mask);
}
}
void mp_lshift_safe_into(mp_int *r, mp_int *x, size_t bits)
{
mp_copy_into(r, x);
mp_lshift_safe_in_place(r, bits);
}
void mp_reduce_mod_2to(mp_int *x, size_t p)
{
size_t word = p / BIGNUM_INT_BITS;
@@ -1506,10 +1590,10 @@ mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus)
}
/*
* Given two coprime nonzero input integers a,b, returns two integers
* A,B such that A*a - B*b = 1. A,B will be the minimal non-negative
* pair satisfying that criterion, which is equivalent to saying that
* 0<=A<b and 0<=B<a.
* Given two input integers a,b which are not both even, computes d =
* gcd(a,b) and also two integers A,B such that A*a - B*b = d. A,B
* will be the minimal non-negative pair satisfying that criterion,
* which is equivalent to saying that 0 <= A < b/d and 0 <= B < a/d.
*
* This algorithm is an adapted form of Stein's algorithm, which
* computes gcd(a,b) using only addition and bit shifts (i.e. without
@@ -1521,9 +1605,11 @@ mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus)
* - if both of a,b are odd, then WLOG a>b, and gcd(a,b) =
* gcd(b,(a-b)/2).
*
* For this application, I always expect the actual gcd to be coprime,
* so we can rule out the 'both even' initial case. So this function
* just performs a sequence of reductions in the following form:
* Sometimes this function is used for modular inversion, in which
* case we already know we expect the two inputs to be coprime, so to
* save time the 'both even' initial case is assumed not to arise (or
* to have been handled already by the caller). So this function just
* performs a sequence of reductions in the following form:
*
* - if a,b are both odd, sort them so that a > b, and replace a with
* b-a; otherwise sort them so that a is the even one
@@ -1534,14 +1620,14 @@ mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus)
* generate those in each case, based on the coefficients from the
* reduced pair of numbers:
*
* - If a is even, and u,v are such that u*(a/2) + v*b = 1:
* + if u is also even, then this is just (u/2)*a + v*b = 1
* + otherwise, (u+b)*(a/2) + (v-a/2)*b is also equal to 1, and
* - If a is even, and u,v are such that u*(a/2) + v*b = d:
* + if u is also even, then this is just (u/2)*a + v*b = d
* + otherwise, (u+b)*(a/2) + (v-a/2)*b is also equal to d, and
* since u and b are both odd, (u+b)/2 is an integer, so we have
* ((u+b)/2)*a + (v-a/2)*b = 1.
* ((u+b)/2)*a + (v-a/2)*b = d.
*
* - If a,b are both odd, and u,v are such that u*b + v*(a-b) = 1,
* then v*a + (u-v)*b = 1.
* - If a,b are both odd, and u,v are such that u*b + v*(a-b) = d,
* then v*a + (u-v)*b = d.
*
* In the case where we passed from (a,b) to (b,(a-b)/2), we regard it
* as having first subtracted b from a and then halved a, so both of
@@ -1559,11 +1645,11 @@ mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus)
* Also, since these mp_ints are generally treated as unsigned, we
* store the coefficients by absolute value, with the semantics that
* they always have opposite sign, and in the unwinding loop we keep a
* bit indicating whether Aa-Bb is currently expected to be +1 or -1,
* so that we can do one final conditional adjustment if it's -1.
* bit indicating whether Aa-Bb is currently expected to be +d or -d,
* so that we can do one final conditional adjustment if it's -d.
*
* Once the reduction rules have managed to reduce the input numbers
* to (0,1), then they are stable (the next reduction will always
* to (0,d), then they are stable (the next reduction will always
* divide the even one by 2, which maps 0 to 0). So it doesn't matter
* if we do more steps of the algorithm than necessary; hence, for
* constant time, we just need to find the maximum number we could
@@ -1582,7 +1668,7 @@ mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus)
* n further steps each of which subtracts 1 from y and halves it.
*/
static void mp_bezout_into(mp_int *a_coeff_out, mp_int *b_coeff_out,
mp_int *a_in, mp_int *b_in)
mp_int *gcd_out, mp_int *a_in, mp_int *b_in)
{
size_t nw = size_t_max(1, size_t_max(a_in->nw, b_in->nw));
@@ -1641,99 +1727,126 @@ static void mp_bezout_into(mp_int *a_coeff_out, mp_int *b_coeff_out,
}
/*
* Now we expect to have reduced the two numbers to 0 and 1,
* Now we expect to have reduced the two numbers to 0 and d,
* although we don't know which way round. (But we avoid checking
* this by assertion; sometimes we'll need to do this computation
* without giving away that we already know the inputs were bogus.
* So we'd prefer to just press on and return nonsense.)
*/
/*
* So their Bezout coefficients at this point are simply
* themselves.
*/
mp_copy_into(ac, a);
mp_copy_into(bc, b);
/*
* We'll maintain the invariant as we unwind that ac * a - bc * b
* is either +1 or -1, and we'll remember which. (We _could_ keep
* it at +1 the whole time, but it would cost more work every time
* round the loop, so it's cheaper to fix that up once at the
* end.)
*
* Initially, the result is +1 if a was the nonzero value after
* reduction, and -1 if b was.
*/
unsigned minus_one = b->w[0];
for (size_t step = steps; step-- > 0 ;) {
if (gcd_out) {
/*
* Recover the data from the step we're unwinding.
* At this point we can return the actual gcd. Since one of
* a,b is it and the other is zero, the easiest way to get it
* is to add them together.
*/
unsigned both_odd = mp_get_bit(record, step*2);
unsigned swap = mp_get_bit(record, step*2+1);
/*
* Unwind the division: if our coefficient of a is odd, we
* adjust the coefficients by +b and +a respectively.
*/
unsigned adjust = ac->w[0] & 1;
mp_cond_add_into(ac, ac, b, adjust);
mp_cond_add_into(bc, bc, a, adjust);
/*
* Now ac is definitely even, so we divide it by two.
*/
mp_rshift_fixed_into(ac, ac, 1);
/*
* Now unwind the subtraction, if there was one, by adding
* ac to bc.
*/
mp_cond_add_into(bc, bc, ac, both_odd);
/*
* Undo the transformation of the input numbers, by
* multiplying a by 2 and then adding b to a (the latter
* only if both_odd).
*/
mp_lshift_fixed_into(a, a, 1);
mp_cond_add_into(a, a, b, both_odd);
/*
* Finally, undo the swap. If we do swap, this also
* reverses the sign of the current result ac*a+bc*b.
*/
mp_cond_swap(a, b, swap);
mp_cond_swap(ac, bc, swap);
minus_one ^= swap;
mp_add_into(gcd_out, a, b);
}
/*
* Now we expect to have recovered the input a,b.
* If the caller _only_ wanted the gcd, and neither Bezout
* coefficient is even required, we can skip the entire unwind
* stage.
*/
assert(mp_cmp_eq(a, a_in) & mp_cmp_eq(b, b_in));
if (a_coeff_out || b_coeff_out) {
/*
* But we might find that our current result is -1 instead of +1,
* that is, we have A',B' such that A'a - B'b = -1.
*
* In that situation, we set A = b-A' and B = a-B', giving us
* Aa-Bb = ab - A'a - ab + B'b = +1.
*/
mp_sub_into(tmp, b, ac);
mp_select_into(ac, ac, tmp, minus_one);
mp_sub_into(tmp, a, bc);
mp_select_into(bc, bc, tmp, minus_one);
/*
* The Bezout coefficients of a,b at this point are simply 0
* for whichever of a,b is zero, and 1 for whichever is
* nonzero. The nonzero number equals gcd(a,b), which by
* assumption is odd, so we can do this by just taking the low
* bit of each one.
*/
ac->w[0] = mp_get_bit(a, 0);
bc->w[0] = mp_get_bit(b, 0);
/*
* Now we really are done. Return the outputs.
*/
if (a_coeff_out)
mp_copy_into(a_coeff_out, ac);
if (b_coeff_out)
mp_copy_into(b_coeff_out, bc);
/*
* Overwrite a,b themselves with those same numbers. This has
* the effect of dividing both of them by d, which will
* arrange that during the unwind stage we generate the
* minimal coefficients instead of a larger pair.
*/
mp_copy_into(a, ac);
mp_copy_into(b, bc);
/*
* We'll maintain the invariant as we unwind that ac * a - bc
* * b is either +d or -d (or rather, +1/-1 after scaling by
* d), and we'll remember which. (We _could_ keep it at +d the
* whole time, but it would cost more work every time round
* the loop, so it's cheaper to fix that up once at the end.)
*
* Initially, the result is +d if a was the nonzero value after
* reduction, and -d if b was.
*/
unsigned minus_d = b->w[0];
for (size_t step = steps; step-- > 0 ;) {
/*
* Recover the data from the step we're unwinding.
*/
unsigned both_odd = mp_get_bit(record, step*2);
unsigned swap = mp_get_bit(record, step*2+1);
/*
* Unwind the division: if our coefficient of a is odd, we
* adjust the coefficients by +b and +a respectively.
*/
unsigned adjust = ac->w[0] & 1;
mp_cond_add_into(ac, ac, b, adjust);
mp_cond_add_into(bc, bc, a, adjust);
/*
* Now ac is definitely even, so we divide it by two.
*/
mp_rshift_fixed_into(ac, ac, 1);
/*
* Now unwind the subtraction, if there was one, by adding
* ac to bc.
*/
mp_cond_add_into(bc, bc, ac, both_odd);
/*
* Undo the transformation of the input numbers, by
* multiplying a by 2 and then adding b to a (the latter
* only if both_odd).
*/
mp_lshift_fixed_into(a, a, 1);
mp_cond_add_into(a, a, b, both_odd);
/*
* Finally, undo the swap. If we do swap, this also
* reverses the sign of the current result ac*a+bc*b.
*/
mp_cond_swap(a, b, swap);
mp_cond_swap(ac, bc, swap);
minus_d ^= swap;
}
/*
* Now we expect to have recovered the input a,b (or rather,
* the versions of them divided by d). But we might find that
* our current result is -d instead of +d, that is, we have
* A',B' such that A'a - B'b = -d.
*
* In that situation, we set A = b-A' and B = a-B', giving us
* Aa-Bb = ab - A'a - ab + B'b = +1.
*/
mp_sub_into(tmp, b, ac);
mp_select_into(ac, ac, tmp, minus_d);
mp_sub_into(tmp, a, bc);
mp_select_into(bc, bc, tmp, minus_d);
/*
* Now we really are done. Return the outputs.
*/
if (a_coeff_out)
mp_copy_into(a_coeff_out, ac);
if (b_coeff_out)
mp_copy_into(b_coeff_out, bc);
}
mp_free(a);
mp_free(b);
@@ -1746,10 +1859,65 @@ static void mp_bezout_into(mp_int *a_coeff_out, mp_int *b_coeff_out,
mp_int *mp_invert(mp_int *x, mp_int *m)
{
mp_int *result = mp_make_sized(m->nw);
mp_bezout_into(result, NULL, x, m);
mp_bezout_into(result, NULL, NULL, x, m);
return result;
}
void mp_gcd_into(mp_int *a, mp_int *b, mp_int *gcd, mp_int *A, mp_int *B)
{
/*
* Identify shared factors of 2. To do this we OR the two numbers
* to get something whose lowest set bit is in the right place,
* remove all higher bits by ANDing it with its own negation, and
* use mp_get_nbits to find the location of the single remaining
* set bit.
*/
mp_int *tmp = mp_make_sized(size_t_max(a->nw, b->nw));
for (size_t i = 0; i < tmp->nw; i++)
tmp->w[i] = mp_word(a, i) | mp_word(b, i);
BignumCarry carry = 1;
for (size_t i = 0; i < tmp->nw; i++) {
BignumInt negw;
BignumADC(negw, carry, 0, ~tmp->w[i], carry);
tmp->w[i] &= negw;
}
size_t shift = mp_get_nbits(tmp) - 1;
mp_free(tmp);
/*
* Make copies of a,b with those shared factors of 2 divided off,
* so that at least one is odd (which is the precondition for
* mp_bezout_into). Compute the gcd of those.
*/
mp_int *as = mp_rshift_safe(a, shift);
mp_int *bs = mp_rshift_safe(b, shift);
mp_bezout_into(A, B, gcd, as, bs);
mp_free(as);
mp_free(bs);
/*
* And finally shift the gcd back up (unless the caller didn't
* even ask for it), to put the shared factors of 2 back in.
*/
if (gcd)
mp_lshift_safe_in_place(gcd, shift);
}
mp_int *mp_gcd(mp_int *a, mp_int *b)
{
mp_int *gcd = mp_make_sized(size_t_min(a->nw, b->nw));
mp_gcd_into(a, b, gcd, NULL, NULL);
return gcd;
}
unsigned mp_coprime(mp_int *a, mp_int *b)
{
mp_int *gcd = mp_gcd(a, b);
unsigned toret = mp_eq_integer(gcd, 1);
mp_free(gcd);
return toret;
}
static uint32_t recip_approx_32(uint32_t x)
{
/*
@@ -1874,7 +2042,7 @@ void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q_out, mp_int *r_out)
*/
size_t shift_up = 0;
for (size_t i = BIGNUM_INT_BITS_BITS; i-- > 0;) {
size_t sl = 1 << i; /* left shift count */
size_t sl = (size_t)1 << i; /* left shift count */
size_t sr = 64 - sl; /* complementary right-shift count */
/* Should we shift up? */
@@ -1911,7 +2079,7 @@ void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q_out, mp_int *r_out)
* instructions, e.g. by splitting up into cases.
*/
for (size_t i = BIGNUM_INT_BITS_BITS; i-- > 0;) {
size_t sl = 1 << i; /* left shift count */
size_t sl = (size_t)1 << i; /* left shift count */
size_t sr = 64 - sl; /* complementary right-shift count */
/* Should we shift up? */
@@ -2091,6 +2259,82 @@ mp_int *mp_mod(mp_int *n, mp_int *d)
return r;
}
mp_int *mp_nthroot(mp_int *y, unsigned n, mp_int *remainder_out)
{
/*
* Allocate scratch space.
*/
mp_int **alloc, **powers, **newpowers, *scratch;
size_t nalloc = 2*(n+1)+1;
alloc = snewn(nalloc, mp_int *);
for (size_t i = 0; i < nalloc; i++)
alloc[i] = mp_make_sized(y->nw + 1);
powers = alloc;
newpowers = alloc + (n+1);
scratch = alloc[2*n+2];
/*
* We're computing the rounded-down nth root of y, i.e. the
* maximal x such that x^n <= y. We try to add 2^i to it for each
* possible value of i, starting from the largest one that might
* fit (i.e. such that 2^{n*i} fits in the size of y) downwards to
* i=0.
*
* We track all the smaller powers of x in the array 'powers'. In
* each iteration, if we update x, we update all of those values
* to match.
*/
mp_copy_integer_into(powers[0], 1);
for (size_t s = mp_max_bits(y) / n + 1; s-- > 0 ;) {
/*
* Let b = 2^s. We need to compute the powers (x+b)^i for each
* i, starting from our recorded values of x^i.
*/
for (size_t i = 0; i < n+1; i++) {
/*
* (x+b)^i = x^i
* + (i choose 1) x^{i-1} b
* + (i choose 2) x^{i-2} b^2
* + ...
* + b^i
*/
uint16_t binom = 1; /* coefficient of b^i */
mp_copy_into(newpowers[i], powers[i]);
for (size_t j = 0; j < i; j++) {
/* newpowers[i] += binom * powers[j] * 2^{(i-j)*s} */
mp_mul_integer_into(scratch, powers[j], binom);
mp_lshift_fixed_into(scratch, scratch, (i-j) * s);
mp_add_into(newpowers[i], newpowers[i], scratch);
uint32_t binom_mul = binom;
binom_mul *= (i-j);
binom_mul /= (j+1);
assert(binom_mul < 0x10000);
binom = binom_mul;
}
}
/*
* Now, is the new value of x^n still <= y? If so, update.
*/
unsigned newbit = mp_cmp_hs(y, newpowers[n]);
for (size_t i = 0; i < n+1; i++)
mp_select_into(powers[i], powers[i], newpowers[i], newbit);
}
if (remainder_out)
mp_sub_into(remainder_out, y, powers[n]);
mp_int *root = mp_new(mp_max_bits(y) / n);
mp_copy_into(root, powers[1]);
for (size_t i = 0; i < nalloc; i++)
mp_free(alloc[i]);
sfree(alloc);
return root;
}
mp_int *mp_modmul(mp_int *x, mp_int *y, mp_int *modulus)
{
mp_int *product = mp_mul(x, y);
@@ -2373,10 +2617,8 @@ mp_int *mp_random_bits_fn(size_t bits, random_read_fn_t random_read)
return toret;
}
mp_int *mp_random_in_range_fn(mp_int *lo, mp_int *hi, random_read_fn_t rf)
mp_int *mp_random_upto_fn(mp_int *limit, random_read_fn_t rf)
{
mp_int *n_outcomes = mp_sub(hi, lo);
/*
* It would be nice to generate our random numbers in such a way
* as to make every possible outcome literally equiprobable. But
@@ -2386,10 +2628,19 @@ mp_int *mp_random_in_range_fn(mp_int *lo, mp_int *hi, random_read_fn_t rf)
* is acceptable on the grounds that you'd have to examine so many
* outputs to even detect it.
*/
mp_int *unreduced = mp_random_bits_fn(mp_max_bits(n_outcomes) + 128, rf);
mp_int *reduced = mp_mod(unreduced, n_outcomes);
mp_add_into(reduced, reduced, lo);
mp_int *unreduced = mp_random_bits_fn(mp_max_bits(limit) + 128, rf);
mp_int *reduced = mp_mod(unreduced, limit);
mp_free(unreduced);
mp_free(n_outcomes);
return reduced;
}
mp_int *mp_random_in_range_fn(mp_int *lo, mp_int *hi, random_read_fn_t rf)
{
mp_int *n_outcomes = mp_sub(hi, lo);
mp_int *addend = mp_random_upto_fn(n_outcomes, rf);
mp_int *result = mp_make_sized(hi->nw);
mp_add_into(result, addend, lo);
mp_free(addend);
mp_free(n_outcomes);
return result;
}
@@ -176,9 +176,10 @@ mp_int *mp_max(mp_int *x, mp_int *y);
void mp_dump(FILE *fp, const char *prefix, mp_int *x, const char *suffix);
/*
* Overwrite one mp_int with another.
* Overwrite one mp_int with another, or with a plain integer.
*/
void mp_copy_into(mp_int *dest, mp_int *src);
void mp_copy_integer_into(mp_int *dest, uintmax_t n);
/*
* Conditional selection. Overwrites dest with either src0 or src1,
@@ -256,6 +257,17 @@ void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q, mp_int *r);
mp_int *mp_div(mp_int *n, mp_int *d);
mp_int *mp_mod(mp_int *x, mp_int *modulus);
/*
* Integer nth root. mp_nthroot returns the largest integer x such
* that x^n <= y, and if 'remainder' is non-NULL then it fills it with
* the residue (y - x^n).
*
* Currently, n has to be small enough that the largest binomial
* coefficient (n choose k) fits in 16 bits, which works out to at
* most 18.
*/
mp_int *mp_nthroot(mp_int *y, unsigned n, mp_int *remainder);
/*
* Trivially easy special case of mp_mod: reduce a number mod a power
* of two.
@@ -270,6 +282,25 @@ void mp_reduce_mod_2to(mp_int *x, size_t p);
mp_int *mp_invert_mod_2to(mp_int *x, size_t p);
mp_int *mp_invert(mp_int *x, mp_int *modulus);
/*
* Greatest common divisor.
*
* mp_gcd_into also returns a pair of Bezout coefficients, namely A,B
* such that a*A - b*B = gcd. (The minus sign is so that both returned
* coefficients can be positive.)
*
* You can pass any of mp_gcd_into's output pointers as NULL if you
* don't need that output value.
*
* mp_gcd is a wrapper with a less cumbersome API, for the case where
* the only output value you need is the gcd itself. mp_coprime is
* even easier, if all you care about is whether or not that gcd is 1.
*/
mp_int *mp_gcd(mp_int *a, mp_int *b);
void mp_gcd_into(mp_int *a, mp_int *b,
mp_int *gcd_out, mp_int *A_out, mp_int *B_out);
unsigned mp_coprime(mp_int *a, mp_int *b);
/*
* System for taking square roots modulo an odd prime.
*
@@ -360,10 +391,17 @@ mp_int *mp_modadd(mp_int *x, mp_int *y, mp_int *modulus);
mp_int *mp_modsub(mp_int *x, mp_int *y, mp_int *modulus);
/*
* Shift an mp_int right by a given number of bits. The shift count is
* Shift an mp_int by a given number of bits. The shift count is
* considered to be secret data, and as a result, the algorithm takes
* O(n log n) time instead of the obvious O(n).
*
* There's no mp_lshift_safe, because the size of mp_int to allocate
* would not be able to avoid depending on the shift count. So if you
* need to behave independently of the size of a left shift, you have
* to know a bound on the space you'll need by some other means.
*/
void mp_lshift_safe_into(mp_int *r, mp_int *x, size_t shift);
void mp_rshift_safe_into(mp_int *r, mp_int *x, size_t shift);
mp_int *mp_rshift_safe(mp_int *x, size_t shift);
/*
@@ -376,6 +414,7 @@ mp_int *mp_rshift_safe(mp_int *x, size_t shift);
*/
void mp_lshift_fixed_into(mp_int *r, mp_int *a, size_t shift);
void mp_rshift_fixed_into(mp_int *r, mp_int *x, size_t shift);
mp_int *mp_lshift_fixed(mp_int *x, size_t shift);
mp_int *mp_rshift_fixed(mp_int *x, size_t shift);
/*
@@ -391,13 +430,16 @@ mp_int *mp_rshift_fixed(mp_int *x, size_t shift);
* then _they_ have link-time dependencies on both modules.)
*
* mp_random_bits[_fn] returns an integer 0 <= n < 2^bits.
* mp_random_upto[_fn](limit) returns an integer 0 <= n < limit.
* mp_random_in_range[_fn](lo,hi) returns an integer lo <= n < hi.
*/
typedef void (*random_read_fn_t)(void *, size_t);
mp_int *mp_random_bits_fn(size_t bits, random_read_fn_t randfn);
mp_int *mp_random_upto_fn(mp_int *limit, random_read_fn_t randfn);
mp_int *mp_random_in_range_fn(
mp_int *lo_inclusive, mp_int *hi_exclusive, random_read_fn_t randfn);
#define mp_random_bits(bits) mp_random_bits_fn(bits, random_read)
#define mp_random_upto(limit) mp_random_upto_fn(limit, random_read)
#define mp_random_in_range(lo, hi) mp_random_in_range_fn(lo, hi, random_read)
#endif /* PUTTY_MPINT_H */
@@ -1,317 +1,324 @@
/*
* mpint_i.h: definitions used internally by the bignum code, and
* also a few other vaguely-bignum-like places.
*/
/* ----------------------------------------------------------------------
* The assorted conditional definitions of BignumInt and multiply
* macros used throughout the bignum code to treat numbers as arrays
* of the most conveniently sized word for the target machine.
* Exported so that other code (e.g. poly1305) can use it too.
*
* This code must export, in whatever ifdef branch it ends up in:
*
* - two types: 'BignumInt' and 'BignumCarry'. BignumInt is an
* unsigned integer type which will be used as the base word size
* for all bignum operations. BignumCarry is an unsigned integer
* type used to hold the carry flag taken as input and output by
* the BignumADC macro (see below).
*
* - five constant macros:
* + BIGNUM_INT_BITS, the number of bits in BignumInt,
* + BIGNUM_INT_BYTES, the number of bytes that works out to
* + BIGNUM_TOP_BIT, the BignumInt value consisting of only the top bit
* + BIGNUM_INT_MASK, the BignumInt value with all bits set
* + BIGNUM_INT_BITS_BITS, log to the base 2 of BIGNUM_INT_BITS.
*
* - four statement macros: BignumADC, BignumMUL, BignumMULADD,
* BignumMULADD2. These do various kinds of multi-word arithmetic,
* and all produce two output values.
* * BignumADC(ret,retc,a,b,c) takes input BignumInt values a,b
* and a BignumCarry c, and outputs a BignumInt ret = a+b+c and
* a BignumCarry retc which is the carry off the top of that
* addition.
* * BignumMUL(rh,rl,a,b) returns the two halves of the
* double-width product a*b.
* * BignumMULADD(rh,rl,a,b,addend) returns the two halves of the
* double-width value a*b + addend.
* * BignumMULADD2(rh,rl,a,b,addend1,addend2) returns the two
* halves of the double-width value a*b + addend1 + addend2.
*
* Every branch of the main ifdef below defines the type BignumInt and
* the value BIGNUM_INT_BITS_BITS. The other constant macros are
* filled in by common code further down.
*
* Most branches also define a macro DEFINE_BIGNUMDBLINT containing a
* typedef statement which declares a type _twice_ the length of a
* BignumInt. This causes the common code further down to produce a
* default implementation of the four statement macros in terms of
* that double-width type, and also to defined BignumCarry to be
* BignumInt.
*
* However, if a particular compile target does not have a type twice
* the length of the BignumInt you want to use but it does provide
* some alternative means of doing add-with-carry and double-word
* multiply, then the ifdef branch in question can just define
* BignumCarry and the four statement macros itself, and that's fine
* too.
*/
/* You can lower the BignumInt size by defining BIGNUM_OVERRIDE on the
* command line to be your chosen max value of BIGNUM_INT_BITS_BITS */
#define BB_OK(b) (!defined BIGNUM_OVERRIDE || BIGNUM_OVERRIDE >= b)
#if defined __SIZEOF_INT128__ && BB_OK(6)
/*
* 64-bit BignumInt using gcc/clang style 128-bit BignumDblInt.
*
* gcc and clang both provide a __uint128_t type on 64-bit targets
* (and, when they do, indicate its presence by the above macro),
* using the same 'two machine registers' kind of code generation
* that 32-bit targets use for 64-bit ints.
*/
typedef unsigned long long BignumInt;
#define BIGNUM_INT_BITS_BITS 6
#define DEFINE_BIGNUMDBLINT typedef __uint128_t BignumDblInt
#elif defined _MSC_VER && defined _M_AMD64 && BB_OK(6)
/*
* 64-bit BignumInt, using Visual Studio x86-64 compiler intrinsics.
*
* 64-bit Visual Studio doesn't provide very much in the way of help
* here: there's no int128 type, and also no inline assembler giving
* us direct access to the x86-64 MUL or ADC instructions. However,
* there are compiler intrinsics giving us that access, so we can
* use those - though it turns out we have to be a little careful,
* since they seem to generate wrong code if their pointer-typed
* output parameters alias their inputs. Hence all the internal temp
* variables inside the macros.
*/
#include <intrin.h>
typedef unsigned char BignumCarry; /* the type _addcarry_u64 likes to use */
typedef unsigned __int64 BignumInt;
#define BIGNUM_INT_BITS_BITS 6
#define BignumADC(ret, retc, a, b, c) do \
{ \
BignumInt ADC_tmp; \
(retc) = _addcarry_u64(c, a, b, &ADC_tmp); \
(ret) = ADC_tmp; \
} while (0)
#define BignumMUL(rh, rl, a, b) do \
{ \
BignumInt MULADD_hi; \
(rl) = _umul128(a, b, &MULADD_hi); \
(rh) = MULADD_hi; \
} while (0)
#define BignumMULADD(rh, rl, a, b, addend) do \
{ \
BignumInt MULADD_lo, MULADD_hi; \
MULADD_lo = _umul128(a, b, &MULADD_hi); \
MULADD_hi += _addcarry_u64(0, MULADD_lo, (addend), &(rl)); \
(rh) = MULADD_hi; \
} while (0)
#define BignumMULADD2(rh, rl, a, b, addend1, addend2) do \
{ \
BignumInt MULADD_lo1, MULADD_lo2, MULADD_hi; \
MULADD_lo1 = _umul128(a, b, &MULADD_hi); \
MULADD_hi += _addcarry_u64(0, MULADD_lo1, (addend1), &MULADD_lo2); \
MULADD_hi += _addcarry_u64(0, MULADD_lo2, (addend2), &(rl)); \
(rh) = MULADD_hi; \
} while (0)
#elif (defined __GNUC__ || defined _LLP64 || __STDC__ >= 199901L) && BB_OK(5)
/* 32-bit BignumInt, using C99 unsigned long long as BignumDblInt */
typedef unsigned int BignumInt;
#define BIGNUM_INT_BITS_BITS 5
#define DEFINE_BIGNUMDBLINT typedef unsigned long long BignumDblInt
#elif defined _MSC_VER && BB_OK(5)
/* 32-bit BignumInt, using Visual Studio __int64 as BignumDblInt */
typedef unsigned int BignumInt;
#define BIGNUM_INT_BITS_BITS 5
#define DEFINE_BIGNUMDBLINT typedef unsigned __int64 BignumDblInt
#elif defined _LP64 && BB_OK(5)
/*
* 32-bit BignumInt, using unsigned long itself as BignumDblInt.
*
* Only for platforms where long is 64 bits, of course.
*/
typedef unsigned int BignumInt;
#define BIGNUM_INT_BITS_BITS 5
#define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
#elif BB_OK(4)
/*
* 16-bit BignumInt, using unsigned long as BignumDblInt.
*
* This is the final fallback for real emergencies: C89 guarantees
* unsigned short/long to be at least the required sizes, so this
* should work on any C implementation at all. But it'll be
* noticeably slow, so if you find yourself in this case you
* probably want to move heaven and earth to find an alternative!
*/
typedef unsigned short BignumInt;
#define BIGNUM_INT_BITS_BITS 4
#define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
#else
/* Should only get here if BB_OK(4) evaluated false, i.e. the
* command line defined BIGNUM_OVERRIDE to an absurdly small
* value. */
#error Must define BIGNUM_OVERRIDE to at least 4
#endif
#undef BB_OK
/*
* Common code across all branches of that ifdef: define all the
* easy constant macros in terms of BIGNUM_INT_BITS_BITS.
*/
#define BIGNUM_INT_BITS (1 << BIGNUM_INT_BITS_BITS)
#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
#define BIGNUM_TOP_BIT (((BignumInt)1) << (BIGNUM_INT_BITS-1))
#define BIGNUM_INT_MASK (BIGNUM_TOP_BIT | (BIGNUM_TOP_BIT-1))
/*
* Just occasionally, we might need a GET_nnBIT_xSB_FIRST macro to
* operate on whatever BignumInt is.
*/
#if BIGNUM_INT_BITS_BITS == 4
#define GET_BIGNUMINT_MSB_FIRST GET_16BIT_MSB_FIRST
#define GET_BIGNUMINT_LSB_FIRST GET_16BIT_LSB_FIRST
#define PUT_BIGNUMINT_MSB_FIRST PUT_16BIT_MSB_FIRST
#define PUT_BIGNUMINT_LSB_FIRST PUT_16BIT_LSB_FIRST
#elif BIGNUM_INT_BITS_BITS == 5
#define GET_BIGNUMINT_MSB_FIRST GET_32BIT_MSB_FIRST
#define GET_BIGNUMINT_LSB_FIRST GET_32BIT_LSB_FIRST
#define PUT_BIGNUMINT_MSB_FIRST PUT_32BIT_MSB_FIRST
#define PUT_BIGNUMINT_LSB_FIRST PUT_32BIT_LSB_FIRST
#elif BIGNUM_INT_BITS_BITS == 6
#define GET_BIGNUMINT_MSB_FIRST GET_64BIT_MSB_FIRST
#define GET_BIGNUMINT_LSB_FIRST GET_64BIT_LSB_FIRST
#define PUT_BIGNUMINT_MSB_FIRST PUT_64BIT_MSB_FIRST
#define PUT_BIGNUMINT_LSB_FIRST PUT_64BIT_LSB_FIRST
#else
#error Ran out of options for GET_BIGNUMINT_xSB_FIRST
#endif
/*
* Common code across _most_ branches of the ifdef: define a set of
* statement macros in terms of the BignumDblInt type provided. In
* this case, we also define BignumCarry to be the same thing as
* BignumInt, for simplicity.
*/
#ifdef DEFINE_BIGNUMDBLINT
typedef BignumInt BignumCarry;
#define BignumADC(ret, retc, a, b, c) do \
{ \
DEFINE_BIGNUMDBLINT; \
BignumDblInt ADC_temp = (BignumInt)(a); \
ADC_temp += (BignumInt)(b); \
ADC_temp += (c); \
(ret) = (BignumInt)ADC_temp; \
(retc) = (BignumCarry)(ADC_temp >> BIGNUM_INT_BITS); \
} while (0)
#define BignumMUL(rh, rl, a, b) do \
{ \
DEFINE_BIGNUMDBLINT; \
BignumDblInt MUL_temp = (BignumInt)(a); \
MUL_temp *= (BignumInt)(b); \
(rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
(rl) = (BignumInt)(MUL_temp); \
} while (0)
#define BignumMULADD(rh, rl, a, b, addend) do \
{ \
DEFINE_BIGNUMDBLINT; \
BignumDblInt MUL_temp = (BignumInt)(a); \
MUL_temp *= (BignumInt)(b); \
MUL_temp += (BignumInt)(addend); \
(rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
(rl) = (BignumInt)(MUL_temp); \
} while (0)
#define BignumMULADD2(rh, rl, a, b, addend1, addend2) do \
{ \
DEFINE_BIGNUMDBLINT; \
BignumDblInt MUL_temp = (BignumInt)(a); \
MUL_temp *= (BignumInt)(b); \
MUL_temp += (BignumInt)(addend1); \
MUL_temp += (BignumInt)(addend2); \
(rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
(rl) = (BignumInt)(MUL_temp); \
} while (0)
#endif /* DEFINE_BIGNUMDBLINT */
/* ----------------------------------------------------------------------
* Data structures used inside bignum.c.
*/
struct mp_int {
size_t nw;
BignumInt *w;
};
struct MontyContext {
/*
* The actual modulus.
*/
mp_int *m;
/*
* Montgomery multiplication works by selecting a value r > m,
* coprime to m, which is really easy to divide by. In binary
* arithmetic, that means making it a power of 2; in fact we make
* it a whole number of BignumInt.
*
* We don't store r directly as an mp_int (there's no need). But
* its value is 2^rbits; we also store rw = rbits/BIGNUM_INT_BITS
* (the corresponding word offset within an mp_int).
*
* pw is the number of words needed to store an mp_int you're
* doing reduction on: it has to be big enough to hold the sum of
* an input value up to m^2 plus an extra addend up to m*r.
*/
size_t rbits, rw, pw;
/*
* The key step in Montgomery reduction requires the inverse of -m
* mod r.
*/
mp_int *minus_minv_mod_r;
/*
* r^1, r^2 and r^3 mod m, which are used for various purposes.
*
* (Annoyingly, this is one of the rare cases where it would have
* been nicer to have a Pascal-style 1-indexed array. I couldn't
* _quite_ bring myself to put a gratuitous zero element in here.
* So you just have to live with getting r^k by taking the [k-1]th
* element of this array.)
*/
mp_int *powers_of_r_mod_m[3];
/*
* Persistent scratch space from which monty_* functions can
* allocate storage for intermediate values.
*/
mp_int *scratch;
};
/*
* mpint_i.h: definitions used internally by the bignum code, and
* also a few other vaguely-bignum-like places.
*/
/* ----------------------------------------------------------------------
* The assorted conditional definitions of BignumInt and multiply
* macros used throughout the bignum code to treat numbers as arrays
* of the most conveniently sized word for the target machine.
* Exported so that other code (e.g. poly1305) can use it too.
*
* This code must export, in whatever ifdef branch it ends up in:
*
* - two types: 'BignumInt' and 'BignumCarry'. BignumInt is an
* unsigned integer type which will be used as the base word size
* for all bignum operations. BignumCarry is an unsigned integer
* type used to hold the carry flag taken as input and output by
* the BignumADC macro (see below).
*
* - five constant macros:
* + BIGNUM_INT_BITS, the number of bits in BignumInt,
* + BIGNUM_INT_BYTES, the number of bytes that works out to
* + BIGNUM_TOP_BIT, the BignumInt value consisting of only the top bit
* + BIGNUM_INT_MASK, the BignumInt value with all bits set
* + BIGNUM_INT_BITS_BITS, log to the base 2 of BIGNUM_INT_BITS.
*
* - four statement macros: BignumADC, BignumMUL, BignumMULADD,
* BignumMULADD2. These do various kinds of multi-word arithmetic,
* and all produce two output values.
* * BignumADC(ret,retc,a,b,c) takes input BignumInt values a,b
* and a BignumCarry c, and outputs a BignumInt ret = a+b+c and
* a BignumCarry retc which is the carry off the top of that
* addition.
* * BignumMUL(rh,rl,a,b) returns the two halves of the
* double-width product a*b.
* * BignumMULADD(rh,rl,a,b,addend) returns the two halves of the
* double-width value a*b + addend.
* * BignumMULADD2(rh,rl,a,b,addend1,addend2) returns the two
* halves of the double-width value a*b + addend1 + addend2.
*
* Every branch of the main ifdef below defines the type BignumInt and
* the value BIGNUM_INT_BITS_BITS. The other constant macros are
* filled in by common code further down.
*
* Most branches also define a macro DEFINE_BIGNUMDBLINT containing a
* typedef statement which declares a type _twice_ the length of a
* BignumInt. This causes the common code further down to produce a
* default implementation of the four statement macros in terms of
* that double-width type, and also to defined BignumCarry to be
* BignumInt.
*
* However, if a particular compile target does not have a type twice
* the length of the BignumInt you want to use but it does provide
* some alternative means of doing add-with-carry and double-word
* multiply, then the ifdef branch in question can just define
* BignumCarry and the four statement macros itself, and that's fine
* too.
*/
/* You can lower the BignumInt size by defining BIGNUM_OVERRIDE on the
* command line to be your chosen max value of BIGNUM_INT_BITS_BITS */
#if defined BIGNUM_OVERRIDE
#define BB_OK(b) ((b) <= BIGNUM_OVERRIDE)
#else
#define BB_OK(b) (1)
#endif
#if defined __SIZEOF_INT128__ && BB_OK(6)
/*
* 64-bit BignumInt using gcc/clang style 128-bit BignumDblInt.
*
* gcc and clang both provide a __uint128_t type on 64-bit targets
* (and, when they do, indicate its presence by the above macro),
* using the same 'two machine registers' kind of code generation
* that 32-bit targets use for 64-bit ints.
*/
typedef unsigned long long BignumInt;
#define BIGNUM_INT_BITS_BITS 6
#define DEFINE_BIGNUMDBLINT typedef __uint128_t BignumDblInt
#elif defined _MSC_VER && defined _M_AMD64 && BB_OK(6)
/*
* 64-bit BignumInt, using Visual Studio x86-64 compiler intrinsics.
*
* 64-bit Visual Studio doesn't provide very much in the way of help
* here: there's no int128 type, and also no inline assembler giving
* us direct access to the x86-64 MUL or ADC instructions. However,
* there are compiler intrinsics giving us that access, so we can
* use those - though it turns out we have to be a little careful,
* since they seem to generate wrong code if their pointer-typed
* output parameters alias their inputs. Hence all the internal temp
* variables inside the macros.
*/
#include <intrin.h>
typedef unsigned char BignumCarry; /* the type _addcarry_u64 likes to use */
typedef unsigned __int64 BignumInt;
#define BIGNUM_INT_BITS_BITS 6
#define BignumADC(ret, retc, a, b, c) do \
{ \
BignumInt ADC_tmp; \
(retc) = _addcarry_u64(c, a, b, &ADC_tmp); \
(ret) = ADC_tmp; \
} while (0)
#define BignumMUL(rh, rl, a, b) do \
{ \
BignumInt MULADD_hi; \
(rl) = _umul128(a, b, &MULADD_hi); \
(rh) = MULADD_hi; \
} while (0)
#define BignumMULADD(rh, rl, a, b, addend) do \
{ \
BignumInt MULADD_lo, MULADD_hi; \
MULADD_lo = _umul128(a, b, &MULADD_hi); \
MULADD_hi += _addcarry_u64(0, MULADD_lo, (addend), &(rl)); \
(rh) = MULADD_hi; \
} while (0)
#define BignumMULADD2(rh, rl, a, b, addend1, addend2) do \
{ \
BignumInt MULADD_lo1, MULADD_lo2, MULADD_hi; \
MULADD_lo1 = _umul128(a, b, &MULADD_hi); \
MULADD_hi += _addcarry_u64(0, MULADD_lo1, (addend1), &MULADD_lo2); \
MULADD_hi += _addcarry_u64(0, MULADD_lo2, (addend2), &(rl)); \
(rh) = MULADD_hi; \
} while (0)
#elif (defined __GNUC__ || defined _LLP64 || __STDC__ >= 199901L) && BB_OK(5)
/* 32-bit BignumInt, using C99 unsigned long long as BignumDblInt */
typedef unsigned int BignumInt;
#define BIGNUM_INT_BITS_BITS 5
#define DEFINE_BIGNUMDBLINT typedef unsigned long long BignumDblInt
#elif defined _MSC_VER && BB_OK(5)
/* 32-bit BignumInt, using Visual Studio __int64 as BignumDblInt */
typedef unsigned int BignumInt;
#define BIGNUM_INT_BITS_BITS 5
#define DEFINE_BIGNUMDBLINT typedef unsigned __int64 BignumDblInt
#elif defined _LP64 && BB_OK(5)
/*
* 32-bit BignumInt, using unsigned long itself as BignumDblInt.
*
* Only for platforms where long is 64 bits, of course.
*/
typedef unsigned int BignumInt;
#define BIGNUM_INT_BITS_BITS 5
#define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
#elif BB_OK(4)
/*
* 16-bit BignumInt, using unsigned long as BignumDblInt.
*
* This is the final fallback for real emergencies: C89 guarantees
* unsigned short/long to be at least the required sizes, so this
* should work on any C implementation at all. But it'll be
* noticeably slow, so if you find yourself in this case you
* probably want to move heaven and earth to find an alternative!
*/
typedef unsigned short BignumInt;
#define BIGNUM_INT_BITS_BITS 4
#define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
#else
/* Should only get here if BB_OK(4) evaluated false, i.e. the
* command line defined BIGNUM_OVERRIDE to an absurdly small
* value. */
#error Must define BIGNUM_OVERRIDE to at least 4
#endif
#undef BB_OK
/*
* Common code across all branches of that ifdef: define all the
* easy constant macros in terms of BIGNUM_INT_BITS_BITS.
*/
#define BIGNUM_INT_BITS (1 << BIGNUM_INT_BITS_BITS)
#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
#define BIGNUM_TOP_BIT (((BignumInt)1) << (BIGNUM_INT_BITS-1))
#define BIGNUM_INT_MASK (BIGNUM_TOP_BIT | (BIGNUM_TOP_BIT-1))
/*
* Just occasionally, we might need a GET_nnBIT_xSB_FIRST macro to
* operate on whatever BignumInt is.
*/
#if BIGNUM_INT_BITS_BITS == 4
#define GET_BIGNUMINT_MSB_FIRST GET_16BIT_MSB_FIRST
#define GET_BIGNUMINT_LSB_FIRST GET_16BIT_LSB_FIRST
#define PUT_BIGNUMINT_MSB_FIRST PUT_16BIT_MSB_FIRST
#define PUT_BIGNUMINT_LSB_FIRST PUT_16BIT_LSB_FIRST
#elif BIGNUM_INT_BITS_BITS == 5
#define GET_BIGNUMINT_MSB_FIRST GET_32BIT_MSB_FIRST
#define GET_BIGNUMINT_LSB_FIRST GET_32BIT_LSB_FIRST
#define PUT_BIGNUMINT_MSB_FIRST PUT_32BIT_MSB_FIRST
#define PUT_BIGNUMINT_LSB_FIRST PUT_32BIT_LSB_FIRST
#elif BIGNUM_INT_BITS_BITS == 6
#define GET_BIGNUMINT_MSB_FIRST GET_64BIT_MSB_FIRST
#define GET_BIGNUMINT_LSB_FIRST GET_64BIT_LSB_FIRST
#define PUT_BIGNUMINT_MSB_FIRST PUT_64BIT_MSB_FIRST
#define PUT_BIGNUMINT_LSB_FIRST PUT_64BIT_LSB_FIRST
#else
#error Ran out of options for GET_BIGNUMINT_xSB_FIRST
#endif
/*
* Common code across _most_ branches of the ifdef: define a set of
* statement macros in terms of the BignumDblInt type provided. In
* this case, we also define BignumCarry to be the same thing as
* BignumInt, for simplicity.
*/
#ifdef DEFINE_BIGNUMDBLINT
typedef BignumInt BignumCarry;
#define BignumADC(ret, retc, a, b, c) do \
{ \
DEFINE_BIGNUMDBLINT; \
BignumDblInt ADC_temp = (BignumInt)(a); \
ADC_temp += (BignumInt)(b); \
ADC_temp += (c); \
(ret) = (BignumInt)ADC_temp; \
(retc) = (BignumCarry)(ADC_temp >> BIGNUM_INT_BITS); \
} while (0)
#define BignumMUL(rh, rl, a, b) do \
{ \
DEFINE_BIGNUMDBLINT; \
BignumDblInt MUL_temp = (BignumInt)(a); \
MUL_temp *= (BignumInt)(b); \
(rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
(rl) = (BignumInt)(MUL_temp); \
} while (0)
#define BignumMULADD(rh, rl, a, b, addend) do \
{ \
DEFINE_BIGNUMDBLINT; \
BignumDblInt MUL_temp = (BignumInt)(a); \
MUL_temp *= (BignumInt)(b); \
MUL_temp += (BignumInt)(addend); \
(rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
(rl) = (BignumInt)(MUL_temp); \
} while (0)
#define BignumMULADD2(rh, rl, a, b, addend1, addend2) do \
{ \
DEFINE_BIGNUMDBLINT; \
BignumDblInt MUL_temp = (BignumInt)(a); \
MUL_temp *= (BignumInt)(b); \
MUL_temp += (BignumInt)(addend1); \
MUL_temp += (BignumInt)(addend2); \
(rh) = (BignumInt)(MUL_temp >> BIGNUM_INT_BITS); \
(rl) = (BignumInt)(MUL_temp); \
} while (0)
#endif /* DEFINE_BIGNUMDBLINT */
/* ----------------------------------------------------------------------
* Data structures used inside bignum.c.
*/
struct mp_int {
size_t nw;
BignumInt *w;
};
struct MontyContext {
/*
* The actual modulus.
*/
mp_int *m;
/*
* Montgomery multiplication works by selecting a value r > m,
* coprime to m, which is really easy to divide by. In binary
* arithmetic, that means making it a power of 2; in fact we make
* it a whole number of BignumInt.
*
* We don't store r directly as an mp_int (there's no need). But
* its value is 2^rbits; we also store rw = rbits/BIGNUM_INT_BITS
* (the corresponding word offset within an mp_int).
*
* pw is the number of words needed to store an mp_int you're
* doing reduction on: it has to be big enough to hold the sum of
* an input value up to m^2 plus an extra addend up to m*r.
*/
size_t rbits, rw, pw;
/*
* The key step in Montgomery reduction requires the inverse of -m
* mod r.
*/
mp_int *minus_minv_mod_r;
/*
* r^1, r^2 and r^3 mod m, which are used for various purposes.
*
* (Annoyingly, this is one of the rare cases where it would have
* been nicer to have a Pascal-style 1-indexed array. I couldn't
* _quite_ bring myself to put a gratuitous zero element in here.
* So you just have to live with getting r^k by taking the [k-1]th
* element of this array.)
*/
mp_int *powers_of_r_mod_m[3];
/*
* Persistent scratch space from which monty_* functions can
* allocate storage for intermediate values.
*/
mp_int *scratch;
};
/* Functions shared between mpint.c and mpunsafe.c */
mp_int *mp_make_sized(size_t nw);
+59
View File
@@ -0,0 +1,59 @@
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include "defs.h"
#include "misc.h"
#include "puttymem.h"
#include "mpint.h"
#include "mpint_i.h"
/*
* This global symbol is also defined in ssh2kex-client.c, to ensure
* that these unsafe non-constant-time mp_int functions can't end up
* accidentally linked in to any PuTTY tool that actually makes an SSH
* client connection.
*
* (Only _client_ connections, however. Uppity, being a test server
* only, is exempt.)
*/
#ifndef MOD_PERSO
const int deliberate_symbol_clash = 12345;
#endif
static size_t mp_unsafe_words_needed(mp_int *x)
{
size_t words = x->nw;
while (words > 1 && !x->w[words-1])
words--;
return words;
}
mp_int *mp_unsafe_shrink(mp_int *x)
{
x->nw = mp_unsafe_words_needed(x);
/* This potentially leaves some allocated words between the new
* and old values of x->nw, which won't be wiped by mp_free now
* that x->nw doesn't mention that they exist. But we've just
* checked they're all zero, so we don't need to wipe them now
* either. */
return x;
}
mp_int *mp_unsafe_copy(mp_int *x)
{
mp_int *copy = mp_make_sized(mp_unsafe_words_needed(x));
mp_copy_into(copy, x);
return copy;
}
uint32_t mp_unsafe_mod_integer(mp_int *x, uint32_t modulus)
{
uint64_t accumulator = 0;
for (size_t i = mp_max_bytes(x); i-- > 0 ;) {
accumulator = 0x100 * accumulator + mp_get_byte(x, i);
accumulator %= modulus;
}
return accumulator;
}
+46
View File
@@ -0,0 +1,46 @@
/*
* mpunsafe.h: functions that deal with mp_ints in ways that are *not*
* expected to be constant-time. Used during key generation, in which
* constant run time is a lost cause anyway.
*
* These functions are in a separate header, so that you can easily
* check that you're not calling them in the wrong context. They're
* also defined in a separate source file, which is only linked in to
* the key generation tools. Furthermore, that source file also
* defines a global symbol that intentionally conflicts with one
* defined in the SSH client code, so that any attempt to put these
* functions into the same binary as the live SSH client
* implementation will cause a link-time failure. They should only be
* linked into PuTTYgen and auxiliary test programs.
*
* Also, just in case those precautions aren't enough, all the unsafe
* functions have 'unsafe' in the name.
*/
#ifndef PUTTY_MPINT_UNSAFE_H
#define PUTTY_MPINT_UNSAFE_H
/*
* The most obvious unsafe thing you want to do with an mp_int is to
* get rid of leading zero words in its representation, so that its
* nominal size is as close as possible to its true size, and you
* don't waste any time processing it.
*
* mp_unsafe_shrink performs this operation in place, mutating the
* size field of the mp_int it's given. It returns the same pointer it
* was given.
*
* mp_unsafe_copy leaves the original mp_int alone and makes a new one
* with the minimal size.
*/
mp_int *mp_unsafe_shrink(mp_int *m);
mp_int *mp_unsafe_copy(mp_int *m);
/*
* Compute the residue of x mod m. This is implemented in the most
* obvious way using the C % operator, which won't be constant-time on
* many C implementations.
*/
uint32_t mp_unsafe_mod_integer(mp_int *x, uint32_t m);
#endif /* PUTTY_MPINT_UNSAFE_H */
@@ -1,297 +1,314 @@
/*
* Networking abstraction in PuTTY.
*
* The way this works is: a back end can choose to open any number
* of sockets - including zero, which might be necessary in some.
* It can register a bunch of callbacks (most notably for when
* data is received) for each socket, and it can call the networking
* abstraction to send data without having to worry about blocking.
* The stuff behind the abstraction takes care of selects and
* nonblocking writes and all that sort of painful gubbins.
*/
#ifndef PUTTY_NETWORK_H
#define PUTTY_NETWORK_H
#include "defs.h"
typedef struct SocketVtable SocketVtable;
typedef struct PlugVtable PlugVtable;
struct Socket {
const struct SocketVtable *vt;
};
struct SocketVtable {
Plug *(*plug) (Socket *s, Plug *p);
/* use a different plug (return the old one) */
/* if p is NULL, it doesn't change the plug */
/* but it does return the one it's using */
void (*close) (Socket *s);
size_t (*write) (Socket *s, const void *data, size_t len);
size_t (*write_oob) (Socket *s, const void *data, size_t len);
void (*write_eof) (Socket *s);
void (*set_frozen) (Socket *s, bool is_frozen);
/* ignored by tcp, but vital for ssl */
const char *(*socket_error) (Socket *s);
SocketPeerInfo *(*peer_info) (Socket *s);
};
typedef union { void *p; int i; } accept_ctx_t;
typedef Socket *(*accept_fn_t)(accept_ctx_t ctx, Plug *plug);
struct Plug {
const struct PlugVtable *vt;
};
struct PlugVtable {
void (*log)(Plug *p, int type, SockAddr *addr, int port,
const char *error_msg, int error_code);
/*
* Passes the client progress reports on the process of setting
* up the connection.
*
* - type==0 means we are about to try to connect to address
* `addr' (error_msg and error_code are ignored)
* - type==1 means we have failed to connect to address `addr'
* (error_msg and error_code are supplied). This is not a
* fatal error - we may well have other candidate addresses
* to fall back to. When it _is_ fatal, the closing()
* function will be called.
* - type==2 means that error_msg contains a line of generic
* logging information about setting up the connection. This
* will typically be a wodge of standard-error output from a
* proxy command, so the receiver should probably prefix it to
* indicate this.
*/
void (*closing)
(Plug *p, const char *error_msg, int error_code, bool calling_back);
/* error_msg is NULL iff it is not an error (ie it closed normally) */
/* calling_back != 0 iff there is a Plug function */
/* currently running (would cure the fixme in try_send()) */
void (*receive) (Plug *p, int urgent, const char *data, size_t len);
/*
* - urgent==0. `data' points to `len' bytes of perfectly
* ordinary data.
*
* - urgent==1. `data' points to `len' bytes of data,
* which were read from before an Urgent pointer.
*
* - urgent==2. `data' points to `len' bytes of data,
* the first of which was the one at the Urgent mark.
*/
void (*sent) (Plug *p, size_t bufsize);
/*
* The `sent' function is called when the pending send backlog
* on a socket is cleared or partially cleared. The new backlog
* size is passed in the `bufsize' parameter.
*/
int (*accepting)(Plug *p, accept_fn_t constructor, accept_ctx_t ctx);
/*
* `accepting' is called only on listener-type sockets, and is
* passed a constructor function+context that will create a fresh
* Socket describing the connection. It returns nonzero if it
* doesn't want the connection for some reason, or 0 on success.
*/
};
/* proxy indirection layer */
/* NB, control of 'addr' is passed via new_connection, which takes
* responsibility for freeing it */
Socket *new_connection(SockAddr *addr, const char *hostname,
int port, bool privport,
bool oobinline, bool nodelay, bool keepalive,
Plug *plug, Conf *conf);
Socket *new_listener(const char *srcaddr, int port, Plug *plug,
bool local_host_only, Conf *conf, int addressfamily);
SockAddr *name_lookup(const char *host, int port, char **canonicalname,
Conf *conf, int addressfamily, LogContext *logctx,
const char *lookup_reason_for_logging);
/* platform-dependent callback from new_connection() */
/* (same caveat about addr as new_connection()) */
Socket *platform_new_connection(SockAddr *addr, const char *hostname,
int port, bool privport,
bool oobinline, bool nodelay, bool keepalive,
Plug *plug, Conf *conf);
/* socket functions */
void sk_init(void); /* called once at program startup */
void sk_cleanup(void); /* called just before program exit */
SockAddr *sk_namelookup(const char *host, char **canonicalname, int address_family);
SockAddr *sk_nonamelookup(const char *host);
void sk_getaddr(SockAddr *addr, char *buf, int buflen);
bool sk_addr_needs_port(SockAddr *addr);
bool sk_hostname_is_local(const char *name);
bool sk_address_is_local(SockAddr *addr);
bool sk_address_is_special_local(SockAddr *addr);
int sk_addrtype(SockAddr *addr);
void sk_addrcopy(SockAddr *addr, char *buf);
void sk_addr_free(SockAddr *addr);
/* sk_addr_dup generates another SockAddr which contains the same data
* as the original one and can be freed independently. May not actually
* physically _duplicate_ it: incrementing a reference count so that
* one more free is required before it disappears is an acceptable
* implementation. */
SockAddr *sk_addr_dup(SockAddr *addr);
/* NB, control of 'addr' is passed via sk_new, which takes responsibility
* for freeing it, as for new_connection() */
Socket *sk_new(SockAddr *addr, int port, bool privport, bool oobinline,
bool nodelay, bool keepalive, Plug *p);
Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug,
bool local_host_only, int address_family);
static inline Plug *sk_plug(Socket *s, Plug *p)
{ return s->vt->plug(s, p); }
static inline void sk_close(Socket *s)
{ s->vt->close(s); }
static inline size_t sk_write(Socket *s, const void *data, size_t len)
{ return s->vt->write(s, data, len); }
static inline size_t sk_write_oob(Socket *s, const void *data, size_t len)
{ return s->vt->write_oob(s, data, len); }
static inline void sk_write_eof(Socket *s)
{ s->vt->write_eof(s); }
static inline void plug_log(
Plug *p, int type, SockAddr *addr, int port, const char *msg, int code)
{ p->vt->log(p, type, addr, port, msg, code); }
static inline void plug_closing(
Plug *p, const char *msg, int code, bool calling_back)
{ p->vt->closing(p, msg, code, calling_back); }
static inline void plug_receive(Plug *p, int urg, const char *data, size_t len)
{ p->vt->receive(p, urg, data, len); }
static inline void plug_sent (Plug *p, size_t bufsize)
{ p->vt->sent(p, bufsize); }
static inline int plug_accepting(Plug *p, accept_fn_t cons, accept_ctx_t ctx)
{ return p->vt->accepting(p, cons, ctx); }
/*
* Special error values are returned from sk_namelookup and sk_new
* if there's a problem. These functions extract an error message,
* or return NULL if there's no problem.
*/
const char *sk_addr_error(SockAddr *addr);
static inline const char *sk_socket_error(Socket *s)
{ return s->vt->socket_error(s); }
/*
* Set the `frozen' flag on a socket. A frozen socket is one in
* which all READABLE notifications are ignored, so that data is
* not accepted from the peer until the socket is unfrozen. This
* exists for two purposes:
*
* - Port forwarding: when a local listening port receives a
* connection, we do not want to receive data from the new
* socket until we have somewhere to send it. Hence, we freeze
* the socket until its associated SSH channel is ready; then we
* unfreeze it and pending data is delivered.
*
* - Socket buffering: if an SSH channel (or the whole connection)
* backs up or presents a zero window, we must freeze the
* associated local socket in order to avoid unbounded buffer
* growth.
*/
static inline void sk_set_frozen(Socket *s, bool is_frozen)
{ s->vt->set_frozen(s, is_frozen); }
/*
* Return a structure giving some information about the other end of
* the socket. May be NULL, if nothing is available at all. If it is
* not NULL, then it is dynamically allocated, and should be freed by
* a call to sk_free_peer_info(). See below for the definition.
*/
static inline SocketPeerInfo *sk_peer_info(Socket *s)
{ return s->vt->peer_info(s); }
/*
* The structure returned from sk_peer_info, and a function to free
* one (in misc.c).
*/
struct SocketPeerInfo {
int addressfamily;
/*
* Text form of the IPv4 or IPv6 address of the other end of the
* socket, if available, in the standard text representation.
*/
const char *addr_text;
/*
* Binary form of the same address. Filled in if and only if
* addr_text is not NULL. You can tell which branch of the union
* is used by examining 'addressfamily'.
*/
union {
unsigned char ipv6[16];
unsigned char ipv4[4];
} addr_bin;
/*
* Remote port number, or -1 if not available.
*/
int port;
/*
* Free-form text suitable for putting in log messages. For IP
* sockets, repeats the address and port information from above.
* But it can be completely different, e.g. for Unix-domain
* sockets it gives information about the uid, gid and pid of the
* connecting process.
*/
const char *log_text;
};
void sk_free_peer_info(SocketPeerInfo *pi);
/*
* Simple wrapper on getservbyname(), needed by ssh.c. Returns the
* port number, in host byte order (suitable for printf and so on).
* Returns 0 on failure. Any platform not supporting getservbyname
* can just return 0 - this function is not required to handle
* numeric port specifications.
*/
int net_service_lookup(char *service);
/*
* Look up the local hostname; return value needs freeing.
* May return NULL.
*/
char *get_hostname(void);
/*
* Trivial socket implementation which just stores an error. Found in
* errsock.c.
*/
Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...);
/*
* Trivial plug that does absolutely nothing. Found in nullplug.c.
*/
extern Plug *const nullplug;
/* ----------------------------------------------------------------------
* Functions defined outside the network code, which have to be
* declared in this header file rather than the main putty.h because
* they use types defined here.
*/
/*
* Exports from be_misc.c.
*/
void backend_socket_log(Seat *seat, LogContext *logctx,
int type, SockAddr *addr, int port,
const char *error_msg, int error_code, Conf *conf,
bool session_started);
typedef struct ProxyStderrBuf {
char buf[8192];
size_t size;
} ProxyStderrBuf;
void psb_init(ProxyStderrBuf *psb);
void log_proxy_stderr(
Plug *plug, ProxyStderrBuf *psb, const void *vdata, size_t len);
#endif
/*
* Networking abstraction in PuTTY.
*
* The way this works is: a back end can choose to open any number
* of sockets - including zero, which might be necessary in some.
* It can register a bunch of callbacks (most notably for when
* data is received) for each socket, and it can call the networking
* abstraction to send data without having to worry about blocking.
* The stuff behind the abstraction takes care of selects and
* nonblocking writes and all that sort of painful gubbins.
*/
#ifndef PUTTY_NETWORK_H
#define PUTTY_NETWORK_H
#include "defs.h"
typedef struct SocketVtable SocketVtable;
typedef struct PlugVtable PlugVtable;
struct Socket {
const struct SocketVtable *vt;
};
struct SocketVtable {
Plug *(*plug) (Socket *s, Plug *p);
/* use a different plug (return the old one) */
/* if p is NULL, it doesn't change the plug */
/* but it does return the one it's using */
void (*close) (Socket *s);
size_t (*write) (Socket *s, const void *data, size_t len);
size_t (*write_oob) (Socket *s, const void *data, size_t len);
void (*write_eof) (Socket *s);
void (*set_frozen) (Socket *s, bool is_frozen);
/* ignored by tcp, but vital for ssl */
const char *(*socket_error) (Socket *s);
SocketPeerInfo *(*peer_info) (Socket *s);
};
typedef union { void *p; int i; } accept_ctx_t;
typedef Socket *(*accept_fn_t)(accept_ctx_t ctx, Plug *plug);
struct Plug {
const struct PlugVtable *vt;
};
typedef enum PlugLogType {
PLUGLOG_CONNECT_TRYING,
PLUGLOG_CONNECT_FAILED,
PLUGLOG_CONNECT_SUCCESS,
PLUGLOG_PROXY_MSG,
} PlugLogType;
struct PlugVtable {
void (*log)(Plug *p, PlugLogType type, SockAddr *addr, int port,
const char *error_msg, int error_code);
/*
* Passes the client progress reports on the process of setting
* up the connection.
*
* - PLUGLOG_CONNECT_TRYING means we are about to try to connect
* to address `addr' (error_msg and error_code are ignored)
*
* - PLUGLOG_CONNECT_FAILED means we have failed to connect to
* address `addr' (error_msg and error_code are supplied). This
* is not a fatal error - we may well have other candidate
* addresses to fall back to. When it _is_ fatal, the closing()
* function will be called.
*
* - PLUGLOG_CONNECT_SUCCESS means we have succeeded in
* connecting to address `addr'.
*
* - PLUGLOG_PROXY_MSG means that error_msg contains a line of
* logging information from whatever the connection is being
* proxied through. This will typically be a wodge of
* standard-error output from a local proxy command, so the
* receiver should probably prefix it to indicate this.
*/
void (*closing)
(Plug *p, const char *error_msg, int error_code, bool calling_back);
/* error_msg is NULL iff it is not an error (ie it closed normally) */
/* calling_back != 0 iff there is a Plug function */
/* currently running (would cure the fixme in try_send()) */
void (*receive) (Plug *p, int urgent, const char *data, size_t len);
/*
* - urgent==0. `data' points to `len' bytes of perfectly
* ordinary data.
*
* - urgent==1. `data' points to `len' bytes of data,
* which were read from before an Urgent pointer.
*
* - urgent==2. `data' points to `len' bytes of data,
* the first of which was the one at the Urgent mark.
*/
void (*sent) (Plug *p, size_t bufsize);
/*
* The `sent' function is called when the pending send backlog
* on a socket is cleared or partially cleared. The new backlog
* size is passed in the `bufsize' parameter.
*/
int (*accepting)(Plug *p, accept_fn_t constructor, accept_ctx_t ctx);
/*
* `accepting' is called only on listener-type sockets, and is
* passed a constructor function+context that will create a fresh
* Socket describing the connection. It returns nonzero if it
* doesn't want the connection for some reason, or 0 on success.
*/
};
/* proxy indirection layer */
/* NB, control of 'addr' is passed via new_connection, which takes
* responsibility for freeing it */
Socket *new_connection(SockAddr *addr, const char *hostname,
int port, bool privport,
bool oobinline, bool nodelay, bool keepalive,
Plug *plug, Conf *conf);
Socket *new_listener(const char *srcaddr, int port, Plug *plug,
bool local_host_only, Conf *conf, int addressfamily);
SockAddr *name_lookup(const char *host, int port, char **canonicalname,
Conf *conf, int addressfamily, LogContext *logctx,
const char *lookup_reason_for_logging);
/* platform-dependent callback from new_connection() */
/* (same caveat about addr as new_connection()) */
Socket *platform_new_connection(SockAddr *addr, const char *hostname,
int port, bool privport,
bool oobinline, bool nodelay, bool keepalive,
Plug *plug, Conf *conf);
/* socket functions */
void sk_init(void); /* called once at program startup */
void sk_cleanup(void); /* called just before program exit */
SockAddr *sk_namelookup(const char *host, char **canonicalname, int address_family);
SockAddr *sk_nonamelookup(const char *host);
void sk_getaddr(SockAddr *addr, char *buf, int buflen);
bool sk_addr_needs_port(SockAddr *addr);
bool sk_hostname_is_local(const char *name);
bool sk_address_is_local(SockAddr *addr);
bool sk_address_is_special_local(SockAddr *addr);
int sk_addrtype(SockAddr *addr);
void sk_addrcopy(SockAddr *addr, char *buf);
void sk_addr_free(SockAddr *addr);
/* sk_addr_dup generates another SockAddr which contains the same data
* as the original one and can be freed independently. May not actually
* physically _duplicate_ it: incrementing a reference count so that
* one more free is required before it disappears is an acceptable
* implementation. */
SockAddr *sk_addr_dup(SockAddr *addr);
/* NB, control of 'addr' is passed via sk_new, which takes responsibility
* for freeing it, as for new_connection() */
Socket *sk_new(SockAddr *addr, int port, bool privport, bool oobinline,
bool nodelay, bool keepalive, Plug *p);
Socket *sk_newlistener(const char *srcaddr, int port, Plug *plug,
bool local_host_only, int address_family);
static inline Plug *sk_plug(Socket *s, Plug *p)
{ return s->vt->plug(s, p); }
static inline void sk_close(Socket *s)
{ s->vt->close(s); }
static inline size_t sk_write(Socket *s, const void *data, size_t len)
{ return s->vt->write(s, data, len); }
static inline size_t sk_write_oob(Socket *s, const void *data, size_t len)
{ return s->vt->write_oob(s, data, len); }
static inline void sk_write_eof(Socket *s)
{ s->vt->write_eof(s); }
static inline void plug_log(
Plug *p, int type, SockAddr *addr, int port, const char *msg, int code)
{ p->vt->log(p, type, addr, port, msg, code); }
static inline void plug_closing(
Plug *p, const char *msg, int code, bool calling_back)
{ p->vt->closing(p, msg, code, calling_back); }
static inline void plug_receive(Plug *p, int urg, const char *data, size_t len)
{ p->vt->receive(p, urg, data, len); }
static inline void plug_sent (Plug *p, size_t bufsize)
{ p->vt->sent(p, bufsize); }
static inline int plug_accepting(Plug *p, accept_fn_t cons, accept_ctx_t ctx)
{ return p->vt->accepting(p, cons, ctx); }
/*
* Special error values are returned from sk_namelookup and sk_new
* if there's a problem. These functions extract an error message,
* or return NULL if there's no problem.
*/
const char *sk_addr_error(SockAddr *addr);
static inline const char *sk_socket_error(Socket *s)
{ return s->vt->socket_error(s); }
/*
* Set the `frozen' flag on a socket. A frozen socket is one in
* which all READABLE notifications are ignored, so that data is
* not accepted from the peer until the socket is unfrozen. This
* exists for two purposes:
*
* - Port forwarding: when a local listening port receives a
* connection, we do not want to receive data from the new
* socket until we have somewhere to send it. Hence, we freeze
* the socket until its associated SSH channel is ready; then we
* unfreeze it and pending data is delivered.
*
* - Socket buffering: if an SSH channel (or the whole connection)
* backs up or presents a zero window, we must freeze the
* associated local socket in order to avoid unbounded buffer
* growth.
*/
static inline void sk_set_frozen(Socket *s, bool is_frozen)
{ s->vt->set_frozen(s, is_frozen); }
/*
* Return a structure giving some information about the other end of
* the socket. May be NULL, if nothing is available at all. If it is
* not NULL, then it is dynamically allocated, and should be freed by
* a call to sk_free_peer_info(). See below for the definition.
*/
static inline SocketPeerInfo *sk_peer_info(Socket *s)
{ return s->vt->peer_info(s); }
/*
* The structure returned from sk_peer_info, and a function to free
* one (in misc.c).
*/
struct SocketPeerInfo {
int addressfamily;
/*
* Text form of the IPv4 or IPv6 address of the other end of the
* socket, if available, in the standard text representation.
*/
const char *addr_text;
/*
* Binary form of the same address. Filled in if and only if
* addr_text is not NULL. You can tell which branch of the union
* is used by examining 'addressfamily'.
*/
union {
unsigned char ipv6[16];
unsigned char ipv4[4];
} addr_bin;
/*
* Remote port number, or -1 if not available.
*/
int port;
/*
* Free-form text suitable for putting in log messages. For IP
* sockets, repeats the address and port information from above.
* But it can be completely different, e.g. for Unix-domain
* sockets it gives information about the uid, gid and pid of the
* connecting process.
*/
const char *log_text;
};
void sk_free_peer_info(SocketPeerInfo *pi);
/*
* Simple wrapper on getservbyname(), needed by ssh.c. Returns the
* port number, in host byte order (suitable for printf and so on).
* Returns 0 on failure. Any platform not supporting getservbyname
* can just return 0 - this function is not required to handle
* numeric port specifications.
*/
int net_service_lookup(char *service);
/*
* Look up the local hostname; return value needs freeing.
* May return NULL.
*/
char *get_hostname(void);
/*
* Trivial socket implementation which just stores an error. Found in
* errsock.c.
*
* The consume_string variant takes an already-formatted dynamically
* allocated string, and takes over ownership of that string.
*/
Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...)
PRINTF_LIKE(2, 3);
Socket *new_error_socket_consume_string(Plug *plug, char *errmsg);
/*
* Trivial plug that does absolutely nothing. Found in nullplug.c.
*/
extern Plug *const nullplug;
/* ----------------------------------------------------------------------
* Functions defined outside the network code, which have to be
* declared in this header file rather than the main putty.h because
* they use types defined here.
*/
/*
* Exports from be_misc.c.
*/
void backend_socket_log(Seat *seat, LogContext *logctx,
PlugLogType type, SockAddr *addr, int port,
const char *error_msg, int error_code, Conf *conf,
bool session_started);
typedef struct ProxyStderrBuf {
char buf[8192];
size_t size;
} ProxyStderrBuf;
void psb_init(ProxyStderrBuf *psb);
void log_proxy_stderr(
Plug *plug, ProxyStderrBuf *psb, const void *vdata, size_t len);
#endif
@@ -1,42 +1,37 @@
/*
* nocmdline.c - stubs in applications which don't do the
* standard(ish) PuTTY tools' command-line parsing
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "putty.h"
/*
* Stub version of the function in cmdline.c which provides the
* password to SSH authentication by remembering it having been passed
* as a command-line option. If we're not doing normal command-line
* handling, then there is no such option, so that function always
* returns failure.
*/
int cmdline_get_passwd_input(prompts_t *p)
{
return -1;
}
/*
* The main cmdline_process_param function is normally called from
* applications' main(). An application linking against this stub
* module shouldn't have a main() that calls it in the first place :-)
* but it is just occasionally called by other supporting functions,
* such as one in uxputty.c which sometimes handles a non-option
* argument by making up equivalent options and passing them back to
* this function. So we have to provide a link-time stub of this
* function, but it had better not end up being called at run time.
*/
int cmdline_process_param(const char *p, char *value,
int need_save, Conf *conf)
{
unreachable("cmdline_process_param should never be called");
}
/*
* This variable will be referred to, so it has to exist. It's ignored.
*/
int cmdline_tooltype = 0;
/*
* nocmdline.c - stubs in applications which don't do the
* standard(ish) PuTTY tools' command-line parsing
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "putty.h"
/*
* Stub version of the function in cmdline.c which provides the
* password to SSH authentication by remembering it having been passed
* as a command-line option. If we're not doing normal command-line
* handling, then there is no such option, so that function always
* returns failure.
*/
int cmdline_get_passwd_input(prompts_t *p)
{
return -1;
}
/*
* The main cmdline_process_param function is normally called from
* applications' main(). An application linking against this stub
* module shouldn't have a main() that calls it in the first place :-)
* but it is just occasionally called by other supporting functions,
* such as one in uxputty.c which sometimes handles a non-option
* argument by making up equivalent options and passing them back to
* this function. So we have to provide a link-time stub of this
* function, but it had better not end up being called at run time.
*/
int cmdline_process_param(const char *p, char *value,
int need_save, Conf *conf)
{
unreachable("cmdline_process_param should never be called");
}
@@ -1,38 +1,38 @@
/*
* Stub implementation of the printing interface for PuTTY, for the
* benefit of non-printing terminal applications.
*/
#include <assert.h>
#include <stdio.h>
#include "putty.h"
struct printer_job_tag {
int dummy;
};
printer_job *printer_start_job(char *printer)
{
return NULL;
}
void printer_job_data(printer_job *pj, void *data, size_t len)
{
}
void printer_finish_job(printer_job *pj)
{
}
printer_enum *printer_start_enum(int *nprinters_ptr)
{
*nprinters_ptr = 0;
return NULL;
}
char *printer_get_name(printer_enum *pe, int i)
{
return NULL;
}
void printer_finish_enum(printer_enum *pe)
{
}
/*
* Stub implementation of the printing interface for PuTTY, for the
* benefit of non-printing terminal applications.
*/
#include <assert.h>
#include <stdio.h>
#include "putty.h"
struct printer_job_tag {
int dummy;
};
printer_job *printer_start_job(char *printer)
{
return NULL;
}
void printer_job_data(printer_job *pj, const void *data, size_t len)
{
}
void printer_finish_job(printer_job *pj)
{
}
printer_enum *printer_start_enum(int *nprinters_ptr)
{
*nprinters_ptr = 0;
return NULL;
}
char *printer_get_name(printer_enum *pe, int i)
{
return NULL;
}
void printer_finish_enum(printer_enum *pe)
{
}
+32
View File
@@ -0,0 +1,32 @@
/*
* noproxy.c: an alternative to proxy.c, for use by auxiliary programs
* that need to make network connections but don't want to include all
* the full-on support for endless network proxies (and its
* configuration requirements). Implements the primary APIs of
* proxy.c, but maps them straight to the underlying network layer.
*/
#include "putty.h"
#include "network.h"
#include "proxy.h"
SockAddr *name_lookup(const char *host, int port, char **canonicalname,
Conf *conf, int addressfamily, LogContext *logctx,
const char *reason)
{
return sk_namelookup(host, canonicalname, addressfamily);
}
Socket *new_connection(SockAddr *addr, const char *hostname,
int port, bool privport,
bool oobinline, bool nodelay, bool keepalive,
Plug *plug, Conf *conf)
{
return sk_new(addr, port, privport, oobinline, nodelay, keepalive, plug);
}
Socket *new_listener(const char *srcaddr, int port, Plug *plug,
bool local_host_only, Conf *conf, int addressfamily)
{
return sk_newlistener(srcaddr, port, plug, local_host_only, addressfamily);
}
+22
View File
@@ -0,0 +1,22 @@
/*
* Stub implementations of RNG functions for applications without an RNG.
*/
#include "putty.h"
void random_read(void *out, size_t size)
{
unreachable("Random numbers are not available in this application");
}
void random_save_seed(void)
{
}
void random_destroy_seed(void)
{
}
void noise_ultralight(NoiseSourceId id, unsigned long data)
{
}
@@ -1,25 +1,25 @@
/*
* Stub implementation of SSH connection-sharing IPC, for any
* platform which can't support it at all.
*/
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include "tree234.h"
#include "putty.h"
#include "ssh.h"
#include "network.h"
int platform_ssh_share(const char *name, Conf *conf,
Plug *downplug, Plug *upplug, Socket **sock,
char **logtext, char **ds_err, char **us_err,
int can_upstream, int can_downstream)
{
return SHARE_NONE;
}
void platform_ssh_share_cleanup(const char *name)
{
}
/*
* Stub implementation of SSH connection-sharing IPC, for any
* platform which can't support it at all.
*/
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include "tree234.h"
#include "putty.h"
#include "ssh.h"
#include "network.h"
int platform_ssh_share(const char *name, Conf *conf,
Plug *downplug, Plug *upplug, Socket **sock,
char **logtext, char **ds_err, char **us_err,
bool can_upstream, bool can_downstream)
{
return SHARE_NONE;
}
void platform_ssh_share_cleanup(const char *name)
{
}

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