Browse Source

PuTTY Pre-release 0.79:2023-05-22.56b16bd

Source commit: b8854c20303cf71066ac3421b037f7bd737c21d6
Martin Prikryl 2 years ago
parent
commit
f7bc002428

+ 16 - 0
source/putty/crypto/hmac.c

@@ -160,6 +160,22 @@ static const char *hmac_text_name(ssh2_mac *mac)
     return ctx->text_name->s;
 }
 
+static const struct hmac_extra ssh_hmac_sha512_extra = { &ssh_sha512, "" };
+const ssh2_macalg ssh_hmac_sha512 = {
+    .new = hmac_new,
+    .free = hmac_free,
+    .setkey = hmac_key,
+    .start = hmac_start,
+    .genresult = hmac_genresult,
+    .next_message = nullmac_next_message,
+    .text_name = hmac_text_name,
+    .name = "hmac-sha2-512",
+    .etm_name = "[email protected]",
+    .len = 64,
+    .keylen = 64,
+    .extra = &ssh_hmac_sha512_extra,
+};
+
 static const struct hmac_extra ssh_hmac_sha256_extra = { &ssh_sha256, "" };
 const ssh2_macalg ssh_hmac_sha256 = {
     .new = hmac_new,

+ 4 - 2
source/putty/crypto/openssh-certs.c

@@ -1033,12 +1033,14 @@ static bool opensshcert_check_cert(
      */
     if (time < ck->valid_after) {
         put_fmt(error, "Certificate is not valid until ");
-        opensshcert_time_to_iso8601(BinarySink_UPCAST(error), time);
+        opensshcert_time_to_iso8601(BinarySink_UPCAST(error),
+                                    ck->valid_after);
         goto out;
     }
     if (time >= ck->valid_before) {
         put_fmt(error, "Certificate expired at ");
-        opensshcert_time_to_iso8601(BinarySink_UPCAST(error), time);
+        opensshcert_time_to_iso8601(BinarySink_UPCAST(error),
+                                    ck->valid_before);
         goto out;
     }
 

+ 1 - 0
source/putty/doc/blurb.but

@@ -23,6 +23,7 @@ page</a>.</p>}
 \cfg{winhelp-filename}{putty.hlp}
 \cfg{info-filename}{putty.info}
 \cfg{chm-filename}{putty.chm}
+\cfg{pdf-filename}{putty.pdf}
 
 PuTTY is a free (MIT-licensed) Windows Telnet and SSH client. This
 manual documents PuTTY, and its companion utilities PSCP, PSFTP,

+ 21 - 1
source/putty/doc/config.but

@@ -3521,6 +3521,9 @@ not available for bugs that \e{cannot} be detected from the server
 version, e.g. because they must be acted on before the server version
 is known.)
 
+(The PuTTY project has a defined policy about when we're prepared to
+add auto-detection for a bug workaround. See \k{feedback-workarounds}.)
+
 \S{config-ssh-bug-ignore2} \q{Chokes on SSH-2 \i{ignore message}s}
 
 An ignore message (SSH_MSG_IGNORE) is a message in the SSH protocol
@@ -3661,6 +3664,23 @@ connection would deadlock. We don't know of any servers that do this,
 but if there is one, then this flag will make PuTTY unable to speak to
 them at all.
 
+\S{config-ssh-bug-rsa-sha2-cert-userauth} \q{Old RSA/SHA2 cert
+algorithm naming}
+
+If PuTTY is trying to do SSH-2 user authentication using an RSA key,
+and the server is using one of the newer SHA-2 based versions of the
+SSH RSA protocol, and the user's key is also a certificate, then
+earlier versions of OpenSSH (up to 7.7) disagree with later versions
+about the right key algorithm string to send in the
+\cw{SSH2_MSG_USERAUTH_REQUEST} packet. Modern versions send a string
+that indicates both the SHA-2 nature and the certificate nature of the
+key, such as \cq{[email protected]}. Earlier versions
+would reject that, and insist on seeing
+\cq{[email protected]} followed by a SHA-2 based signature.
+
+PuTTY should auto-detect the presence of this bug in earlier OpenSSH
+and adjust to send the right string.
+
 \S{config-ssh-bug-sig} \q{Requires padding on SSH-2 \i{RSA} \i{signatures}}
 
 Versions below 3.3 of \i{OpenSSH} require SSH-2 RSA signatures to be
@@ -4071,7 +4091,7 @@ at the bottom of the screen, until a space is typed.
 
 \S{supdup-scroll} \q{Terminal scrolling}
 
-This controls whether the terminal will perform scrolling then the
+This controls whether the terminal will perform scrolling when the
 cursor goes below the last line, or if the cursor will return to the
 first line.
 

+ 18 - 0
source/putty/doc/faq.but

@@ -1084,6 +1084,24 @@ sending of the \cw{IUTF8} mode: on the SSH / TTY panel, select
 \cw{IUTF8} on the list, select \q{Nothing}, and press \q{Set}. (It's
 not possible to disable sending this mode in 0.68.)
 
+\S{faq-privkey-control-moved}{Question} Since 0.78, I can't find where
+to configure my SSH private key.
+
+In PuTTY 0.78, the \q{\ii{Private key} file for authentication} control,
+where you specify a \c{.\i{PPK}} file for SSH public key authentication,
+moved to a new \q{Credentials} panel in the configuration dialog. You can
+find this by opening the \q{SSH} category in the tree view on the left,
+then opening the \q{Auth} subcategory under that, then clicking on
+\q{Credentials}. On this page you'll find the \q{Browse...} button you
+need to select a \c{.PPK} file for authentication, as described in
+\k{config-ssh-privkey}.
+
+(This control had previously been on the \q{Auth} panel since public
+key authentication was first released in 2002, so many online how-to
+guides still describe it there. The configuration controls were
+reorganised to make room for features added in 0.78, such as OpenSSH
+certificates.)
+
 \H{faq-secure} Security questions
 
 \S{faq-publicpc}{Question} Is it safe for me to download PuTTY and

