Skip to content

Commit

Permalink
PuTTY 0.80
Browse files Browse the repository at this point in the history
Source commit: 04e78706e91713a0bbe3be3d75fc7882165d974a
  • Loading branch information
martinprikryl committed Dec 20, 2023
1 parent 513d92a commit 1d7d01a
Show file tree
Hide file tree
Showing 21 changed files with 608 additions and 129 deletions.
16 changes: 10 additions & 6 deletions source/putty/crypto/aes-select.c
Expand Up @@ -59,23 +59,26 @@ static ssh_cipher *aes_select(const ssh_cipheralg *alg)
__VA_ARGS__ \
}

AES_SELECTOR_VTABLE(cbc, "aes128-cbc", "CBC", 128, );
AES_SELECTOR_VTABLE(cbc, "aes192-cbc", "CBC", 192, );
AES_SELECTOR_VTABLE(cbc, "aes256-cbc", "CBC", 256, );
AES_SELECTOR_VTABLE(cbc, "aes128-cbc", "CBC", 128, .flags = SSH_CIPHER_IS_CBC);
AES_SELECTOR_VTABLE(cbc, "aes192-cbc", "CBC", 192, .flags = SSH_CIPHER_IS_CBC);
AES_SELECTOR_VTABLE(cbc, "aes256-cbc", "CBC", 256, .flags = SSH_CIPHER_IS_CBC);
AES_SELECTOR_VTABLE(sdctr, "aes128-ctr", "SDCTR", 128, );
AES_SELECTOR_VTABLE(sdctr, "aes192-ctr", "SDCTR", 192, );
AES_SELECTOR_VTABLE(sdctr, "aes256-ctr", "SDCTR", 256, );
AES_SELECTOR_VTABLE(gcm, "aes128-gcm@openssh.com", "GCM", 128,
.required_mac = &ssh2_aesgcm_mac);
.required_mac = &ssh2_aesgcm_mac,
.flags = SSH_CIPHER_SEPARATE_LENGTH);
AES_SELECTOR_VTABLE(gcm, "aes256-gcm@openssh.com", "GCM", 256,
.required_mac = &ssh2_aesgcm_mac);
.required_mac = &ssh2_aesgcm_mac,
.flags = SSH_CIPHER_SEPARATE_LENGTH);

/* 192-bit AES-GCM is included only so that testcrypt can run standard
* test vectors against it. OpenSSH doesn't define a protocol id for
* it. Hence setting its ssh2_id to NULL here, and more importantly,
* leaving it out of aesgcm_list[] below. */
AES_SELECTOR_VTABLE(gcm, NULL, "GCM", 192,
.required_mac = &ssh2_aesgcm_mac);
.required_mac = &ssh2_aesgcm_mac,
.flags = SSH_CIPHER_SEPARATE_LENGTH);