+ 48 - 0
source/putty/doc/feedback.but

@@ -297,6 +297,54 @@ high-quality software to the users comes first.)
 way to get a feature implemented quickly, if it's a big one that we
 don't have time to do ourselves.
 
+\H{feedback-workarounds} Workarounds for SSH server bugs
+
+It's normal for SSH implementations to automatically enable
+workarounds for each other's bugs, using the software version strings
+that are exchanged at the start of the connection. Typically an SSH
+client will have a list of server version strings that it believes to
+have particular bugs, and auto-enable the appropriate set of
+workarounds when it sees one of those strings. (And servers will have
+a similar list of workarounds for \e{client} software they believe to
+be buggy.)
+
+If you've found a bug in an SSH server, and you'd like us to add an
+auto-detected workaround for it, our policy is that \s{the server
+implementor should fix it first}.
+
+If the server implementor has fixed it in the latest version, and can
+give us a complete description of the version strings that go with the
+bug, then we're happy to use those version strings as a trigger to
+automatically enable our workaround (assuming one is possible). We
+\e{won't} accept requests to auto-enable workarounds for an open-ended
+set of version strings, such as \q{any version of FooServer, including
+future ones not yet released}.
+
+The aim of this policy is to encourage implementors to gradually
+converge on the actual standardised SSH protocol. If we enable people
+to continue violating the spec, by installing open-ended workarounds
+in PuTTY for bugs they're never going to fix, then we're contributing
+to an ecosystem in which everyone carries on having bugs and everyone
+else carries on having to work around them.
+
+An exception: if an SSH server is no longer maintained \e{at all}
+(e.g. the company that produced it has gone out of business), and
+every version of it that was ever released has a bug, then that's one
+situation in which we may be prepared to add a workaround rule that
+matches all versions of that software. (The aim is to stop
+implementors from continuing to release software with the bug \dash
+and if they're not releasing it \e{at all} any more, then that's
+already done!)
+
+We do recognise that sometimes it will be difficult to get the server
+maintainer to fix a bug, or even to answer support requests at all. Or
+it might take them a very long time to get round to doing anything
+about it. We're not completely unwilling to compromise: we're prepared
+to add \e{manually enabled} workarounds to PuTTY even for bugs that an
+implementation hasn't fixed yet. We just won't \e{automatically}
+enable the workaround unless the server maintainer has also done their
+part.
+
 \H{feedback-support} \ii{Support requests}
 
 If you're trying to make PuTTY do something for you and it isn't

+ 1 - 1
source/putty/doc/plink.but

@@ -254,7 +254,7 @@ line.
 \S2{plink-option-share} \I{-share-plink}\c{-share}:
 Test and try to share an existing connection.
 
-This option tris to detect if an existing connection can be shared
+This option tries to detect if an existing connection can be shared
 (See \k{config-ssh-sharing} for more information about SSH connection
 sharing.) and reuses that connection.
 

+ 1 - 1
source/putty/doc/pubkey.but

@@ -367,7 +367,7 @@ will need to tell PuTTY to use for authentication (see
 \k{pageant-mainwin-addkey}).
 
 (You can optionally change some details of the PPK format for your saved
-key files; see \k{puttygen-save-params}. But The defaults should be
+key files; see \k{puttygen-save-params}. But the defaults should be
 fine for most purposes.)
 
 \S{puttygen-savepub} Saving your public key to a disk file

+ 112 - 28
source/putty/doc/puttydoc.txt

@@ -12,7 +12,7 @@ not described here; and the pterm and command-line puttygen and pageant
 utilities are not described at all. The only Unix-specific documentation
 that currently exists is the man pages.
 
-This manual is copyright 1997-2022 Simon Tatham. All rights reserved. You
+This manual is copyright 1997-2023 Simon Tatham. All rights reserved. You
 may distribute this documentation under the MIT licence. See appendix D for
 the licence text in full.
 
@@ -3106,7 +3106,7 @@ Chapter 4: Configuring PuTTY
        alternative, see section 4.14.3.)
 
        Note that if you are using SSH-1 and the server has a bug that makes
-       it unable to deal with SSH-1 ignore messages (see section 4.27.13),
+       it unable to deal with SSH-1 ignore messages (see section 4.27.14),
        enabling keepalives will have no effect.
 
 4.14.2 `Disable Nagle's algorithm'
@@ -4872,6 +4872,9 @@ Chapter 4: Configuring PuTTY
            the server version, e.g. because they must be acted on before
            the server version is known.)
 
+       (The PuTTY project has a defined policy about when we're prepared to
+       add auto-detection for a bug workaround. See section B.6.)
+
 4.27.1 `Chokes on SSH-2 ignore messages'
 
        An ignore message (SSH_MSG_IGNORE) is a message in the SSH protocol
@@ -5009,7 +5012,23 @@ Chapter 4: Configuring PuTTY
        this, but if there is one, then this flag will make PuTTY unable to
        speak to them at all.
 