static const ssh_cipheralg ssh_rijndael_lysator = {
/* Same as aes256_cbc, but with a different protocol ID */
Expand All @@ -84,6 +87,7 @@ static const ssh_cipheralg ssh_rijndael_lysator = {
.blksize = 16,
.real_keybits = 256,
.padded_keybytes = 256/8,
.flags = SSH_CIPHER_IS_CBC,
.text_name = "AES-256 CBC (dummy selector vtable)",
.extra = ssh_aes256_cbc_impls,
};
Expand Down
2 changes: 1 addition & 1 deletion source/putty/doc/plink.but
Expand Up @@ -41,7 +41,7 @@ use Plink:

\c C:\>plink
\c Plink: command-line connection utility
\c Release 0.79
\c Release 0.80
\c Usage: plink [options] [user@]host [command]
\c ("host" can also be a PuTTY saved session name)
\c Options:
Expand Down
2 changes: 1 addition & 1 deletion source/putty/doc/pscp.but
Expand Up @@ -39,7 +39,7 @@ use PSCP:

\c C:\>pscp
\c PuTTY Secure Copy client
\c Release 0.79
\c Release 0.80
\c Usage: pscp [options] [user@]host:source target
\c pscp [options] source [source...] [user@]host:target
\c pscp [options] -ls [user@]host:filespec
Expand Down
6 changes: 3 additions & 3 deletions source/putty/doc/puttydoc.txt
Expand Up @@ -5530,7 +5530,7 @@ Chapter 5: Using PSCP to transfer files securely

C:\>pscp
PuTTY Secure Copy client
Release 0.79
Release 0.80
Usage: pscp [options] [user@]host:source target
pscp [options] source [source...] [user@]host:target
pscp [options] -ls [user@]host:filespec
Expand Down Expand Up @@ -6452,7 +6452,7 @@ Chapter 7: Using the command-line connection tool Plink

C:\>plink
Plink: command-line connection utility
Release 0.79
Release 0.80
Usage: plink [options] [user@]host [command]
("host" can also be a PuTTY saved session name)
Options:
Expand Down Expand Up @@ -12479,4 +12479,4 @@ H.6.12 PLUGIN_AUTH_FAILURE
Secure Shell Protocol (SSH)' (better known by its wire id `keyboard-
interactive').

[PuTTY release 0.79]
[PuTTY release 0.80]
2 changes: 1 addition & 1 deletion source/putty/doc/version.but
@@ -1 +1 @@
\versionid PuTTY release 0.79
\versionid PuTTY release 0.80
4 changes: 2 additions & 2 deletions source/putty/proxy/socks4.c
Expand Up @@ -95,8 +95,8 @@ static void proxy_socks4_process_queue(ProxyNegotiator *pn)

if (data[0] != SOCKS4_REPLY_VERSION) {
pn->error = dupprintf("SOCKS proxy response contained reply "
"version number %d (expected 0)",
(int)data[0]);
"version number %d (expected %d)",
(int)data[0], SOCKS4_REPLY_VERSION);
crStopV;
}