-4.27.8 `Requires padding on SSH-2 RSA signatures'
+4.27.8 `Old RSA/SHA2 cert algorithm naming'
+
+       If PuTTY is trying to do SSH-2 user authentication using an RSA
+       key, and the server is using one of the newer SHA-2 based versions
+       of the SSH RSA protocol, and the user's key is also a certificate,
+       then earlier versions of OpenSSH (up to 7.7) disagree with later
+       versions about the right key algorithm string to send in the
+       SSH2_MSG_USERAUTH_REQUEST packet. Modern versions send a string
+       that indicates both the SHA-2 nature and the certificate nature
+       of the key, such as `[email protected]'. Earlier
+       versions would reject that, and insist on seeing `ssh-rsa-cert-
+       [email protected]' followed by a SHA-2 based signature.
+
+       PuTTY should auto-detect the presence of this bug in earlier OpenSSH
+       and adjust to send the right string.
+
+4.27.9 `Requires padding on SSH-2 RSA signatures'
 
        Versions below 3.3 of OpenSSH require SSH-2 RSA signatures to be
        padded with zero bytes to the same length as the RSA key modulus.
@@ -5026,7 +5045,7 @@ Chapter 4: Configuring PuTTY
 
        This is an SSH-2-specific bug.
 
-4.27.9 `Only supports pre-RFC4419 SSH-2 DH GEX'
+4.27.10 `Only supports pre-RFC4419 SSH-2 DH GEX'
 
        The SSH key exchange method that uses Diffie-Hellman group exchange
        was redesigned after its original release, to use a slightly more
@@ -5041,7 +5060,7 @@ Chapter 4: Configuring PuTTY
 
        This is an SSH-2-specific bug.
 
-4.27.10 `Miscomputes SSH-2 HMAC keys'
+4.27.11 `Miscomputes SSH-2 HMAC keys'
 
        Versions 2.3.0 and below of the SSH server software from ssh.com
        compute the keys for their HMAC message authentication codes
@@ -5056,7 +5075,7 @@ Chapter 4: Configuring PuTTY
 
        This is an SSH-2-specific bug.
 
-4.27.11 `Misuses the session ID in SSH-2 PK auth'
+4.27.12 `Misuses the session ID in SSH-2 PK auth'
 
        Versions below 2.3 of OpenSSH require SSH-2 public-key
        authentication to be done slightly differently: the data to be
@@ -5072,7 +5091,7 @@ Chapter 4: Configuring PuTTY
 
        This is an SSH-2-specific bug.
 
-4.27.12 `Miscomputes SSH-2 encryption keys'
+4.27.13 `Miscomputes SSH-2 encryption keys'
 
        Versions below 2.0.11 of the SSH server software from ssh.com
        compute the keys for the session encryption incorrectly. This
@@ -5086,7 +5105,7 @@ Chapter 4: Configuring PuTTY
 
        This is an SSH-2-specific bug.
 
-4.27.13 `Chokes on SSH-1 ignore messages'
+4.27.14 `Chokes on SSH-1 ignore messages'
 
        An ignore message (SSH_MSG_IGNORE) is a message in the SSH protocol
        which can be sent from the client to the server, or from the server
@@ -5099,15 +5118,15 @@ Chapter 4: Configuring PuTTY
        If this bug is detected, PuTTY will stop using ignore messages.
        This means that keepalives will stop working, and PuTTY will
        have to fall back to a secondary defence against SSH-1 password-
-       length eavesdropping. See section 4.27.14. If this bug is enabled
+       length eavesdropping. See section 4.27.15. If this bug is enabled
        when talking to a correct server, the session will succeed, but
        keepalives will not work and the session might be more vulnerable to
        eavesdroppers than it could be.
 
-4.27.14 `Refuses all SSH-1 password camouflage'
+4.27.15 `Refuses all SSH-1 password camouflage'
 
        When talking to an SSH-1 server which cannot deal with ignore
-       messages (see section 4.27.13), PuTTY will attempt to disguise the
+       messages (see section 4.27.14), PuTTY will attempt to disguise the
        length of the user's password by sending additional padding _within_
        the password packet. This is technically a violation of the SSH-
        1 specification, and so PuTTY will only do it when it cannot use
@@ -5127,7 +5146,7 @@ Chapter 4: Configuring PuTTY
        This is an SSH-1-specific bug. SSH-2 is secure against this type of
        attack.
 
-4.27.15 `Chokes on SSH-1 RSA authentication'
+4.27.16 `Chokes on SSH-1 RSA authentication'
 
        Some SSH-1 servers cannot deal with RSA authentication messages at
        all. If Pageant is running and contains any SSH-1 keys, PuTTY will
@@ -5416,7 +5435,7 @@ Chapter 4: Configuring PuTTY
 
 4.32.4 `Terminal scrolling'
 
-       This controls whether the terminal will perform scrolling then the
+       This controls whether the terminal will perform scrolling when the
        cursor goes below the last line, or if the cursor will return to the
        first line.
 
@@ -6635,7 +6654,7 @@ Chapter 7: Using the command-line connection tool Plink
 
 7.2.3.3 `-share': Test and try to share an existing connection.
 
-       This option tris to detect if an existing connection can be shared
+       This option tries to detect if an existing connection can be shared
        (See section 4.17.5 for more information about SSH connection
        sharing.) and reuses that connection.
 
@@ -7187,7 +7206,7 @@ Chapter 8: Using public keys for SSH authentication
        4.22.1) or tell Pageant to load (see section 9.2.2).
 
        (You can optionally change some details of the PPK format for your
-       saved key files; see section 8.2.13. But The defaults should be fine
+       saved key files; see section 8.2.13. But the defaults should be fine
        for most purposes.)
 
 8.2.11 Saving your public key to a disk file
@@ -8151,7 +8170,7 @@ Chapter 10: Common error messages
        This error can be caused by buggy SSH-1 servers that fail to cope
        with the various strategies we use for camouflaging passwords in
        transit. Upgrade your server, or use the workarounds described in
-       section 4.27.13 and possibly section 4.27.14.
+       section 4.27.14 and possibly section 4.27.15.
 
  10.12 `No supported authentication methods available'
 
@@ -8178,7 +8197,7 @@ Chapter 10: Common error messages
        which may not be noticed.
 
        Occasionally this has been caused by server bugs. An example is the
-       bug described at section 4.27.10, although you're very unlikely to
+       bug described at section 4.27.11, although you're very unlikely to
        encounter that one these days.
 
        In this context MAC stands for Message Authentication Code. It's a
@@ -8195,7 +8214,7 @@ Chapter 10: Common error messages
 
        If you get this error, one thing you could try would be to fiddle
        with the setting of `Miscomputes SSH-2 encryption keys' (see section
-       4.27.12) or `Ignores SSH-2 maximum packet size' (see section 4.27.5)
+       4.27.13) or `Ignores SSH-2 maximum packet size' (see section 4.27.5)
        on the Bugs panel.
 
  10.15 `PuTTY X11 proxy: _various errors_'
@@ -9348,6 +9367,23 @@ A.7.23 After I upgraded PuTTY to 0.68, I can no longer connect to my
        IUTF8 on the list, select `Nothing', and press `Set'. (It's not
        possible to disable sending this mode in 0.68.)
 
+A.7.24 Since 0.78, I can't find where to configure my SSH private key.
+
+       In PuTTY 0.78, the `Private key file for authentication' control,
+       where you specify a `.PPK' file for SSH public key authentication,
+       moved to a new `Credentials' panel in the configuration dialog. You
+       can find this by opening the `SSH' category in the tree view on the
+       left, then opening the `Auth' subcategory under that, then clicking
+       on `Credentials'. On this page you'll find the `Browse...' button
+       you need to select a `.PPK' file for authentication, as described in
+       section 4.22.1.
+
+       (This control had previously been on the `Auth' panel since public
+       key authentication was first released in 2002, so many online how-
+       to guides still describe it there. The configuration controls were
+       reorganised to make room for features added in 0.78, such as OpenSSH
+       certificates.)
+
    A.8 Security questions
 
  A.8.1 Is it safe for me to download PuTTY and use it on a public PC?
@@ -9567,7 +9603,7 @@ A.7.23 After I upgraded PuTTY to 0.68, I can no longer connect to my
        Yes. For most things, you need not bother asking us explicitly for
        permission; our licence already grants you permission.
 
-       See section B.8 for more details.
+       See section B.9 for more details.
 
 A.9.10 Can you sign an agreement indemnifying us against security problems
        in PuTTY?
@@ -9892,7 +9928,7 @@ Appendix B: Feedback and bug reporting
        We get so much e-mail that we literally do not have time to answer
        it all. We regret this, but there's nothing we can do about it.
        So if you can _possibly_ avoid sending mail to the PuTTY team, we
-       recommend you do so. In particular, support requests (section B.6)
+       recommend you do so. In particular, support requests (section B.7)
        are probably better sent to newsgroups, or passed to a local expert
        if possible.
 
@@ -10165,7 +10201,55 @@ Appendix B: Feedback and bug reporting
            to get a feature implemented quickly, if it's a big one that we
            don't have time to do ourselves.
 
-   B.6 Support requests
+   B.6 Workarounds for SSH server bugs
+
+       It's normal for SSH implementations to automatically enable
+       workarounds for each other's bugs, using the software version
+       strings that are exchanged at the start of the connection. Typically
+       an SSH client will have a list of server version strings that it
+       believes to have particular bugs, and auto-enable the appropriate
+       set of workarounds when it sees one of those strings. (And servers
+       will have a similar list of workarounds for _client_ software they
+       believe to be buggy.)
+
+       If you've found a bug in an SSH server, and you'd like us to add
+       an auto-detected workaround for it, our policy is that *the server
+       implementor should fix it first*.
+
+       If the server implementor has fixed it in the latest version, and
+       can give us a complete description of the version strings that go
+       with the bug, then we're happy to use those version strings as a
+       trigger to automatically enable our workaround (assuming one is
+       possible). We _won't_ accept requests to auto-enable workarounds
+       for an open-ended set of version strings, such as `any version of
+       FooServer, including future ones not yet released'.
+
+       The aim of this policy is to encourage implementors to gradually
+       converge on the actual standardised SSH protocol. If we enable
+       people to continue violating the spec, by installing open-ended
+       workarounds in PuTTY for bugs they're never going to fix, then we're
+       contributing to an ecosystem in which everyone carries on having
+       bugs and everyone else carries on having to work around them.
+
+       An exception: if an SSH server is no longer maintained _at all_
+       (e.g. the company that produced it has gone out of business), and
+       every version of it that was ever released has a bug, then that's
+       one situation in which we may be prepared to add a workaround rule
+       that matches all versions of that software. (The aim is to stop
+       implementors from continuing to release software with the bug - and
+       if they're not releasing it _at all_ any more, then that's already
+       done!)
+
+       We do recognise that sometimes it will be difficult to get the
+       server maintainer to fix a bug, or even to answer support requests
+       at all. Or it might take them a very long time to get round to doing
+       anything about it. We're not completely unwilling to compromise:
+       we're prepared to add _manually enabled_ workarounds to PuTTY even
+       for bugs that an implementation hasn't fixed yet. We just won't
+       _automatically_ enable the workaround unless the server maintainer
+       has also done their part.
+
+   B.7 Support requests
 
        If you're trying to make PuTTY do something for you and it isn't
        working, but you're not sure whether it's a bug or not, then
@@ -10206,7 +10290,7 @@ Appendix B: Feedback and bug reporting
        way, you can try mailing it to us, but we can't guarantee to have
        time to answer it.
 
-   B.7 Web server administration
+   B.8 Web server administration
 
        If the PuTTY web site is down (Connection Timed Out), please don't
        bother mailing us to tell us about it. Most of us read our e-mail on
@@ -10228,7 +10312,7 @@ Appendix B: Feedback and bug reporting
        contact us if that doesn't solve the problem (in case we need to
        remove the mirror from our list).
 