Expand Down
4 changes: 2 additions & 2 deletions source/putty/proxy/socks5.c
Expand Up @@ -353,7 +353,7 @@ static void proxy_socks5_process_queue(ProxyNegotiator *pn)
"SOCKS 5 CHAP authentication failed");
crStopV;
}
} else if (s->chap_attr==SOCKS5_AUTH_CHAP_ATTR_CHALLENGE) {
} else if (s->chap_attr == SOCKS5_AUTH_CHAP_ATTR_CHALLENGE) {
/* The CHAP challenge string. Send the response */
strbuf *response = chap_response(
make_ptrlen(s->chap_buf, s->chap_attr_len),
Expand Down Expand Up @@ -387,7 +387,7 @@ static void proxy_socks5_process_queue(ProxyNegotiator *pn)
* byte[] address, with variable size (see below)
* uint16 port
*/
put_byte(pn->output, SOCKS5_REPLY_VERSION);
put_byte(pn->output, SOCKS5_REQUEST_VERSION);
put_byte(pn->output, SOCKS_CMD_CONNECT);
put_byte(pn->output, 0); /* reserved byte */

Expand Down
24 changes: 12 additions & 12 deletions source/putty/putty.h
Expand Up @@ -1293,7 +1293,7 @@ struct SeatVtable {
* confirm_ssh_host_key above.
*/
SeatPromptResult (*confirm_weak_crypto_primitive)(
Seat *seat, const char *algtype, const char *algname,
Seat *seat, SeatDialogText *text,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);

/*
Expand All @@ -1304,11 +1304,10 @@ struct SeatVtable {
* This form is used in the case where we're using a host key
* below the warning threshold because that's the best one we have
* cached, but at least one host key algorithm *above* the
* threshold is available that we don't have cached. 'betteralgs'
* lists the better algorithm(s).
* threshold is available that we don't have cached.
*/
SeatPromptResult (*confirm_weak_cached_hostkey)(
Seat *seat, const char *algname, const char *betteralgs,
Seat *seat, SeatDialogText *text,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);

/*
Expand Down Expand Up @@ -1444,15 +1443,15 @@ static inline SeatPromptResult seat_confirm_ssh_host_key(
{ return iseat.seat->vt->confirm_ssh_host_key(
iseat.seat, h, p, ktyp, kstr, text, helpctx, cb, ctx); }
static inline SeatPromptResult seat_confirm_weak_crypto_primitive(
InteractionReadySeat iseat, const char *atyp, const char *aname,
InteractionReadySeat iseat, SeatDialogText *text,
void (*cb)(void *ctx, SeatPromptResult result), void *ctx)
{ return iseat.seat->vt->confirm_weak_crypto_primitive(
iseat.seat, atyp, aname, cb, ctx); }
iseat.seat, text, cb, ctx); }
static inline SeatPromptResult seat_confirm_weak_cached_hostkey(
InteractionReadySeat iseat, const char *aname, const char *better,
InteractionReadySeat iseat, SeatDialogText *text,
void (*cb)(void *ctx, SeatPromptResult result), void *ctx)
{ return iseat.seat->vt->confirm_weak_cached_hostkey(
iseat.seat, aname, better, cb, ctx); }
iseat.seat, text, cb, ctx); }
static inline const SeatDialogPromptDescriptions *seat_prompt_descriptions(
Seat *seat)
{ return seat->vt->prompt_descriptions(seat); }
Expand Down Expand Up @@ -1505,6 +1504,7 @@ struct SeatDialogPromptDescriptions {
const char *hk_accept_action;
const char *hk_connect_once_action;
const char *hk_cancel_action, *hk_cancel_action_Participle;
const char *weak_accept_action, *weak_cancel_action;
};

/* In the utils subdir: print a message to the Seat which can't be
Expand Down Expand Up @@ -1537,10 +1537,10 @@ SeatPromptResult nullseat_confirm_ssh_host_key(
char *keystr, SeatDialogText *text, HelpCtx helpctx,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);
SeatPromptResult nullseat_confirm_weak_crypto_primitive(
Seat *seat, const char *algtype, const char *algname,
Seat *seat, SeatDialogText *text,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);
SeatPromptResult nullseat_confirm_weak_cached_hostkey(
Seat *seat, const char *algname, const char *betteralgs,
Seat *seat, SeatDialogText *text,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);
const SeatDialogPromptDescriptions *nullseat_prompt_descriptions(Seat *seat);
bool nullseat_is_never_utf8(Seat *seat);
Expand Down Expand Up @@ -1573,10 +1573,10 @@ SeatPromptResult console_confirm_ssh_host_key(
char *keystr, SeatDialogText *text, HelpCtx helpctx,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);
SeatPromptResult console_confirm_weak_crypto_primitive(
Seat *seat, const char *algtype, const char *algname,
Seat *seat, SeatDialogText *text,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);
SeatPromptResult console_confirm_weak_cached_hostkey(
Seat *seat, const char *algname, const char *betteralgs,
Seat *seat, SeatDialogText *text,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);
StripCtrlChars *console_stripctrl_new(
Seat *seat, BinarySink *bs_out, SeatInteractionContext sic);
Expand Down
2 changes: 1 addition & 1 deletion source/putty/settings.c
Expand Up @@ -146,7 +146,7 @@ static void gpps(settings_r *sesskey, const char *name, const char *def,
* format of a Filename or FontSpec is platform-dependent. So the
* platform-dependent functions MUST return some sort of value.
*/
static void gppfont(settings_r *sesskey, char *name,
static void gppfont(settings_r *sesskey, const char *name,
Conf *conf, int primary)
{
FontSpec *result = read_setting_fontspec(sesskey, name);
Expand Down
15 changes: 15 additions & 0 deletions source/putty/ssh.h
Expand Up @@ -1903,11 +1903,26 @@ void add_to_commasep(strbuf *buf, const char *data);
void add_to_commasep_pl(strbuf *buf, ptrlen data);
bool get_commasep_word(ptrlen *list, ptrlen *word);

/* Reasons why something warned by confirm_weak_crypto_primitive might
* be considered weak */
typedef enum WeakCryptoReason {
WCR_BELOW_THRESHOLD, /* user has told us to consider it weak */
WCR_TERRAPIN, /* known vulnerability CVE-2023-48795 */
WCR_TERRAPIN_AVOIDABLE, /* same, but demoting ChaCha20 can avoid it */
} WeakCryptoReason;

SeatPromptResult verify_ssh_host_key(
InteractionReadySeat iseat, Conf *conf, const char *host, int port,
ssh_key *key, const char *keytype, char *keystr, const char *keydisp,
char **fingerprints, int ca_count,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);
SeatPromptResult confirm_weak_crypto_primitive(
InteractionReadySeat iseat, const char *algtype, const char *algname,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx,
WeakCryptoReason wcr);
SeatPromptResult confirm_weak_cached_hostkey(
InteractionReadySeat iseat, const char *algname, const char **betteralgs,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx);

typedef struct ssh_transient_hostkey_cache ssh_transient_hostkey_cache;
ssh_transient_hostkey_cache *ssh_transient_hostkey_cache_new(void);
Expand Down
6 changes: 4 additions & 2 deletions source/putty/ssh/bpp.h
Expand Up @@ -138,12 +138,14 @@ void ssh2_bpp_new_outgoing_crypto(
BinaryPacketProtocol *bpp,
const ssh_cipheralg *cipher, const void *ckey, const void *iv,
const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
const ssh_compression_alg *compression, bool delayed_compression);
const ssh_compression_alg *compression, bool delayed_compression,
bool reset_sequence_number);
void ssh2_bpp_new_incoming_crypto(
BinaryPacketProtocol *bpp,
const ssh_cipheralg *cipher, const void *ckey, const void *iv,
const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
const ssh_compression_alg *compression, bool delayed_compression);
const ssh_compression_alg *compression, bool delayed_compression,
bool reset_sequence_number);

/*
* A query method specific to the interface between ssh2transport and
Expand Down
12 changes: 10 additions & 2 deletions source/putty/ssh/bpp2.c
Expand Up @@ -106,7 +106,8 @@ void ssh2_bpp_new_outgoing_crypto(
BinaryPacketProtocol *bpp,
const ssh_cipheralg *cipher, const void *ckey, const void *iv,
const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
const ssh_compression_alg *compression, bool delayed_compression)
const ssh_compression_alg *compression, bool delayed_compression,
bool reset_sequence_number)
{
struct ssh2_bpp_state *s;
assert(bpp->vt == &ssh2_bpp_vtable);
Expand Down Expand Up @@ -150,6 +151,9 @@ void ssh2_bpp_new_outgoing_crypto(
s->out.mac = NULL;
}

if (reset_sequence_number)
s->out.sequence = 0;

if (delayed_compression && !s->seen_userauth_success) {
s->out.pending_compression = compression;
s->out_comp = NULL;
Expand All @@ -174,7 +178,8 @@ void ssh2_bpp_new_incoming_crypto(
BinaryPacketProtocol *bpp,
const ssh_cipheralg *cipher, const void *ckey, const void *iv,
const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
const ssh_compression_alg *compression, bool delayed_compression)
const ssh_compression_alg *compression, bool delayed_compression,
bool reset_sequence_number)
{
struct ssh2_bpp_state *s;
assert(bpp->vt == &ssh2_bpp_vtable);
Expand Down Expand Up @@ -231,6 +236,9 @@ void ssh2_bpp_new_incoming_crypto(
* start consuming the input data again. */
s->pending_newkeys = false;

if (reset_sequence_number)
s->in.sequence = 0;

/* And schedule a run of handle_input, in case there's already
* input data in the queue. */
queue_idempotent_callback(&s->bpp.ic_in_raw);
Expand Down
104 changes: 104 additions & 0 deletions source/putty/ssh/common.c
Expand Up @@ -1085,6 +1085,110 @@ SeatPromptResult verify_ssh_host_key(
return toret;
}

SeatPromptResult confirm_weak_crypto_primitive(
InteractionReadySeat iseat, const char *algtype, const char *algname,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx,
WeakCryptoReason wcr)
{
SeatDialogText *text = seat_dialog_text_new();
const SeatDialogPromptDescriptions *pds =
seat_prompt_descriptions(iseat.seat);

seat_dialog_text_append(text, SDT_TITLE, "%s Security Alert", appname);

switch (wcr) {
case WCR_BELOW_THRESHOLD:
seat_dialog_text_append(
text, SDT_PARA,
"The first %s supported by the server is %s, "
"which is below the configured warning threshold.",
algtype, algname);
break;
case WCR_TERRAPIN:
case WCR_TERRAPIN_AVOIDABLE:
seat_dialog_text_append(
text, SDT_PARA,
"The %s selected for this session is %s, "
"which, with this server, is vulnerable to the 'Terrapin' attack "
"CVE-2023-48795, potentially allowing an attacker to modify "
"the encrypted session.",
algtype, algname);
seat_dialog_text_append(
text, SDT_PARA,
"Upgrading, patching, or reconfiguring this SSH server is the "
"best way to avoid this vulnerability, if possible.");
if (wcr == WCR_TERRAPIN_AVOIDABLE) {
seat_dialog_text_append(
text, SDT_PARA,
"You can also avoid this vulnerability by abandoning "
"this connection, moving ChaCha20 to below the "
"'warn below here' line in PuTTY's SSH cipher "
"configuration (so that an algorithm without the "
"vulnerability will be selected), and starting a new "
"connection.");
}
break;
default:
unreachable("bad WeakCryptoReason");
}

/* In batch mode, we print the above information and then this
* abort message, and stop. */
seat_dialog_text_append(text, SDT_BATCH_ABORT, "Connection abandoned.");

seat_dialog_text_append(
text, SDT_PARA, "To accept the risk and continue, %s. "
"To abandon the connection, %s.",
pds->weak_accept_action, pds->weak_cancel_action);

seat_dialog_text_append(text, SDT_PROMPT, "Continue with connection?");

SeatPromptResult toret = seat_confirm_weak_crypto_primitive(
iseat, text, callback, ctx);
seat_dialog_text_free(text);
return toret;
}

SeatPromptResult confirm_weak_cached_hostkey(
InteractionReadySeat iseat, const char *algname, const char **betteralgs,
void (*callback)(void *ctx, SeatPromptResult result), void *ctx)
{
SeatDialogText *text = seat_dialog_text_new();
const SeatDialogPromptDescriptions *pds =
seat_prompt_descriptions(iseat.seat);

seat_dialog_text_append(text, SDT_TITLE, "%s Security Alert", appname);

seat_dialog_text_append(
text, SDT_PARA,
"The first host key type we have stored for this server "
"is %s, which is below the configured warning threshold.", algname);

seat_dialog_text_append(
text, SDT_PARA,
"The server also provides the following types of host key "
"above the threshold, which we do not have stored:");

for (const char **p = betteralgs; *p; p++)
seat_dialog_text_append(text, SDT_DISPLAY, "%s", *p);

/* In batch mode, we print the above information and then this
* abort message, and stop. */
seat_dialog_text_append(text, SDT_BATCH_ABORT, "Connection abandoned.");

seat_dialog_text_append(
text, SDT_PARA, "To accept the risk and continue, %s. "
"To abandon the connection, %s.",
pds->weak_accept_action, pds->weak_cancel_action);

seat_dialog_text_append(text, SDT_PROMPT, "Continue with connection?");

SeatPromptResult toret = seat_confirm_weak_cached_hostkey(
iseat, text, callback, ctx);
seat_dialog_text_free(text);
return toret;
}

/* ----------------------------------------------------------------------
* Common functions shared between SSH-1 layers.
*/
Expand Down

0 comments on commit 1d7d01a

Please sign in to comment.