-   B.8 Asking permission for things
+   B.9 Asking permission for things
 
        PuTTY is distributed under the MIT Licence (see appendix D for
        details). This means you can do almost _anything_ you like with our
@@ -10258,7 +10342,7 @@ Appendix B: Feedback and bug reporting
        If you just want to link to our web site, just go ahead. (It's not
        clear that we _could_ stop you doing this, even if we wanted to!)
 
-   B.9 Mirroring the PuTTY web site
+  B.10 Mirroring the PuTTY web site
 
        If you want to set up a mirror of the PuTTY website, go ahead and
        set one up. Please don't bother asking us for permission before
@@ -10282,7 +10366,7 @@ Appendix B: Feedback and bug reporting
        guidelines on the Mirrors page); but if you just want to ask for
        permission, you don't need to. You already have permission.
 
-  B.10 Praise and compliments
+  B.11 Praise and compliments
 
        One of the most rewarding things about maintaining free software
        is getting e-mails that just say `thanks'. We are always happy to
@@ -10296,7 +10380,7 @@ Appendix B: Feedback and bug reporting
        To everyone who's ever sent us praise and compliments, in the past
        and the future: _you're welcome_!
 
-  B.11 E-mail address
+  B.12 E-mail address
 
        The actual address to mail is <[email protected]>.
 
@@ -10690,7 +10774,7 @@ Appendix C: PPK file format
 Appendix D: PuTTY Licence
 -------------------------
 
-       PuTTY is copyright 1997-2022 Simon Tatham.
+       PuTTY is copyright 1997-2023 Simon Tatham.
 
        Portions copyright Robert de Bath, Joris van Rantwijk, Delian
        Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
@@ -12358,4 +12442,4 @@ H.6.12 PLUGIN_AUTH_FAILURE
        Secure Shell Protocol (SSH)' (better known by its wire id `keyboard-
        interactive').
 
-[PuTTY release 0.78]
+[PuTTY pre-release 0.79:2023-05-22.56b16bd]

+ 1 - 1
source/putty/doc/version.but

@@ -1 +1 @@
-\versionid PuTTY release 0.78
+\versionid PuTTY pre-release 0.79:2023-05-22.56b16bd

+ 3 - 2
source/putty/putty.h

@@ -363,11 +363,12 @@ typedef enum {
     MBT_NOTHING,
     MBT_LEFT, MBT_MIDDLE, MBT_RIGHT,   /* `raw' button designations */
     MBT_SELECT, MBT_EXTEND, MBT_PASTE, /* `cooked' button designations */
-    MBT_WHEEL_UP, MBT_WHEEL_DOWN       /* mouse wheel */
+    MBT_WHEEL_UP, MBT_WHEEL_DOWN,      /* vertical mouse wheel */
+    MBT_WHEEL_LEFT, MBT_WHEEL_RIGHT    /* horizontal mouse wheel */
 } Mouse_Button;
 
 typedef enum {
-    MA_NOTHING, MA_CLICK, MA_2CLK, MA_3CLK, MA_DRAG, MA_RELEASE
+    MA_NOTHING, MA_CLICK, MA_2CLK, MA_3CLK, MA_DRAG, MA_RELEASE, MA_MOVE
 } Mouse_Action;
 
 /* Keyboard modifiers -- keys the user is actually holding down */

+ 6 - 6
source/putty/settings.c

@@ -686,12 +686,12 @@ void save_open_settings(settings_w *sesskey, Conf *conf)
     write_setting_b(sesskey, "BellOverload", conf_get_bool(conf, CONF_bellovl));
     write_setting_i(sesskey, "BellOverloadN", conf_get_int(conf, CONF_bellovl_n));
     write_setting_i(sesskey, "BellOverloadT", conf_get_int(conf, CONF_bellovl_t)
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                     * 1000
 #endif
                     );
     write_setting_i(sesskey, "BellOverloadS", conf_get_int(conf, CONF_bellovl_s)
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                     * 1000
 #endif
                     );
@@ -1120,22 +1120,22 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
     gppb(sesskey, "BellOverload", true, conf, CONF_bellovl);
     gppi(sesskey, "BellOverloadN", 5, conf, CONF_bellovl_n);
     i = gppi_raw(sesskey, "BellOverloadT", 2*TICKSPERSEC
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                                    *1000
 #endif
                                    );
     conf_set_int(conf, CONF_bellovl_t, i
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                  / 1000
 #endif
                  );
     i = gppi_raw(sesskey, "BellOverloadS", 5*TICKSPERSEC
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                                    *1000
 #endif
                                    );
     conf_set_int(conf, CONF_bellovl_s, i
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                  / 1000
 #endif
                  );

+ 1 - 0
source/putty/ssh.h

@@ -1205,6 +1205,7 @@ extern const ssh2_macalg ssh_hmac_sha1_buggy;
 extern const ssh2_macalg ssh_hmac_sha1_96;
 extern const ssh2_macalg ssh_hmac_sha1_96_buggy;
 extern const ssh2_macalg ssh_hmac_sha256;
+extern const ssh2_macalg ssh_hmac_sha512;
 extern const ssh2_macalg ssh2_poly1305;
 extern const ssh2_macalg ssh2_aesgcm_mac;
 extern const ssh2_macalg ssh2_aesgcm_mac_sw;

+ 10 - 0
source/putty/ssh/common.c

@@ -742,6 +742,10 @@ size_t ssh_ppl_default_queued_data_size(PacketProtocolLayer *ppl)
     return ppl->out_pq->pqb.total_size;
 }
 
+void ssh_ppl_default_final_output(PacketProtocolLayer *ppl)
+{
+}
+
 static void ssh_ppl_prompts_callback(void *ctx)
 {
     ssh_ppl_process_queue((PacketProtocolLayer *)ctx);
@@ -1023,6 +1027,12 @@ SeatPromptResult verify_ssh_host_key(
             text, SDT_PARA, "If you trust this host, %s to add the key to "
             "%s's cache and carry on connecting.",
             pds->hk_accept_action, appname);
+        if (key && ssh_key_alg(key)->is_certificate) {
+            seat_dialog_text_append(
+                text, SDT_PARA, "(Storing this certified key in the cache "
+                "will NOT cause its certification authority to be trusted "
+                "for any other key or host.)");
+        }
         seat_dialog_text_append(
             text, SDT_PARA, "If you want to carry on connecting just once, "
             "without adding the key to the cache, %s.",

+ 1 - 0
source/putty/ssh/connection2.c

@@ -27,6 +27,7 @@ static const PacketProtocolLayerVtable ssh2_connection_vtable = {
     .special_cmd = ssh2_connection_special_cmd,
     .reconfigure = ssh2_connection_reconfigure,
     .queued_data_size = ssh_ppl_default_queued_data_size,
+    .final_output = ssh_ppl_default_final_output,
     .name = "ssh-connection",
 };
 

+ 6 - 0
source/putty/ssh/ppl.h

@@ -19,6 +19,7 @@ struct PacketProtocolLayerVtable {
         PacketProtocolLayer *ppl, SessionSpecialCode code, int arg);
     void (*reconfigure)(PacketProtocolLayer *ppl, Conf *conf);
     size_t (*queued_data_size)(PacketProtocolLayer *ppl);
+    void (*final_output)(PacketProtocolLayer *ppl);
 
     /* Protocol-level name of this layer. */
     const char *name;
@@ -68,6 +69,8 @@ static inline void ssh_ppl_reconfigure(PacketProtocolLayer *ppl, Conf *conf)
 { ppl->vt->reconfigure(ppl, conf); }
 static inline size_t ssh_ppl_queued_data_size(PacketProtocolLayer *ppl)
 { return ppl->vt->queued_data_size(ppl); }
+static inline void ssh_ppl_final_output(PacketProtocolLayer *ppl)
+{ ppl->vt->final_output(ppl); }
 
 static inline InteractionReadySeat ppl_get_iseat(PacketProtocolLayer *ppl)
 { return interactor_announce(ppl->interactor); }
@@ -93,6 +96,9 @@ void ssh_ppl_replace(PacketProtocolLayer *old, PacketProtocolLayer *new);
  * has other things to take into account as well. */
 size_t ssh_ppl_default_queued_data_size(PacketProtocolLayer *ppl);
 
+/* Default implementation of final_output which outputs nothing. */
+void ssh_ppl_default_final_output(PacketProtocolLayer *ppl);
+
 PacketProtocolLayer *ssh1_login_new(
     Conf *conf, const char *host, int port,
     PacketProtocolLayer *successor_layer);

+ 17 - 1
source/putty/ssh/ssh.c

@@ -474,6 +474,9 @@ void ssh_remote_error(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         /* Error messages sent by the remote don't count as clean exits */
         ssh->exitcode = 128;
 
@@ -492,6 +495,9 @@ void ssh_remote_eof(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         /* EOF from the remote, if we were expecting it, does count as
          * a clean exit */
         ssh->exitcode = 0;
@@ -515,6 +521,9 @@ void ssh_proto_error(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         ssh->exitcode = 128;
 
         ssh_bpp_queue_disconnect(ssh->bpp, msg,
@@ -532,6 +541,9 @@ void ssh_sw_abort(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         ssh->exitcode = 128;
 
         ssh_initiate_connection_close(ssh);
@@ -549,6 +561,9 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         /* Closing the connection due to user action, even if the
          * action is the user aborting during authentication prompts,
          * does count as a clean exit - except that this is also how
@@ -1038,7 +1053,8 @@ static void ssh_reconfig(Backend *be, Conf *conf)
     if (ssh->pinger)
         pinger_reconfig(ssh->pinger, ssh->conf, conf);
 
-    ssh_ppl_reconfigure(ssh->base_layer, conf);
+    if (ssh->base_layer)
+        ssh_ppl_reconfigure(ssh->base_layer, conf);
 
     conf_free(ssh->conf);
     ssh->conf = conf_copy(conf);

+ 12 - 1
source/putty/ssh/transport2.c

@@ -20,7 +20,8 @@ const struct ssh_signkey_with_user_pref_id ssh2_hostkey_algs[] = {
 };
 
 const static ssh2_macalg *const macs[] = {
-    &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
+    &ssh_hmac_sha256, &ssh_hmac_sha512,
+    &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
 };
 const static ssh2_macalg *const buggymacs[] = {
     &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5
@@ -79,6 +80,7 @@ static size_t ssh2_transport_queued_data_size(PacketProtocolLayer *ppl);
 static void ssh2_transport_set_max_data_size(struct ssh2_transport_state *s);
 static unsigned long sanitise_rekey_time(int rekey_time, unsigned long def);
 static void ssh2_transport_higher_layer_packet_callback(void *context);
+static void ssh2_transport_final_output(PacketProtocolLayer *ppl);
 
 static const PacketProtocolLayerVtable ssh2_transport_vtable = {
     .free = ssh2_transport_free,
@@ -87,6 +89,7 @@ static const PacketProtocolLayerVtable ssh2_transport_vtable = {
     .special_cmd = ssh2_transport_special_cmd,
     .reconfigure = ssh2_transport_reconfigure,
     .queued_data_size = ssh2_transport_queued_data_size,
+    .final_output = ssh2_transport_final_output,
     .name = NULL, /* no protocol name for this layer */
 };
 
@@ -2405,3 +2408,11 @@ static size_t ssh2_transport_queued_data_size(PacketProtocolLayer *ppl)
     return (ssh_ppl_default_queued_data_size(ppl) +
             ssh_ppl_queued_data_size(s->higher_layer));
 }
+
+static void ssh2_transport_final_output(PacketProtocolLayer *ppl)
+{
+    struct ssh2_transport_state *s =
+        container_of(ppl, struct ssh2_transport_state, ppl);
+
+    ssh_ppl_final_output(s->higher_layer);
+}

+ 83 - 50
source/putty/ssh/userauth2-client.c

@@ -132,7 +132,9 @@ static bool ssh2_userauth_ki_setup_prompts(
 static bool ssh2_userauth_ki_run_prompts(struct ssh2_userauth_state *s);
 static void ssh2_userauth_ki_write_responses(
     struct ssh2_userauth_state *s, BinarySink *bs);
+static void ssh2_userauth_final_output(PacketProtocolLayer *ppl);
 
+static void ssh2_userauth_print_banner(struct ssh2_userauth_state *s);
 static ptrlen workaround_rsa_sha2_cert_userauth(
     struct ssh2_userauth_state *s, ptrlen id);
 
@@ -143,6 +145,7 @@ static const PacketProtocolLayerVtable ssh2_userauth_vtable = {
     .special_cmd = ssh2_userauth_special_cmd,
     .reconfigure = ssh2_userauth_reconfigure,
     .queued_data_size = ssh_ppl_default_queued_data_size,
+    .final_output = ssh2_userauth_final_output,
     .name = "ssh-userauth",
 };
 
@@ -243,33 +246,38 @@ static void ssh2_userauth_free(PacketProtocolLayer *ppl)
     sfree(s);
 }
 
+static void ssh2_userauth_handle_banner_packet(struct ssh2_userauth_state *s,
+                                               PktIn *pktin)
+{
+    if (!s->show_banner)
+        return;
+
+    ptrlen string = get_string(pktin);
+    if (string.len > BANNER_LIMIT - bufchain_size(&s->banner))
+        string.len = BANNER_LIMIT - bufchain_size(&s->banner);
+
+    if (!s->banner_scc_initialised) {
+        s->banner_scc = seat_stripctrl_new(
+            s->ppl.seat, BinarySink_UPCAST(&s->banner_bs), SIC_BANNER);
+        if (s->banner_scc)
+            stripctrl_enable_line_limiting(s->banner_scc);
+        s->banner_scc_initialised = true;
+    }
+
+    if (s->banner_scc)
+        put_datapl(s->banner_scc, string);
+    else
+        put_datapl(&s->banner_bs, string);
+}
+
 static void ssh2_userauth_filter_queue(struct ssh2_userauth_state *s)
 {
     PktIn *pktin;
-    ptrlen string;
 
     while ((pktin = pq_peek(s->ppl.in_pq)) != NULL) {
         switch (pktin->type) {
           case SSH2_MSG_USERAUTH_BANNER:
-            if (!s->show_banner) {
-                pq_pop(s->ppl.in_pq);
-                break;
-            }
-
-            string = get_string(pktin);
-            if (string.len > BANNER_LIMIT - bufchain_size(&s->banner))
-                string.len = BANNER_LIMIT - bufchain_size(&s->banner);
-            if (!s->banner_scc_initialised) {
-                s->banner_scc = seat_stripctrl_new(
-                    s->ppl.seat, BinarySink_UPCAST(&s->banner_bs), SIC_BANNER);
-                if (s->banner_scc)
-                    stripctrl_enable_line_limiting(s->banner_scc);
-                s->banner_scc_initialised = true;
-            }
-            if (s->banner_scc)
-                put_datapl(s->banner_scc, string);
-            else
-                put_datapl(&s->banner_bs, string);
+            ssh2_userauth_handle_banner_packet(s, pktin);
             pq_pop(s->ppl.in_pq);
             break;
 
@@ -834,35 +842,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
              * point, but we still need to precede and follow it with
              * anti-spoofing header lines.
              */
-            if (bufchain_size(&s->banner) &&
-                (seat_verbose(s->ppl.seat) || seat_interactive(s->ppl.seat))) {
-                if (s->banner_scc) {
-                    seat_antispoof_msg(
-                        ppl_get_iseat(&s->ppl),
-                        "Pre-authentication banner message from server:");
-                    seat_set_trust_status(s->ppl.seat, false);
-                }
-
-                bool mid_line = false;
-                while (bufchain_size(&s->banner) > 0) {
-                    ptrlen data = bufchain_prefix(&s->banner);
-                    seat_banner_pl(ppl_get_iseat(&s->ppl), data);
-                    mid_line =
-                        (((const char *)data.ptr)[data.len-1] != '\n');
-                    bufchain_consume(&s->banner, data.len);
-                }
-                bufchain_clear(&s->banner);
-
-                if (mid_line)
-                    seat_banner_pl(ppl_get_iseat(&s->ppl),
-                                   PTRLEN_LITERAL("\r\n"));
-
-                if (s->banner_scc) {
-                    seat_set_trust_status(s->ppl.seat, true);
-                    seat_antispoof_msg(ppl_get_iseat(&s->ppl),
-                                       "End of banner message from server");
-                }
-            }
+            ssh2_userauth_print_banner(s);
 
             if (pktin && pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
                 ppl_logevent("Access granted");
@@ -2084,6 +2064,39 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
     crFinishV;
 }
 
+static void ssh2_userauth_print_banner(struct ssh2_userauth_state *s)
+{
+    if (bufchain_size(&s->banner) &&
+        (seat_verbose(s->ppl.seat) || seat_interactive(s->ppl.seat))) {
+        if (s->banner_scc) {
+            seat_antispoof_msg(
+                ppl_get_iseat(&s->ppl),
+                "Pre-authentication banner message from server:");
+            seat_set_trust_status(s->ppl.seat, false);
+        }
+
+        bool mid_line = false;
+        while (bufchain_size(&s->banner) > 0) {
+            ptrlen data = bufchain_prefix(&s->banner);
+            seat_banner_pl(ppl_get_iseat(&s->ppl), data);
+            mid_line =
+                (((const char *)data.ptr)[data.len-1] != '\n');
+            bufchain_consume(&s->banner, data.len);
+        }
+        bufchain_clear(&s->banner);
+
+        if (mid_line)
+            seat_banner_pl(ppl_get_iseat(&s->ppl),
+                           PTRLEN_LITERAL("\r\n"));
+
+        if (s->banner_scc) {
+            seat_set_trust_status(s->ppl.seat, true);
+            seat_antispoof_msg(ppl_get_iseat(&s->ppl),
+                               "End of banner message from server");
+        }
+    }
+}
+
 static bool ssh2_userauth_ki_setup_prompts(
     struct ssh2_userauth_state *s, BinarySource *src, bool plugin)
 {
@@ -2441,7 +2454,7 @@ static ptrlen workaround_rsa_sha2_cert_userauth(
 {
     if (!(s->ppl.remote_bugs & BUG_RSA_SHA2_CERT_USERAUTH))
         return id;
-/*
+    /*
      * No need to try to do this in a general way based on the
      * relations between ssh_keyalgs; we know there are a limited
      * number of affected versions of OpenSSH, so this doesn't have to
@@ -2581,3 +2594,23 @@ static void ssh2_userauth_reconfigure(PacketProtocolLayer *ppl, Conf *conf)
         container_of(ppl, struct ssh2_userauth_state, ppl);
     ssh_ppl_reconfigure(s->successor_layer, conf);
 }
+
+static void ssh2_userauth_final_output(PacketProtocolLayer *ppl)
+{
+    struct ssh2_userauth_state *s =
+        container_of(ppl, struct ssh2_userauth_state, ppl);
+
+    /*
+     * Check for any unconsumed banner packets that might have landed
+     * in our queue just before the server closed the connection, and
+     * add them to our banner buffer.
+     */
+    for (PktIn *pktin = pq_first(s->ppl.in_pq); pktin != NULL;
+         pktin = pq_next(s->ppl.in_pq, pktin)) {
+        if (pktin->type == SSH2_MSG_USERAUTH_BANNER)
+            ssh2_userauth_handle_banner_packet(s, pktin);
+    }
+
+    /* And now make sure we've shown the banner, before exiting */
+    ssh2_userauth_print_banner(s);
+}

+ 1 - 9
source/putty/sshpubk.c

@@ -516,24 +516,18 @@ static char *read_body(BinarySource *src)
 
 static bool read_blob(BinarySource *src, int nlines, BinarySink *bs)
 {
-    unsigned char *blob;
     char *line;
     int linelen;
     int i, j, k;
 
     /* We expect at most 64 base64 characters, ie 48 real bytes, per line. */
-    assert(nlines < MAX_KEY_BLOB_LINES);
-    blob = snewn(48 * nlines, unsigned char);
 
     for (i = 0; i < nlines; i++) {
         line = read_body(src);
-        if (!line) {
-            sfree(blob);
+        if (!line)
             return false;
-        }
         linelen = strlen(line);
         if (linelen % 4 != 0 || linelen > 64) {
-            sfree(blob);
             sfree(line);
             return false;
         }
@@ -542,14 +536,12 @@ static bool read_blob(BinarySource *src, int nlines, BinarySink *bs)
             k = base64_decode_atom(line + j, decoded);
             if (!k) {
                 sfree(line);
-                sfree(blob);
                 return false;
             }
             put_data(bs, decoded, k);
         }
         sfree(line);
     }
-    sfree(blob);
     return true;
 }
 

+ 4 - 4
source/putty/version.h

@@ -1,5 +1,5 @@
 /* Generated by automated build script */
-#define RELEASE 0.78
-#define TEXTVER "Release 0.78"
-#define SSHVER "-Release-0.78"
-#define BINARY_VERSION 0,78,0,0
+#define PRERELEASE 0.79
+#define TEXTVER "Pre-release 0.79:2023-05-22.56b16bd"
+#define SSHVER "-Prerelease-0.79:20230522.56b16bd"
+#define BINARY_VERSION 0,78,33974,0

+ 6 - 4
source/putty/windows/unicode.c

@@ -1071,9 +1071,11 @@ static int check_compose_internal(int first, int second, int recurse)
     if (recurse == 0) {
         nc = check_compose_internal(second, first, 1);
         if (nc == -1)
-            nc = check_compose_internal(toupper(first), toupper(second), 1);
+            nc = check_compose_internal(toupper((unsigned char)first),
+                                        toupper((unsigned char)second), 1);
         if (nc == -1)
-            nc = check_compose_internal(toupper(second), toupper(first), 1);
+            nc = check_compose_internal(toupper((unsigned char)second),
+                                        toupper((unsigned char)first), 1);
     }
     return nc;
 }
@@ -1097,9 +1099,9 @@ int decode_codepage(const char *cp_name)
         s = cp_name;
         d = cpi->name;
         for (;;) {
-            while (*s && !isalnum(*s) && *s != ':')
+            while (*s && !isalnum((unsigned char)*s) && *s != ':')
                 s++;
-            while (*d && !isalnum(*d) && *d != ':')
+            while (*d && !isalnum((unsigned char)*d) && *d != ':')
                 d++;
             if (*s == 0) {
                 codepage = cpi->codepage;