Переглянути джерело

Merge branch 'thirdparty_dev' into dev

# Conflicts:
#	source/putty/WINDOWS/winhsock.c
#	source/putty/WINDOWS/winnet.c
#	source/putty/WINDOWS/winpgntc.c
#	source/putty/WINDOWS/winstuff.h
#	source/putty/misc.c
#	source/putty/mpint.c
#	source/putty/mpint_i.h
#	source/putty/ssh.c
#	source/putty/ssh2userauth.c
#	source/putty/sshdss.c
#	source/putty/sshecc.c
#	source/putty/sshpubk.c
#	source/putty/sshrsa.c

Source commit: 90885833c1f338f612044c5cbadea7ef0c0e719c
Martin Prikryl 6 роки тому
батько
коміт
a6de10a805
53 змінених файлів з 826 додано та 585 видалено
  1. 5 5
      source/putty/agentf.c
  2. 4 4
      source/putty/be_misc.c
  3. 23 0
      source/putty/ecc.c
  4. 5 0
      source/putty/ecc.h
  5. 40 43
      source/putty/import.c
  6. 13 15
      source/putty/logging.c
  7. 4 3
      source/putty/mainchan.c
  8. 17 11
      source/putty/marshal.h
  9. 2 2
      source/putty/misc.c
  10. 117 94
      source/putty/misc.h
  11. 41 12
      source/putty/mpint.c
  12. 8 0
      source/putty/mpint.h
  13. 1 1
      source/putty/mpint_i.h
  14. 6 5
      source/putty/network.h
  15. 3 2
      source/putty/nullplug.c
  16. 6 4
      source/putty/portfwd.c
  17. 36 39
      source/putty/proxy.c
  18. 1 4
      source/putty/proxy.h
  19. 11 8
      source/putty/putty.h
  20. 67 28
      source/putty/ssh.c
  21. 9 3
      source/putty/ssh.h
  22. 3 3
      source/putty/ssh1bpp.c
  23. 1 1
      source/putty/ssh1censor.c
  24. 2 2
      source/putty/ssh1connection-client.c
  25. 15 17
      source/putty/ssh1connection.c
  26. 1 2
      source/putty/ssh1login.c
  27. 1 1
      source/putty/ssh2bpp-bare.c
  28. 5 5
      source/putty/ssh2bpp.c
  29. 1 1
      source/putty/ssh2censor.c
  30. 26 31
      source/putty/ssh2connection.c
  31. 1 2
      source/putty/ssh2kex-client.c
  32. 2 2
      source/putty/ssh2transport.c
  33. 29 14
      source/putty/ssh2userauth.c
  34. 1 1
      source/putty/sshaes.c
  35. 3 3
      source/putty/sshchan.h
  36. 8 3
      source/putty/sshcommon.c
  37. 20 6
      source/putty/sshdss.c
  38. 24 13
      source/putty/sshecc.c
  39. 6 0
      source/putty/sshprng.c
  40. 7 7
      source/putty/sshpubk.c
  41. 6 0
      source/putty/sshrand.c
  42. 125 78
      source/putty/sshrsa.c
  43. 2 1
      source/putty/sshsh256.c
  44. 2 1
      source/putty/sshsha.c
  45. 13 13
      source/putty/sshshare.c
  46. 16 17
      source/putty/sshverstring.c
  47. 13 15
      source/putty/utils.c
  48. 11 14
      source/putty/windows/winhandl.c
  49. 15 18
      source/putty/windows/winhsock.c
  50. 12 8
      source/putty/windows/winnet.c
  51. 1 1
      source/putty/windows/winpgntc.c
  52. 7 5
      source/putty/windows/winstuff.h
  53. 28 17
      source/putty/x11fwd.c

+ 5 - 5
source/putty/agentf.c

@@ -39,7 +39,7 @@ static void agentf_callback(void *vctx, void *reply, int replylen);
 
 static void agentf_try_forward(agentf *af)
 {
-    unsigned datalen, length;
+    size_t datalen, length;
     strbuf *message;
     unsigned char msglen[4];
     void *reply;
@@ -72,7 +72,7 @@ static void agentf_try_forward(agentf *af)
             break;         /* not even a length field available yet */
 
         bufchain_fetch(&af->inbuffer, msglen, 4);
-        length = GET_32BIT(msglen);
+        length = GET_32BIT_MSB_FIRST(msglen);
 
         if (length > AGENT_MAX_MSGLEN-4) {
             /*
@@ -142,7 +142,7 @@ static void agentf_callback(void *vctx, void *reply, int replylen)
 }
 
 static void agentf_free(Channel *chan);
-static int agentf_send(Channel *chan, bool is_stderr, const void *, int);
+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);
@@ -196,8 +196,8 @@ static void agentf_free(Channel *chan)
     sfree(af);
 }
 
-static int agentf_send(Channel *chan, bool is_stderr,
-                       const void *data, int length)
+static size_t agentf_send(Channel *chan, bool is_stderr,
+                          const void *data, size_t length)
 {
     pinitassert(chan->vt == &agentf_channelvt);
     agentf *af = container_of(chan, agentf, chan);

+ 4 - 4
source/putty/be_misc.c

@@ -59,11 +59,10 @@ void backend_socket_log(Seat *seat, LogContext *logctx,
     }
 }
 
-void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, int len)
+void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, size_t len)
 {
     const char *data = (const char *)vdata;
-    int pos = 0;
-    int msglen;
+    size_t pos = 0;
     const char *nlpos;
     char *msg, *fullmsg;
 
@@ -88,7 +87,8 @@ void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, int len)
         /*
          * Collect the resulting line of data and pass it to plug_log.
          */
-        msglen = bufchain_size(buf);
+        size_t msglen = bufchain_size(buf);
+        assert(msglen < ~(size_t)0);
         msg = snewn(msglen+1, char);
         bufchain_fetch(buf, msg, msglen);
         bufchain_consume(buf, msglen);

+ 23 - 0
source/putty/ecc.c

@@ -112,6 +112,14 @@ WeierstrassPoint *ecc_weierstrass_point_new_identity(WeierstrassCurve *wc)
     return wp;
 }
 
+void ecc_weierstrass_point_copy_into(
+    WeierstrassPoint *dest, WeierstrassPoint *src)
+{
+    mp_copy_into(dest->X, src->X);
+    mp_copy_into(dest->Y, src->Y);
+    mp_copy_into(dest->Z, src->Z);
+}
+
 WeierstrassPoint *ecc_weierstrass_point_copy(WeierstrassPoint *orig)
 {
     WeierstrassPoint *wp = ecc_weierstrass_point_new_empty(orig->wc);
@@ -635,6 +643,13 @@ MontgomeryPoint *ecc_montgomery_point_new(MontgomeryCurve *mc, mp_int *x)
     return mp;
 }
 
+void ecc_montgomery_point_copy_into(
+    MontgomeryPoint *dest, MontgomeryPoint *src)
+{
+    mp_copy_into(dest->X, src->X);
+    mp_copy_into(dest->Z, src->Z);
+}
+
 MontgomeryPoint *ecc_montgomery_point_copy(MontgomeryPoint *orig)
 {
     MontgomeryPoint *mp = ecc_montgomery_point_new_empty(orig->mc);
@@ -936,6 +951,14 @@ EdwardsPoint *ecc_edwards_point_new(
         ec, monty_import(ec->mc, x), monty_import(ec->mc, y));
 }
 
+void ecc_edwards_point_copy_into(EdwardsPoint *dest, EdwardsPoint *src)
+{
+    mp_copy_into(dest->X, src->X);
+    mp_copy_into(dest->Y, src->Y);
+    mp_copy_into(dest->Z, src->Z);
+    mp_copy_into(dest->T, src->T);
+}
+
 EdwardsPoint *ecc_edwards_point_copy(EdwardsPoint *orig)
 {
     EdwardsPoint *ep = ecc_edwards_point_new_empty(orig->ec);

+ 5 - 0
source/putty/ecc.h

@@ -61,6 +61,8 @@ 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);
 
@@ -143,6 +145,8 @@ void ecc_montgomery_curve_free(MontgomeryCurve *);
  * 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);
 
@@ -213,6 +217,7 @@ 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);
 

+ 40 - 43
source/putty/import.c

@@ -281,10 +281,10 @@ struct openssh_pem_key {
     strbuf *keyblob;
 };
 
-void BinarySink_put_mp_ssh2_from_string(
-    BinarySink *bs, const void *bytesv, int nbytes)
+void BinarySink_put_mp_ssh2_from_string(BinarySink *bs, ptrlen str)
 {
-    const unsigned char *bytes = (const unsigned char *)bytesv;
+    const unsigned char *bytes = (const unsigned char *)str.ptr;
+    size_t nbytes = str.len;
     while (nbytes > 0 && bytes[0] == 0) {
         nbytes--;
         bytes++;
@@ -297,8 +297,8 @@ void BinarySink_put_mp_ssh2_from_string(
     }
     put_data(bs, bytes, nbytes);
 }
-#define put_mp_ssh2_from_string(bs, val, len) \
-    BinarySink_put_mp_ssh2_from_string(BinarySink_UPCAST(bs), val, len)
+#define put_mp_ssh2_from_string(bs, str) \
+    BinarySink_put_mp_ssh2_from_string(BinarySink_UPCAST(bs), str)
 
 static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename,
                                                     const char **errmsg_p)
@@ -537,8 +537,6 @@ static ssh2_userkey *openssh_pem_read(
     const char *errmsg;
     strbuf *blob = strbuf_new();
     int privptr = 0, publen;
-    const char *modptr = NULL;
-    int modlen = 0;
 
     if (!key)
 	return NULL;
@@ -600,7 +598,7 @@ static ssh2_userkey *openssh_pem_read(
 
         /* Reinitialise our BinarySource to parse just the inside of that
          * SEQUENCE. */
-        BinarySource_BARE_INIT(src, seq.data.ptr, seq.data.len);
+        BinarySource_BARE_INIT_PL(src, seq.data);
     }
 
     /* Expect a load of INTEGERs. */
@@ -625,11 +623,11 @@ static ssh2_userkey *openssh_pem_read(
         sub1 = get_ber(src);
 
         /* Now look inside sub0 for the curve OID */
-        BinarySource_BARE_INIT(src, sub0.data.ptr, sub0.data.len);
+        BinarySource_BARE_INIT_PL(src, sub0.data);
         oid = get_ber(src);
 
         /* And inside sub1 for the public-key BIT STRING */
-        BinarySource_BARE_INIT(src, sub1.data.ptr, sub1.data.len);
+        BinarySource_BARE_INIT_PL(src, sub1.data);
         pubkey = get_ber(src);
 
         if (get_err(src) ||
@@ -669,7 +667,7 @@ static ssh2_userkey *openssh_pem_read(
         put_stringz(blob, curve->name);
         put_stringpl(blob, pubkey.data);
         publen = blob->len;
-        put_mp_ssh2_from_string(blob, privkey.data.ptr, privkey.data.len);
+        put_mp_ssh2_from_string(blob, privkey.data);
 
         retkey->key = ssh_key_new_priv(
             alg, make_ptrlen(blob->u, publen),
@@ -685,6 +683,8 @@ static ssh2_userkey *openssh_pem_read(
 
         put_stringz(blob, key->keytype == OP_DSA ? "ssh-dss" : "ssh-rsa");
 
+        ptrlen rsa_modulus = PTRLEN_LITERAL("");
+
         for (i = 0; i < num_integers; i++) {
             ber_item integer = get_ber(src);
 
@@ -712,13 +712,11 @@ static ssh2_userkey *openssh_pem_read(
                  */
                 if (i == 1) {
                     /* Save the details for after we deal with number 2. */
-                    modptr = integer.data.ptr;
-                    modlen = integer.data.len;
+                    rsa_modulus = integer.data;
                 } else if (i != 6 && i != 7) {
-                    put_mp_ssh2_from_string(blob, integer.data.ptr,
-                                            integer.data.len);
+                    put_mp_ssh2_from_string(blob, integer.data);
                     if (i == 2) {
-                        put_mp_ssh2_from_string(blob, modptr, modlen);
+                        put_mp_ssh2_from_string(blob, rsa_modulus);
                         privptr = blob->len;
                     }
                 }
@@ -727,8 +725,7 @@ static ssh2_userkey *openssh_pem_read(
                  * Integers 1-4 go into the public blob; integer 5 goes
                  * into the private blob.
                  */
-                put_mp_ssh2_from_string(blob, integer.data.ptr,
-                                        integer.data.len);
+                put_mp_ssh2_from_string(blob, integer.data);
                 if (i == 4)
                     privptr = blob->len;
             }
@@ -1229,7 +1226,7 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename,
         {
             BinarySource opts[1];
 
-            BinarySource_BARE_INIT(opts, str.ptr, str.len);
+            BinarySource_BARE_INIT_PL(opts, str);
             ret->kdfopts.bcrypt.salt = get_string(opts);
             ret->kdfopts.bcrypt.rounds = get_uint32(opts);
 
@@ -1398,7 +1395,7 @@ static ssh2_userkey *openssh_new_read(
      * Now parse the entire encrypted section, and extract the key
      * identified by key_wanted.
      */
-    BinarySource_BARE_INIT(src, key->private.ptr, key->private.len);
+    BinarySource_BARE_INIT_PL(src, key->private);
 
     checkint = get_uint32(src);
     if (get_uint32(src) != checkint || get_err(src)) {
@@ -1918,10 +1915,10 @@ static bool sshcom_encrypted(const Filename *filename, char **comment)
     return answer;
 }
 
-void BinarySink_put_mp_sshcom_from_string(
-    BinarySink *bs, const void *bytesv, int nbytes)
+void BinarySink_put_mp_sshcom_from_string(BinarySink *bs, ptrlen str)
 {
-    const unsigned char *bytes = (const unsigned char *)bytesv;
+    const unsigned char *bytes = (const unsigned char *)str.ptr;
+    size_t nbytes = str.len;
     int bits = nbytes * 8 - 1;
 
     while (bits > 0) {
@@ -1935,8 +1932,8 @@ void BinarySink_put_mp_sshcom_from_string(
     put_data(bs, bytes, nbytes);
 }
 
-#define put_mp_sshcom_from_string(bs, val, len) \
-    BinarySink_put_mp_sshcom_from_string(BinarySink_UPCAST(bs), val, len)
+#define put_mp_sshcom_from_string(bs, str) \
+    BinarySink_put_mp_sshcom_from_string(BinarySink_UPCAST(bs), str)
 
 static ptrlen BinarySource_get_mp_sshcom_as_string(BinarySource *src)
 {
@@ -2077,13 +2074,13 @@ static ssh2_userkey *sshcom_read(
      * Expect the ciphertext to be formatted as a containing string,
      * and reinitialise src to start parsing the inside of that string.
      */
-    BinarySource_BARE_INIT(src, ciphertext.ptr, ciphertext.len);
+    BinarySource_BARE_INIT_PL(src, ciphertext);
     str = get_string(src);
     if (get_err(src)) {
         errmsg = "containing string was ill-formed";
         goto error;
     }
-    BinarySource_BARE_INIT(src, str.ptr, str.len);
+    BinarySource_BARE_INIT_PL(src, str);
 
     /*
      * Now we break down into RSA versus DSA. In either case we'll
@@ -2107,13 +2104,13 @@ static ssh2_userkey *sshcom_read(
 
         alg = &ssh_rsa;
         put_stringz(blob, "ssh-rsa");
-        put_mp_ssh2_from_string(blob, e.ptr, e.len);
-        put_mp_ssh2_from_string(blob, n.ptr, n.len);
+        put_mp_ssh2_from_string(blob, e);
+        put_mp_ssh2_from_string(blob, n);
         publen = blob->len;
-        put_mp_ssh2_from_string(blob, d.ptr, d.len);
-        put_mp_ssh2_from_string(blob, q.ptr, q.len);
-        put_mp_ssh2_from_string(blob, p.ptr, p.len);
-        put_mp_ssh2_from_string(blob, u.ptr, u.len);
+        put_mp_ssh2_from_string(blob, d);
+        put_mp_ssh2_from_string(blob, q);
+        put_mp_ssh2_from_string(blob, p);
+        put_mp_ssh2_from_string(blob, u);
     } else {
         ptrlen p, q, g, x, y;
 
@@ -2135,12 +2132,12 @@ static ssh2_userkey *sshcom_read(
 
         alg = &ssh_dss;
         put_stringz(blob, "ssh-dss");
-        put_mp_ssh2_from_string(blob, p.ptr, p.len);
-        put_mp_ssh2_from_string(blob, q.ptr, q.len);
-        put_mp_ssh2_from_string(blob, g.ptr, g.len);
-        put_mp_ssh2_from_string(blob, y.ptr, y.len);
+        put_mp_ssh2_from_string(blob, p);
+        put_mp_ssh2_from_string(blob, q);
+        put_mp_ssh2_from_string(blob, g);
+        put_mp_ssh2_from_string(blob, y);
         publen = blob->len;
-        put_mp_ssh2_from_string(blob, x.ptr, x.len);
+        put_mp_ssh2_from_string(blob, x);
     }
 
     retkey = snew(ssh2_userkey);
@@ -2271,10 +2268,10 @@ static bool sshcom_write(
     if (initial_zero)
         put_uint32(outblob, 0);
     for (i = 0; i < nnumbers; i++)
-	put_mp_sshcom_from_string(outblob, numbers[i].ptr, numbers[i].len);
+	put_mp_sshcom_from_string(outblob, numbers[i]);
     /* Now wrap up the encrypted payload. */
-    PUT_32BIT(outblob->s + lenpos + 4,
-              outblob->len - (lenpos + 8));
+    PUT_32BIT_MSB_FIRST(outblob->s + lenpos + 4,
+                        outblob->len - (lenpos + 8));
     /* Pad encrypted blob to a multiple of cipher block size. */
     if (passphrase) {
 	int padding = -(outblob->len - (lenpos+4)) & 7;
@@ -2286,9 +2283,9 @@ static bool sshcom_write(
     cipherlen = outblob->len - (lenpos + 4);
     assert(!passphrase || cipherlen % 8 == 0);
     /* Wrap up the encrypted blob string. */
-    PUT_32BIT(outblob->s + lenpos, cipherlen);
+    PUT_32BIT_MSB_FIRST(outblob->s + lenpos, cipherlen);
     /* And finally fill in the total length field. */
-    PUT_32BIT(outblob->s + 4, outblob->len);
+    PUT_32BIT_MSB_FIRST(outblob->s + 4, outblob->len);
 
     /*
      * Encrypt the key.

+ 13 - 15
source/putty/logging.c

@@ -31,7 +31,7 @@ static Filename *xlatlognam(Filename *s, char *hostname, int port,
  * isn't open, buffering data if it's in the process of being
  * opened asynchronously, etc.
  */
-static void logwrite(LogContext *ctx, void *data, int len)
+static void logwrite(LogContext *ctx, ptrlen data)
 {
     /*
      * In state L_CLOSED, we call logfopen, which will set the state
@@ -42,10 +42,10 @@ static void logwrite(LogContext *ctx, void *data, int len)
 	logfopen(ctx);
 
     if (ctx->state == L_OPENING) {
-	bufchain_add(&ctx->queue, data, len);
+	bufchain_add(&ctx->queue, data.ptr, data.len);
     } else if (ctx->state == L_OPEN) {
 	assert(ctx->lgfp);
-	if (fwrite(data, 1, len, ctx->lgfp) < (size_t)len) {
+	if (fwrite(data.ptr, 1, data.len, ctx->lgfp) < data.len) {
 	    logfclose(ctx);
 	    ctx->state = L_ERROR;
             lp_eventlog(ctx->lp, "Disabled writing session log "
@@ -67,7 +67,7 @@ static void logprintf(LogContext *ctx, const char *fmt, ...)
     data = dupvprintf(fmt, ap);
     va_end(ap);
 
-    logwrite(ctx, data, strlen(data));
+    logwrite(ctx, ptrlen_from_asciz(data));
     sfree(data);
 }
 
@@ -137,11 +137,9 @@ static void logfopen_callback(void *vctx, int mode)
      */
     assert(ctx->state != L_OPENING);   /* make _sure_ it won't be requeued */
     while (bufchain_size(&ctx->queue)) {
-	void *data;
-	int len;
-	bufchain_prefix(&ctx->queue, &data, &len);
-	logwrite(ctx, data, len);
-	bufchain_consume(&ctx->queue, len);
+        ptrlen data = bufchain_prefix(&ctx->queue);
+	logwrite(ctx, data);
+	bufchain_consume(&ctx->queue, data.len);
     }
     logflush(ctx);
 }
@@ -205,7 +203,7 @@ void logtraffic(LogContext *ctx, unsigned char c, int logmode)
 {
     if (ctx->logtype > 0) {
 	if (ctx->logtype == logmode)
-	    logwrite(ctx, &c, 1);
+	    logwrite(ctx, make_ptrlen(&c, 1));
     }
 }
 
@@ -276,13 +274,13 @@ void logeventf(LogContext *ctx, const char *fmt, ...)
  * Set of blanking areas must be in increasing order.
  */
 void log_packet(LogContext *ctx, int direction, int type,
-		const char *texttype, const void *data, int len,
+		const char *texttype, const void *data, size_t len,
 		int n_blanks, const struct logblank_t *blanks,
 		const unsigned long *seq,
                 unsigned downstream_id, const char *additional_log_text)
 {
-    char dumpdata[80], smalldata[5];
-    int p = 0, b = 0, omitted = 0;
+    char dumpdata[128], smalldata[5];
+    size_t p = 0, b = 0, omitted = 0;
     int output_pos = 0; /* NZ if pending output in dumpdata */
 
     if (!(ctx->logtype == LGTYP_SSHRAW ||
@@ -354,7 +352,7 @@ 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, "  %08x%*s\r\n", p-(p%16), 1+3*16+2+16, "");
+	    sprintf(dumpdata, "  %08zx%*s\r\n", p-(p%16), 1+3*16+2+16, "");
 
 	/* Deal with the current byte. */
 	if (blktype == PKTLOG_OMIT) {
@@ -380,7 +378,7 @@ void log_packet(LogContext *ctx, int direction, int type,
 	if (((p % 16) == 0) || (p == len) || omitted) {
 	    if (output_pos) {
 		strcpy(dumpdata + 10+1+3*16+2+output_pos, "\r\n");
-		logwrite(ctx, dumpdata, strlen(dumpdata));
+		logwrite(ctx, ptrlen_from_asciz(dumpdata));
 		output_pos = 0;
 	    }
 	}

+ 4 - 3
source/putty/mainchan.c

@@ -14,7 +14,8 @@
 static void mainchan_free(Channel *chan);
 static void mainchan_open_confirmation(Channel *chan);
 static void mainchan_open_failure(Channel *chan, const char *errtext);
-static int mainchan_send(Channel *chan, bool is_stderr, const void *, int);
+static size_t mainchan_send(
+    Channel *chan, bool is_stderr, const void *, size_t);
 static void mainchan_send_eof(Channel *chan);
 static void mainchan_set_input_wanted(Channel *chan, bool wanted);
 static char *mainchan_log_close_msg(Channel *chan);
@@ -362,8 +363,8 @@ static void mainchan_open_failure(Channel *chan, const char *errtext)
     queue_toplevel_callback(get_log_callback_set(mc->cl->logctx), mainchan_open_failure_abort, ctx);
 }
 
-static int mainchan_send(Channel *chan, bool is_stderr,
-                         const void *data, int length)
+static size_t mainchan_send(Channel *chan, bool is_stderr,
+                         const void *data, size_t length)
 {
     pinitassert(chan->vt == &mainchan_channelvt);
     mainchan *mc = container_of(chan, mainchan, chan);

+ 17 - 11
source/putty/marshal.h

@@ -227,19 +227,25 @@ struct BinarySource {
  * Implementation macros, similar to BinarySink.
  */
 #define BinarySource_IMPLEMENTATION BinarySource binarysource_[1]
-#define BinarySource_INIT__(obj, data_, len_)    \
-    ((obj)->data = (data_),                             \
-     (obj)->len = (len_),                               \
-     (obj)->pos = 0,                                    \
-     (obj)->err = BSE_NO_ERROR,                         \
-     (obj)->binarysource_ = (obj))
-#define BinarySource_BARE_INIT(obj, data_, len_)                \
+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, data_, len_))
-#define BinarySource_INIT(obj, data_, len_)                             \
+              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), data_, len_))
-#define BinarySource_DOWNCAST(object, type)                               \
+              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)                                       \

+ 2 - 2
source/putty/misc.c

@@ -317,8 +317,8 @@ const char * get_putty_version()
 }
 
 #endif
-int nullseat_output(
-    Seat *seat, bool is_stderr, const void *data, int len) { return 0; }
+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; }

+ 117 - 94
source/putty/misc.h

@@ -95,7 +95,7 @@ int base64_decode_atom(const char *atom, unsigned char *out);
 struct bufchain_granule;
 struct bufchain_tag {
     struct bufchain_granule *head, *tail;
-    int buffersize;		       /* current amount of buffered data */
+    size_t buffersize;           /* current amount of buffered data */
 
     void (*queue_idempotent_callback)(IdempotentCallback *ic);
     IdempotentCallback *ic;
@@ -103,14 +103,14 @@ struct bufchain_tag {
 
 void bufchain_init(bufchain *ch);
 void bufchain_clear(bufchain *ch);
-int bufchain_size(bufchain *ch);
-void bufchain_add(bufchain *ch, const void *data, int len);
-void bufchain_prefix(bufchain *ch, void **data, int *len);
-void bufchain_consume(bufchain *ch, int len);
-void bufchain_fetch(bufchain *ch, void *data, int len);
-void bufchain_fetch_consume(bufchain *ch, void *data, int len);
-bool bufchain_try_fetch_consume(bufchain *ch, void *data, int len);
-int bufchain_fetch_consume_up_to(bufchain *ch, void *data, int len);
+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));
@@ -125,7 +125,7 @@ static inline void bufchain_set_callback(bufchain *ch, IdempotentCallback *ic)
     bufchain_set_callback_inner(ch, ic, queue_idempotent_callback);
 }
 
-void sanitise_term_data(bufchain *out, const void *vdata, int len);
+void sanitise_term_data(bufchain *out, const void *vdata, size_t len);
 
 bool validate_manual_hostkey(char *key);
 
@@ -170,6 +170,8 @@ int string_length_for_printf(size_t);
  * 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
@@ -244,94 +246,115 @@ void debug_memdump(const void *buf, int len, bool L);
 #define max(x,y) ( (x) > (y) ? (x) : (y) )
 #endif
 
-#define GET_64BIT_LSB_FIRST(cp) \
-  (((uint64_t)(unsigned char)(cp)[0]) | \
-  ((uint64_t)(unsigned char)(cp)[1] << 8) | \
-  ((uint64_t)(unsigned char)(cp)[2] << 16) | \
-  ((uint64_t)(unsigned char)(cp)[3] << 24) | \
-  ((uint64_t)(unsigned char)(cp)[4] << 32) | \
-  ((uint64_t)(unsigned char)(cp)[5] << 40) | \
-  ((uint64_t)(unsigned char)(cp)[6] << 48) | \
-  ((uint64_t)(unsigned char)(cp)[7] << 56))
-
-#define PUT_64BIT_LSB_FIRST(cp, value) ( \
-  (cp)[0] = (unsigned char)(value), \
-  (cp)[1] = (unsigned char)((value) >> 8), \
-  (cp)[2] = (unsigned char)((value) >> 16), \
-  (cp)[3] = (unsigned char)((value) >> 24), \
-  (cp)[4] = (unsigned char)((value) >> 32), \
-  (cp)[5] = (unsigned char)((value) >> 40), \
-  (cp)[6] = (unsigned char)((value) >> 48), \
-  (cp)[7] = (unsigned char)((value) >> 56) )
-
-#define GET_32BIT_LSB_FIRST(cp) \
-  (((uint32_t)(unsigned char)(cp)[0]) | \
-  ((uint32_t)(unsigned char)(cp)[1] << 8) | \
-  ((uint32_t)(unsigned char)(cp)[2] << 16) | \
-  ((uint32_t)(unsigned char)(cp)[3] << 24))
-
-#define PUT_32BIT_LSB_FIRST(cp, value) ( \
-  (cp)[0] = (unsigned char)(value), \
-  (cp)[1] = (unsigned char)((value) >> 8), \
-  (cp)[2] = (unsigned char)((value) >> 16), \
-  (cp)[3] = (unsigned char)((value) >> 24) )
-
-#define GET_16BIT_LSB_FIRST(cp) \
-  (((unsigned long)(unsigned char)(cp)[0]) | \
-  ((unsigned long)(unsigned char)(cp)[1] << 8))
-
-#define PUT_16BIT_LSB_FIRST(cp, value) ( \
-  (cp)[0] = (unsigned char)(value), \
-  (cp)[1] = (unsigned char)((value) >> 8) )
-
-#define GET_32BIT_MSB_FIRST(cp) \
-  (((uint32_t)(unsigned char)(cp)[0] << 24) | \
-  ((uint32_t)(unsigned char)(cp)[1] << 16) | \
-  ((uint32_t)(unsigned char)(cp)[2] << 8) | \
-  ((uint32_t)(unsigned char)(cp)[3]))
-
-#define GET_32BIT(cp) GET_32BIT_MSB_FIRST(cp)
-
-#define PUT_32BIT_MSB_FIRST(cp, value) ( \
-  (cp)[0] = (unsigned char)((value) >> 24), \
-  (cp)[1] = (unsigned char)((value) >> 16), \
-  (cp)[2] = (unsigned char)((value) >> 8), \
-  (cp)[3] = (unsigned char)(value) )
-
-#define PUT_32BIT(cp, value) PUT_32BIT_MSB_FIRST(cp, value)
-
-#define GET_64BIT_MSB_FIRST(cp) \
-  (((uint64_t)(unsigned char)(cp)[0] << 56) | \
-  ((uint64_t)(unsigned char)(cp)[1] << 48) | \
-  ((uint64_t)(unsigned char)(cp)[2] << 40) | \
-  ((uint64_t)(unsigned char)(cp)[3] << 32) | \
-  ((uint64_t)(unsigned char)(cp)[4] << 24) | \
-  ((uint64_t)(unsigned char)(cp)[5] << 16) | \
-  ((uint64_t)(unsigned char)(cp)[6] << 8) | \
-  ((uint64_t)(unsigned char)(cp)[7]))
-
-#define PUT_64BIT_MSB_FIRST(cp, value) ( \
-  (cp)[0] = (unsigned char)((value) >> 56), \
-  (cp)[1] = (unsigned char)((value) >> 48), \
-  (cp)[2] = (unsigned char)((value) >> 40), \
-  (cp)[3] = (unsigned char)((value) >> 32), \
-  (cp)[4] = (unsigned char)((value) >> 24), \
-  (cp)[5] = (unsigned char)((value) >> 16), \
-  (cp)[6] = (unsigned char)((value) >> 8), \
-  (cp)[7] = (unsigned char)(value) )
-
-#define GET_16BIT_MSB_FIRST(cp) \
-  (((unsigned long)(unsigned char)(cp)[0] << 8) | \
-  ((unsigned long)(unsigned char)(cp)[1]))
-
-#define PUT_16BIT_MSB_FIRST(cp, value) ( \
-  (cp)[0] = (unsigned char)((value) >> 8), \
-  (cp)[1] = (unsigned char)(value) )
+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] = value;
+    p[1] = (value) >> 8;
+    p[2] = (value) >> 16;
+    p[3] = (value) >> 24;
+    p[4] = (value) >> 32;
+    p[5] = (value) >> 40;
+    p[6] = (value) >> 48;
+    p[7] = (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] = value;
+    p[1] = (value) >> 8;
+    p[2] = (value) >> 16;
+    p[3] = (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] = value;
+    p[1] = (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] = value;
+    p[6] = (value) >> 8;
+    p[5] = (value) >> 16;
+    p[4] = (value) >> 24;
+    p[3] = (value) >> 32;
+    p[2] = (value) >> 40;
+    p[1] = (value) >> 48;
+    p[0] = (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] = value;
+    p[2] = (value) >> 8;
+    p[1] = (value) >> 16;
+    p[0] = (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] = value;
+    p[0] = (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)) */
-#define NULLTOEMPTY(s) ((s)?(s):"")
+static inline const char *NULLTOEMPTY(const char *s)
+{
+    return s ? s : "";
+}
 
 #ifdef MPEXT
 // Recent PuTTY code uses C99 standard that allows code before initialization.

+ 41 - 12
source/putty/mpint.c

@@ -120,7 +120,7 @@ void mp_select_into(mp_int *dest, mp_int *src0, mp_int *src1,
 void mp_cond_swap(mp_int *x0, mp_int *x1, unsigned swap)
 {
     pinitassert(x0->nw == x1->nw);
-    BignumInt mask = -(BignumInt)(1 & swap);
+    volatile BignumInt mask = -(BignumInt)(1 & swap);
     size_t i; // WINSCP
     for (i = 0; i < x0->nw; i++) {
         BignumInt diff = (x0->w[i] ^ x1->w[i]) & mask;
@@ -731,6 +731,38 @@ void mp_sub_into(mp_int *r, mp_int *a, mp_int *b)
     mp_add_masked_into(r->w, r->nw, a, b, ~(BignumInt)0, ~(BignumInt)0, 1);
 }
 
+void mp_and_into(mp_int *r, mp_int *a, mp_int *b)
+{
+    for (size_t i = 0; i < r->nw; i++) {
+        BignumInt aword = mp_word(a, i), bword = mp_word(b, i);
+        r->w[i] = aword & bword;
+    }
+}
+
+void mp_or_into(mp_int *r, mp_int *a, mp_int *b)
+{
+    for (size_t i = 0; i < r->nw; i++) {
+        BignumInt aword = mp_word(a, i), bword = mp_word(b, i);
+        r->w[i] = aword | bword;
+    }
+}
+
+void mp_xor_into(mp_int *r, mp_int *a, mp_int *b)
+{
+    for (size_t i = 0; i < r->nw; i++) {
+        BignumInt aword = mp_word(a, i), bword = mp_word(b, i);
+        r->w[i] = aword ^ bword;
+    }
+}
+
+void mp_bic_into(mp_int *r, mp_int *a, mp_int *b)
+{
+    for (size_t i = 0; i < r->nw; i++) {
+        BignumInt aword = mp_word(a, i), bword = mp_word(b, i);
+        r->w[i] = aword & ~bword;
+    }
+}
+
 static void mp_cond_negate(mp_int *r, mp_int *x, unsigned yes)
 {
     BignumCarry carry = yes;
@@ -1467,21 +1499,19 @@ mp_int *monty_invert(MontyContext *mc, mp_int *x)
 
 /*
  * Importing a number into Montgomery representation involves
- * multiplying it by r and reducing mod m. We could do this using the
- * straightforward mp_modmul, but since we have the machinery to avoid
- * division, why don't we use it? If we multiply the number not by r
- * itself, but by the residue of r^2 mod m, then we can do an actual
- * Montgomery reduction to reduce the result and remove the extra
- * factor of r.
+ * multiplying it by r and reducing mod m. We use the general-purpose
+ * mp_modmul for this, in case the input number is out of range.
  */
-void monty_import_into(MontyContext *mc, mp_int *r, mp_int *x)
+mp_int *monty_import(MontyContext *mc, mp_int *x)
 {
-    monty_mul_into(mc, r, x, mc->powers_of_r_mod_m[1]);
+    return mp_modmul(x, mc->powers_of_r_mod_m[0], mc->m);
 }
 
-mp_int *monty_import(MontyContext *mc, mp_int *x)
+void monty_import_into(MontyContext *mc, mp_int *r, mp_int *x)
 {
-    return monty_mul(mc, x, mc->powers_of_r_mod_m[1]);
+    mp_int *imported = monty_import(mc, x);
+    mp_copy_into(r, imported);
+    mp_free(imported);
 }
 
 /*
@@ -1544,7 +1574,6 @@ mp_int *monty_pow(MontyContext *mc, mp_int *base, mp_int *exponent)
 
 mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus)
 {
-    assert(base->nw <= modulus->nw);
     assert(modulus->nw > 0);
     assert(modulus->w[0] & 1);
 

+ 8 - 0
source/putty/mpint.h

@@ -197,6 +197,14 @@ mp_int *mp_add(mp_int *x, mp_int *y);
 mp_int *mp_sub(mp_int *x, mp_int *y);
 mp_int *mp_mul(mp_int *x, mp_int *y);
 
+/*
+ * Bitwise operations.
+ */
+void mp_and_into(mp_int *r, mp_int *a, mp_int *b);
+void mp_or_into(mp_int *r, mp_int *a, mp_int *b);
+void mp_xor_into(mp_int *r, mp_int *a, mp_int *b);
+void mp_bic_into(mp_int *r, mp_int *a, mp_int *b);
+
 /*
  * Addition, subtraction and multiplication with one argument small
  * enough to fit in a C integer. For mp_mul_integer_into, it has to be

+ 1 - 1
source/putty/mpint_i.h

@@ -131,7 +131,7 @@
   #define BIGNUM_INT_BITS_BITS 5
   #define DEFINE_BIGNUMDBLINT typedef unsigned long long BignumDblInt
 
-#elif (defined _MSC_VER && defined _M_IX86 && BB_OK(5)) || defined(MPEXT)
+#elif defined _MSC_VER && BB_OK(5) || defined(MPEXT)
 
   /* 32-bit BignumInt, using Visual Studio __int64 as BignumDblInt */
 

+ 6 - 5
source/putty/network.h

@@ -28,8 +28,8 @@ struct SocketVtable {
     /* if p is NULL, it doesn't change the plug */
     /* but it does return the one it's using */
     void (*close) (Socket *s);
-    int (*write) (Socket *s, const void *data, int len);
-    int (*write_oob) (Socket *s, const void *data, int len);
+    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 (*flush) (Socket *s);
     void (*set_frozen) (Socket *s, bool is_frozen);
@@ -70,7 +70,7 @@ struct PlugVtable {
     /* 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, char *data, int len);
+    void (*receive) (Plug *p, int urgent, const char *data, size_t len);
     /*
      *  - urgent==0. `data' points to `len' bytes of perfectly
      *    ordinary data.
@@ -81,7 +81,7 @@ struct PlugVtable {
      *  - urgent==2. `data' points to `len' bytes of data,
      *    the first of which was the one at the Urgent mark.
      */
-    void (*sent) (Plug *p, int bufsize);
+    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
@@ -289,6 +289,7 @@ 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);
-void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, int len);
+void log_proxy_stderr(
+    Plug *plug, bufchain *buf, const void *vdata, size_t len);
 
 #endif

+ 3 - 2
source/putty/nullplug.c

@@ -17,11 +17,12 @@ static void nullplug_closing(Plug *plug, const char *error_msg, int error_code,
 {
 }
 
-static void nullplug_receive(Plug *plug, int urgent, char *data, int len)
+static void nullplug_receive(
+    Plug *plug, int urgent, const char *data, size_t len)
 {
 }
 
-static void nullplug_sent(Plug *plug, int bufsize)
+static void nullplug_sent(Plug *plug, size_t bufsize)
 {
 }
 

+ 6 - 4
source/putty/portfwd.c

@@ -192,7 +192,7 @@ static char *ipv6_to_string(ptrlen ipv6)
                      (unsigned)GET_16BIT_MSB_FIRST(addr + 14));
 }
 
-static void pfd_receive(Plug *plug, int urgent, char *data, int len)
+static void pfd_receive(Plug *plug, int urgent, const char *data, size_t len)
 {
     struct PortForwarding *pf =
         container_of(plug, struct PortForwarding, plug);
@@ -417,7 +417,7 @@ static void pfd_receive(Plug *plug, int urgent, char *data, int len)
         sshfwd_write(pf->c, data, len);
 }
 
-static void pfd_sent(Plug *plug, int bufsize)
+static void pfd_sent(Plug *plug, size_t bufsize)
 {
     struct PortForwarding *pf =
         container_of(plug, struct PortForwarding, plug);
@@ -437,7 +437,8 @@ static const PlugVtable PortForwarding_plugvt = {
 static void pfd_chan_free(Channel *chan);
 static void pfd_open_confirmation(Channel *chan);
 static void pfd_open_failure(Channel *chan, const char *errtext);
-static int pfd_send(Channel *chan, bool is_stderr, const void *data, int len);
+static size_t pfd_send(
+    Channel *chan, bool is_stderr, const void *data, size_t len);
 static void pfd_send_eof(Channel *chan);
 static void pfd_set_input_wanted(Channel *chan, bool wanted);
 static char *pfd_log_close_msg(Channel *chan);
@@ -644,7 +645,8 @@ static void pfd_chan_free(Channel *chan)
 /*
  * Called to send data down the raw connection.
  */
-static int pfd_send(Channel *chan, bool is_stderr, const void *data, int len)
+static size_t pfd_send(
+    Channel *chan, bool is_stderr, const void *data, size_t len)
 {
     pinitassert(chan->vt == &PortForwarding_channelvt);
     PortForwarding *pf = container_of(chan, PortForwarding, chan);

+ 36 - 39
source/putty/proxy.c

@@ -24,9 +24,7 @@
  */
 void proxy_activate (ProxySocket *p)
 {
-    void *data;
-    int len;
-    long output_before, output_after;
+    size_t output_before, output_after;
     
     p->state = PROXY_STATE_ACTIVE;
 
@@ -43,21 +41,21 @@ void proxy_activate (ProxySocket *p)
     
     /* send buffered OOB writes */
     while (bufchain_size(&p->pending_oob_output_data) > 0) {
-	bufchain_prefix(&p->pending_oob_output_data, &data, &len);
-	output_after += sk_write_oob(p->sub_socket, data, len);
-	bufchain_consume(&p->pending_oob_output_data, len);
+        ptrlen data = bufchain_prefix(&p->pending_oob_output_data);
+	output_after += sk_write_oob(p->sub_socket, data.ptr, data.len);
+	bufchain_consume(&p->pending_oob_output_data, data.len);
     }
 
     /* send buffered normal writes */
     while (bufchain_size(&p->pending_output_data) > 0) {
-	bufchain_prefix(&p->pending_output_data, &data, &len);
-	output_after += sk_write(p->sub_socket, data, len);
-	bufchain_consume(&p->pending_output_data, len);
+	ptrlen data = bufchain_prefix(&p->pending_output_data);
+	output_after += sk_write(p->sub_socket, data.ptr, data.len);
+	bufchain_consume(&p->pending_output_data, data.len);
     }
 
     /* if we managed to send any data, let the higher levels know. */
     if (output_after < output_before)
-	plug_sent(p->plug, output_after);
+        plug_sent(p->plug, output_after);
 
     /* if we were asked to flush the output during
      * the proxy negotiation process, do so now.
@@ -95,7 +93,7 @@ static void sk_proxy_close (Socket *s)
     sfree(ps);
 }
 
-static int sk_proxy_write (Socket *s, const void *data, int len)
+static size_t sk_proxy_write (Socket *s, const void *data, size_t len)
 {
     ProxySocket *ps = container_of(s, ProxySocket, sock);
 
@@ -106,7 +104,7 @@ static int sk_proxy_write (Socket *s, const void *data, int len)
     return sk_write(ps->sub_socket, data, len);
 }
 
-static int sk_proxy_write_oob (Socket *s, const void *data, int len)
+static size_t sk_proxy_write_oob (Socket *s, const void *data, size_t len)
 {
     ProxySocket *ps = container_of(s, ProxySocket, sock);
 
@@ -160,15 +158,13 @@ static void sk_proxy_set_frozen (Socket *s, bool is_frozen)
 	 * so we have to check each time.
 	 */
         while (!ps->freeze && bufchain_size(&ps->pending_input_data) > 0) {
-	    void *data;
 	    char databuf[512];
-	    int len;
-	    bufchain_prefix(&ps->pending_input_data, &data, &len);
-	    if (len > lenof(databuf))
-		len = lenof(databuf);
-	    memcpy(databuf, data, len);
-	    bufchain_consume(&ps->pending_input_data, len);
-	    plug_receive(ps->plug, 0, databuf, len);
+	    ptrlen data = bufchain_prefix(&ps->pending_input_data);
+	    if (data.len > lenof(databuf))
+		data.len = lenof(databuf);
+	    memcpy(databuf, data.ptr, data.len);
+	    bufchain_consume(&ps->pending_input_data, data.len);
+	    plug_receive(ps->plug, 0, databuf, data.len);
 	}
 
 	/* if we're still frozen, we'll have to wait for another
@@ -214,7 +210,8 @@ static void plug_proxy_closing (Plug *p, const char *error_msg,
     }
 }
 
-static void plug_proxy_receive (Plug *p, int urgent, char *data, int len)
+static void plug_proxy_receive(
+    Plug *p, int urgent, const char *data, size_t len)
 {
     ProxySocket *ps = container_of(p, ProxySocket, plugimpl);
 
@@ -233,12 +230,11 @@ static void plug_proxy_receive (Plug *p, int urgent, char *data, int len)
     }
 }
 
-static void plug_proxy_sent (Plug *p, int bufsize)
+static void plug_proxy_sent (Plug *p, size_t bufsize)
 {
     ProxySocket *ps = container_of(p, ProxySocket, plugimpl);
 
     if (ps->state != PROXY_STATE_ACTIVE) {
-	ps->sent_bufsize = bufsize;
 	ps->negotiate(ps, PROXY_CHANGE_SENT);
 	return;
     }
@@ -553,9 +549,9 @@ Socket *new_listener(const char *srcaddr, int port, Plug *plug,
  * HTTP CONNECT proxy type.
  */
 
-static int get_line_end (char * data, int len)
+static bool get_line_end(char *data, size_t len, size_t *out)
 {
-    int off = 0;
+    size_t off = 0;
 
     while (off < len)
     {
@@ -564,16 +560,20 @@ static int get_line_end (char * data, int len)
 	    off++;
 
 	    /* is that the only thing on this line? */
-	    if (off <= 2) return off;
+            if (off <= 2) {
+                *out = off;
+                return true;
+            }
 
 	    /* if not, then there is the possibility that this header
 	     * continues onto the next line, if it starts with a space
 	     * or a tab.
 	     */
 
-	    if (off + 1 < len &&
-		data[off+1] != ' ' &&
-		data[off+1] != '\t') return off;
+            if (off + 1 < len && data[off+1] != ' ' && data[off+1] != '\t') {
+                *out = off;
+                return true;
+            }
 
 	    /* the line does continue, so we have to keep going
 	     * until we see an the header's "real" end of line.
@@ -584,7 +584,7 @@ static int get_line_end (char * data, int len)
 	off++;
     }
 
-    return -1;
+    return false;
 }
 
 int proxy_http_negotiate (ProxySocket *p, int change)
@@ -666,8 +666,7 @@ int proxy_http_negotiate (ProxySocket *p, int change)
 	 */
 
 	char *data, *datap;
-	int len;
-	int eol;
+	size_t len, eol;
 
 	if (p->state == 1) {
 
@@ -685,8 +684,7 @@ int proxy_http_negotiate (ProxySocket *p, int change)
 	     */
 	    data[len] = '\0';
 
-	    eol = get_line_end(data, len);
-	    if (eol < 0) {
+            if (!get_line_end(data, len, &eol)) {
 		sfree(data);
 		return 1;
 	    }
@@ -734,17 +732,16 @@ int proxy_http_negotiate (ProxySocket *p, int change)
 	    datap = data;
 	    bufchain_fetch(&p->pending_input_data, data, len);
 
-	    eol = get_line_end(datap, len);
-	    if (eol < 0) {
+            if (!get_line_end(datap, len, &eol)) {
 		sfree(data);
 		return 1;
 	    }
-	    while (eol > 2)
-	    {
+	    while (eol > 2) {
 		bufchain_consume(&p->pending_input_data, eol);
 		datap += eol;
 		len   -= eol;
-		eol = get_line_end(datap, len);
+                if (!get_line_end(datap, len, &eol))
+                    eol = 0;           /* terminate the loop */
 	    }
 
 	    if (eol == 2) {

+ 1 - 4
source/putty/proxy.h

@@ -68,12 +68,9 @@ struct ProxySocket {
 
     /* receive */
     bool receive_urgent;
-    char *receive_data;
+    const char *receive_data;
     int receive_len;
 
-    /* sent */
-    int sent_bufsize;
-
     /* accepting */
     accept_fn_t accepting_constructor;
     accept_ctx_t accepting_ctx;

+ 11 - 8
source/putty/putty.h

@@ -503,9 +503,9 @@ struct BackendVtable {
     /* Pass in a replacement configuration. */
     void (*reconfig) (Backend *be, Conf *conf);
     /* send() returns the current amount of buffered data. */
-    int (*send) (Backend *be, const char *buf, int len);
+    size_t (*send) (Backend *be, const char *buf, size_t len);
     /* sendbuffer() does the same thing but without attempting a send */
-    int (*sendbuffer) (Backend *be);
+    size_t (*sendbuffer) (Backend *be);
     void (*size) (Backend *be, int width, int height);
     void (*special) (Backend *be, SessionSpecialCode code, int arg);
     const SessionSpecial *(*get_specials) (Backend *be);
@@ -518,7 +518,7 @@ struct BackendVtable {
     bool (*ldisc_option_state) (Backend *be, int);
     void (*provide_ldisc) (Backend *be, Ldisc *ldisc);
     /* Tells the back end that the front end  buffer is clearing. */
-    void (*unthrottle) (Backend *be, int bufsize);
+    void (*unthrottle) (Backend *be, size_t bufsize);
     int (*cfg_info) (Backend *be);
 
     /* Only implemented in the SSH protocol: check whether a
@@ -742,7 +742,7 @@ struct SeatVtable {
      *
      * The return value is the current size of the output backlog.
      */
-    int (*output)(Seat *seat, bool is_stderr, const void *data, int len);
+    size_t (*output)(Seat *seat, bool is_stderr, const void *data, size_t len);
 
     /*
      * Called when the back end wants to indicate that EOF has arrived
@@ -964,7 +964,8 @@ void seat_connection_fatal(Seat *seat, const char *fmt, ...);
  * These are generally obvious, except for is_utf8, where you might
  * plausibly want to return either fixed answer 'no' or 'yes'.
  */
-int nullseat_output(Seat *seat, bool is_stderr, const void *data, int len);
+size_t nullseat_output(
+    Seat *seat, bool is_stderr, const void *data, size_t len);
 bool nullseat_eof(Seat *seat);
 int nullseat_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input);
 void nullseat_notify_remote_exit(Seat *seat);
@@ -1552,7 +1553,7 @@ void term_reconfig(Terminal *, Conf *);
 void term_request_copy(Terminal *, const int *clipboards, int n_clipboards);
 void term_request_paste(Terminal *, int clipboard);
 void term_seen_key_event(Terminal *); 
-int term_data(Terminal *, bool is_stderr, const void *data, int len);
+size_t term_data(Terminal *, bool is_stderr, const void *data, size_t len);
 void term_provide_backend(Terminal *term, Backend *backend);
 void term_provide_logctx(Terminal *term, LogContext *logctx);
 void term_set_focus(Terminal *term, bool has_focus);
@@ -1640,7 +1641,7 @@ struct logblank_t {
     int type;
 };
 void log_packet(LogContext *logctx, int direction, int type,
-		const char *texttype, const void *data, int len,
+		const char *texttype, const void *data, size_t len,
 		int n_blanks, const struct logblank_t *blanks,
 		const unsigned long *sequence,
                 unsigned downstream_id, const char *additional_log_text);
@@ -1714,6 +1715,8 @@ void random_setup_special();
 /* Manually drop a random seed into the random number generator, e.g.
  * just before generating a key. */
 void random_reseed(ptrlen seed);
+/* Limit on how much entropy is worth putting into the generator (bits). */
+size_t random_seed_bits(void);
 
 /*
  * Exports from pinger.c.
@@ -1847,7 +1850,7 @@ printer_enum *printer_start_enum(int *nprinters);
 char *printer_get_name(printer_enum *, int);
 void printer_finish_enum(printer_enum *);
 printer_job *printer_start_job(char *printer);
-void printer_job_data(printer_job *, void *, int);
+void printer_job_data(printer_job *, const void *, size_t);
 void printer_finish_job(printer_job *);
 
 /*

+ 67 - 28
source/putty/ssh.c

@@ -61,9 +61,31 @@ struct Ssh {
 
     int version;
     int conn_throttle_count;
-    int overall_bufsize;
+    size_t overall_bufsize;
     bool throttled_all;
-    bool frozen;
+
+    /*
+     * logically_frozen is true if we're not currently _processing_
+     * data from the SSH socket (e.g. because a higher layer has asked
+     * us not to due to ssh_throttle_conn). socket_frozen is true if
+     * we're not even _reading_ data from the socket (i.e. it should
+     * always match the value we last passed to sk_set_frozen).
+     *
+     * The two differ in that socket_frozen can also become
+     * temporarily true because of a large backlog in the in_raw
+     * bufchain, to force no further plug_receive events until the BPP
+     * input function has had a chance to run. (Some front ends, like
+     * GTK, can persistently call the network and never get round to
+     * the toplevel callbacks.) If we've stopped reading from the
+     * socket for that reason, we absolutely _do_ want to carry on
+     * processing our input bufchain, because that's the only way
+     * it'll ever get cleared!
+     *
+     * ssh_check_frozen() resets socket_frozen, and should be called
+     * whenever either of logically_frozen and the bufchain size
+     * changes.
+     */
+    bool logically_frozen, socket_frozen;
 
     /* in case we find these out before we have a ConnectionLayer to tell */
     int term_width, term_height;
@@ -117,7 +139,7 @@ struct Ssh {
         logevent_and_free((ssh)->logctx, dupprintf params))
 
 static void ssh_shutdown(Ssh *ssh);
-static void ssh_throttle_all(Ssh *ssh, bool enable, int bufsize);
+static void ssh_throttle_all(Ssh *ssh, bool enable, size_t bufsize);
 static void ssh_bpp_output_raw_data_callback(void *vctx);
 
 LogContext *ssh_get_logctx(Ssh *ssh)
@@ -297,6 +319,29 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv,
     ssh_bpp_free(old_bpp);
 }
 
+static void ssh_check_frozen(Ssh *ssh)
+{
+    if (!ssh->s)
+        return;
+
+    bool prev_frozen = ssh->socket_frozen;
+    ssh->socket_frozen = (ssh->logically_frozen ||
+                          bufchain_size(&ssh->in_raw) > SSH_MAX_BACKLOG);
+    sk_set_frozen(ssh->s, ssh->socket_frozen);
+    if (prev_frozen && !ssh->socket_frozen && ssh->bpp) {
+        /*
+         * If we've just unfrozen, process any SSH connection data
+         * that was stashed in our queue while we were frozen.
+         */
+        queue_idempotent_callback(&ssh->bpp->ic_in_raw);
+    }
+}
+
+void ssh_conn_processed_data(Ssh *ssh)
+{
+    ssh_check_frozen(ssh);
+}
+
 static void ssh_bpp_output_raw_data_callback(void *vctx)
 {
     Ssh *ssh = (Ssh *)vctx;
@@ -305,17 +350,16 @@ static void ssh_bpp_output_raw_data_callback(void *vctx)
         return;
 
     while (bufchain_size(&ssh->out_raw) > 0) {
-        void *data;
-        int len, backlog;
+        size_t backlog;
 
-        bufchain_prefix(&ssh->out_raw, &data, &len);
+        ptrlen data = bufchain_prefix(&ssh->out_raw);
 
         if (ssh->logctx)
-            log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len,
+            log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data.ptr, data.len,
                        0, NULL, NULL, 0, NULL);
-        backlog = sk_write(ssh->s, data, len);
+        backlog = sk_write(ssh->s, data.ptr, data.len);
 
-        bufchain_consume(&ssh->out_raw, len);
+        bufchain_consume(&ssh->out_raw, data.len);
 
         if (backlog > SSH_MAX_BACKLOG) {
             ssh_throttle_all(ssh, true, backlog);
@@ -323,6 +367,8 @@ static void ssh_bpp_output_raw_data_callback(void *vctx)
         }
     }
 
+    ssh_check_frozen(ssh);
+
     if (ssh->pending_close) {
         sk_close(ssh->s);
         ssh->s = NULL;
@@ -528,7 +574,7 @@ static void ssh_closing(Plug *plug, const char *error_msg, int error_code,
     }
 }
 
-static void ssh_receive(Plug *plug, int urgent, char *data, int len)
+static void ssh_receive(Plug *plug, int urgent, const char *data, size_t len)
 {
     Ssh *ssh = container_of(plug, Ssh, plug);
 
@@ -538,11 +584,13 @@ static void ssh_receive(Plug *plug, int urgent, char *data, int len)
 		   0, NULL, NULL, 0, NULL);
 
     bufchain_add(&ssh->in_raw, data, len);
-    if (!ssh->frozen && ssh->bpp)
+    if (!ssh->logically_frozen && ssh->bpp)
         queue_idempotent_callback(&ssh->bpp->ic_in_raw);
+
+    ssh_check_frozen(ssh);
 }
 
-static void ssh_sent(Plug *plug, int bufsize)
+static void ssh_sent(Plug *plug, size_t bufsize)
 {
     Ssh *ssh = container_of(plug, Ssh, plug);
     /*
@@ -760,24 +808,15 @@ void ssh_throttle_conn(Ssh *ssh, int adjust)
         return;                /* don't change current frozen state */
     }
 
-    ssh->frozen = frozen;
-
-    if (ssh->s) {
-        sk_set_frozen(ssh->s, frozen);
-
-        /*
-         * Now process any SSH connection data that was stashed in our
-         * queue while we were frozen.
-         */
-        queue_idempotent_callback(&ssh->bpp->ic_in_raw);
-    }
+    ssh->logically_frozen = frozen;
+    ssh_check_frozen(ssh);
 }
 
 /*
  * Throttle or unthrottle _all_ local data streams (for when sends
  * on the SSH connection itself back up).
  */
-static void ssh_throttle_all(Ssh *ssh, bool enable, int bufsize)
+static void ssh_throttle_all(Ssh *ssh, bool enable, size_t bufsize)
 {
     if (enable == ssh->throttled_all)
 	return;
@@ -896,7 +935,7 @@ static void ssh_reconfig(Backend *be, Conf *conf)
 /*
  * Called to send data down the SSH connection.
  */
-static int ssh_send(Backend *be, const char *buf, int len)
+static size_t ssh_send(Backend *be, const char *buf, size_t len)
 {
     Ssh *ssh = container_of(be, Ssh, backend);
 
@@ -913,10 +952,10 @@ static int ssh_send(Backend *be, const char *buf, int len)
 /*
  * Called to query the current amount of buffered stdin data.
  */
-static int ssh_sendbuffer(Backend *be)
+static size_t ssh_sendbuffer(Backend *be)
 {
     Ssh *ssh = container_of(be, Ssh, backend);
-    int backlog;
+    size_t backlog;
 
     if (!ssh || !ssh->s || !ssh->cl)
 	return 0;
@@ -1017,7 +1056,7 @@ static void ssh_special(Backend *be, SessionSpecialCode code, int arg)
  * This is called when the seat's output channel manages to clear some
  * backlog.
  */
-static void ssh_unthrottle(Backend *be, int bufsize)
+static void ssh_unthrottle(Backend *be, size_t bufsize)
 {
     Ssh *ssh = container_of(be, Ssh, backend);
 

+ 9 - 3
source/putty/ssh.h

@@ -277,10 +277,10 @@ struct ConnectionLayerVtable {
     void (*terminal_size)(ConnectionLayer *cl, int width, int height);
 
     /* Indicate that the backlog on standard output has cleared */
-    void (*stdout_unthrottle)(ConnectionLayer *cl, int bufsize);
+    void (*stdout_unthrottle)(ConnectionLayer *cl, size_t bufsize);
 
     /* Query the size of the backlog on standard _input_ */
-    int (*stdin_backlog)(ConnectionLayer *cl);
+    size_t (*stdin_backlog)(ConnectionLayer *cl);
 
     /* Tell the connection layer that the SSH connection itself has
      * backed up, so it should tell all currently open channels to
@@ -384,6 +384,9 @@ void ssh_got_exitcode(Ssh *ssh, int status);
 void ssh_ldisc_update(Ssh *ssh);
 void ssh_got_fallback_cmd(Ssh *ssh);
 
+/* Communications back to ssh.c from the BPP */
+void ssh_conn_processed_data(Ssh *ssh);
+
 /* Functions to abort the connection, for various reasons. */
 void ssh_remote_error(Ssh *ssh, const char *fmt, ...);
 void ssh_remote_eof(Ssh *ssh, const char *fmt, ...);
@@ -732,6 +735,7 @@ struct ssh_keyalg {
 
     /* Methods that operate on an existing ssh_key */
     void (*freekey) (ssh_key *key);
+    char *(*invalid) (ssh_key *key, unsigned flags);
     void (*sign) (ssh_key *key, ptrlen data, unsigned flags, BinarySink *);
     bool (*verify) (ssh_key *key, ptrlen sig, ptrlen data);
     void (*public_blob)(ssh_key *key, BinarySink *);
@@ -754,6 +758,7 @@ struct ssh_keyalg {
 #define ssh_key_new_priv_openssh(alg, bs) ((alg)->new_priv_openssh(alg, bs))
 
 #define ssh_key_free(key) ((key)->vt->freekey(key))
+#define ssh_key_invalid(key, flags) ((key)->vt->invalid(key, flags))
 #define ssh_key_sign(key, data, flags, bs) \
     ((key)->vt->sign(key, data, flags, bs))
 #define ssh_key_verify(key, sig, data) ((key)->vt->verify(key, sig, data))
@@ -930,6 +935,7 @@ void prng_seed_begin(prng *p);
 void prng_seed_finish(prng *p);
 void prng_read(prng *p, void *vout, size_t size);
 void prng_add_entropy(prng *p, unsigned source_id, ptrlen data);
+size_t prng_seed_bits(prng *p);
 
 /* This function must be implemented by the platform, and returns a
  * timer in milliseconds that the PRNG can use to know whether it's
@@ -1143,7 +1149,7 @@ char *ssh2_pubkey_openssh_str(ssh2_userkey *key);
 void ssh2_write_pubkey(FILE *fp, const char *comment,
                        const void *v_pub_blob, int pub_len,
                        int keytype);
-char *ssh2_fingerprint_blob(const void *blob, int bloblen);
+char *ssh2_fingerprint_blob(ptrlen);
 char *ssh2_fingerprint(ssh_key *key);
 int key_type(const Filename *filename);
 const char *key_type_to_str(int type);

+ 3 - 3
source/putty/ssh1bpp.c

@@ -181,7 +181,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp)
             ssh_cipher_decrypt(s->cipher_in, s->data, s->biglen);
 
         s->realcrc = crc32_ssh1(make_ptrlen(s->data, s->biglen - 4));
-        s->gotcrc = GET_32BIT(s->data + s->biglen - 4);
+        s->gotcrc = GET_32BIT_MSB_FIRST(s->data + s->biglen - 4);
         if (s->gotcrc != s->realcrc) {
             ssh_sw_abort(s->bpp.ssh, "Incorrect CRC received on packet");
             crStopV;
@@ -332,8 +332,8 @@ static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt)
     random_read(pkt->data + pktoffs, 4+8 - pktoffs);
     crc = crc32_ssh1(
         make_ptrlen(pkt->data + pktoffs + 4, biglen - 4)); /* all ex len */
-    PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc);
-    PUT_32BIT(pkt->data + pktoffs, len);
+    PUT_32BIT_MSB_FIRST(pkt->data + pktoffs + 4 + biglen - 4, crc);
+    PUT_32BIT_MSB_FIRST(pkt->data + pktoffs, len);
 
     if (s->cipher_out)
         ssh_cipher_encrypt(s->cipher_out, pkt->data + pktoffs + 4, biglen);

+ 1 - 1
source/putty/ssh1censor.c

@@ -17,7 +17,7 @@ int ssh1_censor_packet(
     ptrlen str;
     BinarySource src[1];
 
-    BinarySource_BARE_INIT(src, pkt.ptr, pkt.len);
+    BinarySource_BARE_INIT_PL(src, pkt);
 
     if (pls->omit_data &&
         (type == SSH1_SMSG_STDOUT_DATA ||

+ 2 - 2
source/putty/ssh1connection-client.c

@@ -399,8 +399,8 @@ static void ssh1mainchan_hint_channel_is_simple(SshChannel *sc)
 {
 }
 
-static int ssh1mainchan_write(
-    SshChannel *sc, bool is_stderr, const void *data, int len)
+static size_t ssh1mainchan_write(
+    SshChannel *sc, bool is_stderr, const void *data, size_t len)
 {
     struct ssh1_connection_state *s =
         container_of(sc, struct ssh1_connection_state, mainchan_sc);

+ 15 - 17
source/putty/ssh1connection.c

@@ -58,8 +58,8 @@ static struct X11FakeAuth *ssh1_add_x11_display(
     ConnectionLayer *cl, int authtype, struct X11Display *disp);
 static bool ssh1_agent_forwarding_permitted(ConnectionLayer *cl);
 static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height);
-static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize);
-static int ssh1_stdin_backlog(ConnectionLayer *cl);
+static void ssh1_stdout_unthrottle(ConnectionLayer *cl, size_t bufsize);
+static size_t ssh1_stdin_backlog(ConnectionLayer *cl);
 static void ssh1_throttle_all_channels(ConnectionLayer *cl, bool throttled);
 static bool ssh1_ldisc_option(ConnectionLayer *cl, int option);
 static void ssh1_set_ldisc_option(ConnectionLayer *cl, int option, bool value);
@@ -94,11 +94,11 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = {
     ssh1_set_wants_user_input,
 };
 
-static int ssh1channel_write(
-    SshChannel *c, bool is_stderr, const void *buf, int len);
+static size_t ssh1channel_write(
+    SshChannel *c, bool is_stderr, const void *buf, size_t len);
 static void ssh1channel_write_eof(SshChannel *c);
 static void ssh1channel_initiate_close(SshChannel *c, const char *err);
-static void ssh1channel_unthrottle(SshChannel *c, int bufsize);
+static void ssh1channel_unthrottle(SshChannel *c, size_t bufsize);
 static Conf *ssh1channel_get_conf(SshChannel *c);
 static void ssh1channel_window_override_removed(SshChannel *c) { /* ignore */ }
 
@@ -581,7 +581,7 @@ static void ssh1channel_initiate_close(SshChannel *sc, const char *err)
     ssh1_channel_check_close(c);
 }
 
-static void ssh1channel_unthrottle(SshChannel *sc, int bufsize)
+static void ssh1channel_unthrottle(SshChannel *sc, size_t bufsize)
 {
     struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc);
     struct ssh1_connection_state *s = c->connlayer;
@@ -592,8 +592,8 @@ static void ssh1channel_unthrottle(SshChannel *sc, int bufsize)
     }
 }
 
-static int ssh1channel_write(
-    SshChannel *sc, bool is_stderr, const void *buf, int len)
+static size_t ssh1channel_write(
+    SshChannel *sc, bool is_stderr, const void *buf, size_t len)
 {
     struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc);
     struct ssh1_connection_state *s = c->connlayer;
@@ -698,7 +698,7 @@ static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height)
         mainchan_terminal_size(s->mainchan, width, height);
 }
 
-static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize)
+static void ssh1_stdout_unthrottle(ConnectionLayer *cl, size_t bufsize)
 {
     struct ssh1_connection_state *s =
         container_of(cl, struct ssh1_connection_state, cl);
@@ -709,7 +709,7 @@ static void ssh1_stdout_unthrottle(ConnectionLayer *cl, int bufsize)
     }
 }
 
-static int ssh1_stdin_backlog(ConnectionLayer *cl)
+static size_t ssh1_stdin_backlog(ConnectionLayer *cl)
 {
     return 0;
 }
@@ -783,13 +783,11 @@ static void ssh1_connection_got_user_input(PacketProtocolLayer *ppl)
         /*
          * Add user input to the main channel's buffer.
          */
-        void *data;
-        int len;
-        bufchain_prefix(s->ppl.user_input, &data, &len);
-        if (len > 512)
-            len = 512;
-        sshfwd_write(&s->mainchan_sc, data, len);
-        bufchain_consume(s->ppl.user_input, len);
+        ptrlen data = bufchain_prefix(s->ppl.user_input);
+        if (data.len > 512)
+            data.len = 512;
+        sshfwd_write(&s->mainchan_sc, data.ptr, data.len);
+        bufchain_consume(s->ppl.user_input, data.len);
     }
 }
 

+ 1 - 2
source/putty/ssh1login.c

@@ -490,8 +490,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
                 strbuf_free(request);
                 crMaybeWaitUntilV(!s->auth_agent_query);
             }
-            BinarySource_BARE_INIT(
-                s->asrc, s->agent_response.ptr, s->agent_response.len);
+            BinarySource_BARE_INIT_PL(s->asrc, s->agent_response);
 
             get_uint32(s->asrc); /* skip length field */
             if (get_byte(s->asrc) == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {

+ 1 - 1
source/putty/ssh2bpp-bare.c

@@ -170,7 +170,7 @@ static void ssh2_bare_bpp_format_packet(struct ssh2_bare_bpp_state *s,
 
     s->outgoing_sequence++;        /* only for diagnostics, really */
 
-    PUT_32BIT(pkt->data, pkt->length - 4);
+    PUT_32BIT_MSB_FIRST(pkt->data, pkt->length - 4);
     bufchain_add(s->bpp.out_raw, pkt->data, pkt->length);
 }
 

+ 5 - 5
source/putty/ssh2bpp.c

@@ -343,7 +343,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
 
                 /* See if that gives us a valid packet. */
                 if (ssh2_mac_verresult(s->in.mac, s->buf + s->packetlen) &&
-                    ((s->len = toint(GET_32BIT(s->buf))) ==
+                    ((s->len = toint(GET_32BIT_MSB_FIRST(s->buf))) ==
                      s->packetlen-4))
                     break;
                 if (s->packetlen >= (long)OUR_V2_PACKETLIMIT) {
@@ -383,9 +383,9 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
                 memcpy(len, s->buf, 4);
                 ssh_cipher_decrypt_length(
                     s->in.cipher, len, 4, s->in.sequence);
-                s->len = toint(GET_32BIT(len));
+                s->len = toint(GET_32BIT_MSB_FIRST(len));
             } else {
-                s->len = toint(GET_32BIT(s->buf));
+                s->len = toint(GET_32BIT_MSB_FIRST(s->buf));
             }
 
             /*
@@ -450,7 +450,7 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
             /*
              * Now get the length figure.
              */
-            s->len = toint(GET_32BIT(s->buf));
+            s->len = toint(GET_32BIT_MSB_FIRST(s->buf));
 
             /*
              * _Completely_ silly lengths should be stomped on before they
@@ -729,7 +729,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
         put_byte(pkt, 0);              /* make space for random padding */
     random_read(pkt->data + origlen, padding);
     pkt->data[4] = padding;
-    PUT_32BIT(pkt->data, origlen + padding - 4);
+    PUT_32BIT_MSB_FIRST(pkt->data, origlen + padding - 4);
 
     /* Encrypt length if the scheme requires it */
     if (s->out.cipher &&

+ 1 - 1
source/putty/ssh2censor.c

@@ -17,7 +17,7 @@ int ssh2_censor_packet(
     ptrlen str;
     BinarySource src[1];
 
-    BinarySource_BARE_INIT(src, pkt.ptr, pkt.len);
+    BinarySource_BARE_INIT_PL(src, pkt);
 
     if (pls->omit_data &&
         (type == SSH2_MSG_CHANNEL_DATA ||

+ 26 - 31
source/putty/ssh2connection.c

@@ -59,8 +59,8 @@ static void ssh2_sharing_queue_global_request(
 static void ssh2_sharing_no_more_downstreams(ConnectionLayer *cl);
 static bool ssh2_agent_forwarding_permitted(ConnectionLayer *cl);
 static void ssh2_terminal_size(ConnectionLayer *cl, int width, int height);
-static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize);
-static int ssh2_stdin_backlog(ConnectionLayer *cl);
+static void ssh2_stdout_unthrottle(ConnectionLayer *cl, size_t bufsize);
+static size_t ssh2_stdin_backlog(ConnectionLayer *cl);
 static void ssh2_throttle_all_channels(ConnectionLayer *cl, bool throttled);
 static bool ssh2_ldisc_option(ConnectionLayer *cl, int option);
 static void ssh2_set_ldisc_option(ConnectionLayer *cl, int option, bool value);
@@ -122,11 +122,11 @@ static char *ssh2_channel_open_failure_error_text(PktIn *pktin)
     return dupprintf("%s [%.*s]", reason_code_string, PTRLEN_PRINTF(reason));
 }
 
-static int ssh2channel_write(
-    SshChannel *c, bool is_stderr, const void *buf, int len);
+static size_t ssh2channel_write(
+    SshChannel *c, bool is_stderr, const void *buf, size_t len);
 static void ssh2channel_write_eof(SshChannel *c);
 static void ssh2channel_initiate_close(SshChannel *c, const char *err);
-static void ssh2channel_unthrottle(SshChannel *c, int bufsize);
+static void ssh2channel_unthrottle(SshChannel *c, size_t bufsize);
 static Conf *ssh2channel_get_conf(SshChannel *c);
 static void ssh2channel_window_override_removed(SshChannel *c);
 static void ssh2channel_x11_sharing_handover(
@@ -162,7 +162,7 @@ static const struct SshChannelVtable ssh2channel_vtable = {
 static void ssh2_channel_check_close(struct ssh2_channel *c);
 static void ssh2_channel_try_eof(struct ssh2_channel *c);
 static void ssh2_set_window(struct ssh2_channel *c, int newwin);
-static int ssh2_try_send(struct ssh2_channel *c);
+static size_t ssh2_try_send(struct ssh2_channel *c);
 static void ssh2_try_send_and_unthrottle(struct ssh2_channel *c);
 static void ssh2_channel_check_throttle(struct ssh2_channel *c);
 static void ssh2_channel_close_local(struct ssh2_channel *c,
@@ -685,8 +685,7 @@ static bool ssh2_connection_filter_queue(struct ssh2_connection_state *s)
                     BinarySource bs_modes[1];
                     struct ssh_ttymodes modes;
 
-                    BinarySource_BARE_INIT(
-                        bs_modes, encoded_modes.ptr, encoded_modes.len);
+                    BinarySource_BARE_INIT_PL(bs_modes, encoded_modes);
                     modes = read_ttymodes_from_packet(bs_modes, 2);
                     if (get_err(bs_modes) || get_avail(bs_modes) > 0) {
                         ppl_logevent("Unable to decode terminal mode string");
@@ -1064,25 +1063,23 @@ static void ssh2_channel_try_eof(struct ssh2_channel *c)
 /*
  * Attempt to send data on an SSH-2 channel.
  */
-static int ssh2_try_send(struct ssh2_channel *c)
+static size_t ssh2_try_send(struct ssh2_channel *c)
 {
     struct ssh2_connection_state *s = c->connlayer;
     PktOut *pktout;
-    int bufsize;
+    size_t bufsize;
 
     while (c->remwindow > 0 &&
            (bufchain_size(&c->outbuffer) > 0 ||
             bufchain_size(&c->errbuffer) > 0)) {
-	int len;
-	void *data;
         bufchain *buf = (bufchain_size(&c->errbuffer) > 0 ?
                          &c->errbuffer : &c->outbuffer);
 
-	bufchain_prefix(buf, &data, &len);
-	if ((unsigned)len > c->remwindow)
-	    len = c->remwindow;
-	if ((unsigned)len > c->remmaxpkt)
-	    len = c->remmaxpkt;
+	ptrlen data = bufchain_prefix(buf);
+	if (data.len > c->remwindow)
+	    data.len = c->remwindow;
+	if (data.len > c->remmaxpkt)
+	    data.len = c->remmaxpkt;
         if (buf == &c->errbuffer) {
             pktout = ssh_bpp_new_pktout(
                 s->ppl.bpp, SSH2_MSG_CHANNEL_EXTENDED_DATA);
@@ -1092,10 +1089,10 @@ static int ssh2_try_send(struct ssh2_channel *c)
             pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_DATA);
             put_uint32(pktout, c->remoteid);
         }
-        put_string(pktout, data, len);
+        put_stringpl(pktout, data);
         pq_push(s->ppl.out_pq, pktout);
-	bufchain_consume(buf, len);
-	c->remwindow -= len;
+	bufchain_consume(buf, data.len);
+	c->remwindow -= data.len;
     }
 
     /*
@@ -1331,11 +1328,11 @@ static void ssh2channel_initiate_close(SshChannel *sc, const char *err)
     ssh2_channel_check_close(c);
 }
 
-static void ssh2channel_unthrottle(SshChannel *sc, int bufsize)
+static void ssh2channel_unthrottle(SshChannel *sc, size_t bufsize)
 {
     struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
     struct ssh2_connection_state *s = c->connlayer;
-    int buflimit;
+    size_t buflimit;
 
     buflimit = s->ssh_is_simple ? 0 : c->locmaxwin;
     if (bufsize < buflimit)
@@ -1347,8 +1344,8 @@ static void ssh2channel_unthrottle(SshChannel *sc, int bufsize)
     }
 }
 
-static int ssh2channel_write(
-    SshChannel *sc, bool is_stderr, const void *buf, int len)
+static size_t ssh2channel_write(
+    SshChannel *sc, bool is_stderr, const void *buf, size_t len)
 {
     struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
     assert(!(c->closes & CLOSES_SENT_EOF));
@@ -1587,7 +1584,7 @@ static void ssh2_terminal_size(ConnectionLayer *cl, int width, int height)
         mainchan_terminal_size(s->mainchan, width, height);
 }
 
-static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize)
+static void ssh2_stdout_unthrottle(ConnectionLayer *cl, size_t bufsize)
 {
     struct ssh2_connection_state *s =
         container_of(cl, struct ssh2_connection_state, cl);
@@ -1596,7 +1593,7 @@ static void ssh2_stdout_unthrottle(ConnectionLayer *cl, int bufsize)
         sshfwd_unthrottle(s->mainchan_sc, bufsize);
 }
 
-static int ssh2_stdin_backlog(ConnectionLayer *cl)
+static size_t ssh2_stdin_backlog(ConnectionLayer *cl)
 {
     struct ssh2_connection_state *s =
         container_of(cl, struct ssh2_connection_state, cl);
@@ -1680,11 +1677,9 @@ static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl)
         /*
          * Add user input to the main channel's buffer.
          */
-        void *data;
-        int len;
-        bufchain_prefix(s->ppl.user_input, &data, &len);
-        sshfwd_write(s->mainchan_sc, data, len);
-        bufchain_consume(s->ppl.user_input, len);
+        ptrlen data = bufchain_prefix(s->ppl.user_input);
+        sshfwd_write(s->mainchan_sc, data.ptr, data.len);
+        bufchain_consume(s->ppl.user_input, data.len);
     }
 }
 

+ 1 - 2
source/putty/ssh2kex-client.c

@@ -428,8 +428,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
                 if (s->hostkey_alg) {
                     s->hkey = ssh_key_new_pub(s->hostkey_alg,
                                               s->hostkeydata);
-                    put_string(s->exhash,
-                               s->hostkeydata.ptr, s->hostkeydata.len);
+                    put_stringpl(s->exhash, s->hostkeydata);
                 }
                 /*
                  * Can't loop as we have no token to pass to

+ 2 - 2
source/putty/ssh2transport.c

@@ -759,8 +759,8 @@ static bool ssh2_scan_kexinits(
     ptrlen clists[NKEXLIST], slists[NKEXLIST];
     const struct kexinit_algorithm *selected[NKEXLIST];
 
-    BinarySource_BARE_INIT(client, client_kexinit.ptr, client_kexinit.len);
-    BinarySource_BARE_INIT(server, server_kexinit.ptr, server_kexinit.len);
+    BinarySource_BARE_INIT_PL(client, client_kexinit);
+    BinarySource_BARE_INIT_PL(server, server_kexinit);
 
     /* Skip packet type bytes and random cookies. */
     get_data(client, 1 + 16);

+ 29 - 14
source/putty/ssh2userauth.c

@@ -282,8 +282,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
             strbuf_free(request);
             crWaitUntilV(!s->auth_agent_query);
         }
-        BinarySource_BARE_INIT(
-            s->asrc, s->agent_response.ptr, s->agent_response.len);
+        BinarySource_BARE_INIT_PL(s->asrc, s->agent_response);
 
         get_uint32(s->asrc); /* skip length field */
         if (get_byte(s->asrc) == SSH2_AGENT_IDENTITIES_ANSWER) {
@@ -471,11 +470,10 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                 if (bufchain_size(&s->banner) &&
                     (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) {
                     while (bufchain_size(&s->banner) > 0) {
-                        void *data;
-                        int len;
-                        bufchain_prefix(&s->banner, &data, &len);
-                        display_banner(s->ppl.seat, &s->banner, len); // WINSCP
-                        bufchain_consume(&s->banner, len);
+                        ptrlen data = bufchain_prefix(&s->banner);
+                        seat_stderr(s->ppl.seat, data.ptr, data.len);
+                        display_banner(s->ppl.seat, &s->banner, data.len); // WINSCP
+                        bufchain_consume(&s->banner, data.len);
                     }
                 }
                 bufchain_clear(&s->banner);
@@ -659,7 +657,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                 s->comment = get_string(s->asrc);
                 {
                     BinarySource src[1];
-                    BinarySource_BARE_INIT(src, s->pk.ptr, s->pk.len);
+                    BinarySource_BARE_INIT_PL(src, s->pk);
                     s->alg = get_string(src);
                 }
 
@@ -735,10 +733,10 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                             pq_push(s->ppl.out_pq, s->pktout);
                             s->type = AUTH_TYPE_PUBLICKEY;
                         } else {
-                            /* FIXME: less drastic response */
-                            ssh_sw_abort(s->ppl.ssh, "Pageant failed to "
-                                         "provide a signature");
-                            return;
+                            ppl_logevent("Pageant refused signing request");
+                            ppl_printf("Pageant failed to "
+                                       "provide a signature\r\n");
+                            s->suppress_wait_for_response_packet = true;
                         }
                     }
                 }
@@ -865,6 +863,23 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                             ppl_printf("Unable to load private key (%s)\r\n",
                                        error);
                             key = NULL;
+                            s->suppress_wait_for_response_packet = true;
+                            break; /* try something else */
+                        }
+                    } else {
+                        /* FIXME: if we ever support variable signature
+                         * flags, this is somewhere they'll need to be
+                         * put */
+                        char *invalid = ssh_key_invalid(key->key, 0);
+                        if (invalid) {
+                            ppl_printf("Cannot use this private key (%s)\r\n",
+                                       invalid);
+                            ssh_key_free(key->key);
+                            sfree(key->comment);
+                            sfree(key);
+                            sfree(invalid);
+                            key = NULL;
+                            s->suppress_wait_for_response_packet = true;
                             break; /* try something else */
                         }
                     }
@@ -1634,8 +1649,8 @@ static void ssh2_userauth_add_sigblob(
     struct ssh2_userauth_state *s, PktOut *pkt, ptrlen pkblob, ptrlen sigblob)
 {
     BinarySource pk[1], sig[1];
-    BinarySource_BARE_INIT(pk, pkblob.ptr, pkblob.len);
-    BinarySource_BARE_INIT(sig, sigblob.ptr, sigblob.len);
+    BinarySource_BARE_INIT_PL(pk, pkblob);
+    BinarySource_BARE_INIT_PL(sig, sigblob);
 
     /* dmemdump(pkblob, pkblob_len); */
     /* dmemdump(sigblob, sigblob_len); */

+ 1 - 1
source/putty/sshaes.c

@@ -133,7 +133,7 @@ struct aes_extra {
         NULL, &extra_##cid };                                           \
 
 #define VTABLES(keylen)                                                 \
-    VTABLES_INNER(aes ## keylen ## _cbc, "aes" #keylen,                 \
+    VTABLES_INNER(aes ## keylen ## _cbc, "aes" #keylen "-cbc",          \
                   keylen, "AES-" #keylen " CBC", _encrypt, _decrypt,    \
                   setiv_cbc, SSH_CIPHER_IS_CBC)                         \
     VTABLES_INNER(aes ## keylen ## _sdctr, "aes" #keylen "-ctr",        \

+ 3 - 3
source/putty/sshchan.h

@@ -19,7 +19,7 @@ struct ChannelVtable {
     void (*open_confirmation)(Channel *);
     void (*open_failed)(Channel *, const char *error_text);
 
-    int (*send)(Channel *, bool is_stderr, const void *buf, int len);
+    size_t (*send)(Channel *, bool is_stderr, const void *buf, size_t len);
     void (*send_eof)(Channel *);
     void (*set_input_wanted)(Channel *, bool wanted);
 
@@ -156,10 +156,10 @@ Channel *zombiechan_new(void);
  */
 
 struct SshChannelVtable {
-    int (*write)(SshChannel *c, bool is_stderr, const void *, int);
+    size_t (*write)(SshChannel *c, bool is_stderr, const void *, size_t);
     void (*write_eof)(SshChannel *c);
     void (*initiate_close)(SshChannel *c, const char *err);
-    void (*unthrottle)(SshChannel *c, int bufsize);
+    void (*unthrottle)(SshChannel *c, size_t bufsize);
     Conf *(*get_conf)(SshChannel *c);
     void (*window_override_removed)(SshChannel *c);
     void (*x11_sharing_handover)(SshChannel *c,

+ 8 - 3
source/putty/sshcommon.c

@@ -288,7 +288,8 @@ void ssh_free_pktout(PktOut *pkt)
  */
 
 static void zombiechan_free(Channel *chan);
-static int zombiechan_send(Channel *chan, bool is_stderr, const void *, int);
+static size_t zombiechan_send(
+    Channel *chan, bool is_stderr, const void *, size_t);
 static void zombiechan_set_input_wanted(Channel *chan, bool wanted);
 static void zombiechan_do_nothing(Channel *chan);
 static void zombiechan_open_failure(Channel *chan, const char *);
@@ -344,8 +345,8 @@ static void zombiechan_open_failure(Channel *chan, const char *errtext)
     assert(chan->vt == &zombiechan_channelvt);
 }
 
-static int zombiechan_send(Channel *chan, bool is_stderr,
-                           const void *data, int length)
+static size_t zombiechan_send(Channel *chan, bool is_stderr,
+                              const void *data, size_t length)
 {
     assert(chan->vt == &zombiechan_channelvt);
     return 0;
@@ -850,7 +851,11 @@ void ssh_ppl_user_output_string_and_free(PacketProtocolLayer *ppl, char *text)
 static void ssh_bpp_input_raw_data_callback(void *context)
 {
     BinaryPacketProtocol *bpp = (BinaryPacketProtocol *)context;
+    Ssh *ssh = bpp->ssh;               /* in case bpp is about to get freed */
     ssh_bpp_handle_input(bpp);
+    /* If we've now cleared enough backlog on the input connection, we
+     * may need to unfreeze it. */
+    ssh_conn_processed_data(ssh);
 }
 
 static void ssh_bpp_output_packet_callback(void *context)

+ 20 - 6
source/putty/sshdss.c

@@ -17,7 +17,7 @@ static ssh_key *dss_new_pub(const ssh_keyalg *self, ptrlen data)
     BinarySource src[1];
     struct dss_key *dss;
 
-    BinarySource_BARE_INIT(src, data.ptr, data.len);
+    BinarySource_BARE_INIT_PL(src, data);
     if (!ptrlen_eq_string(get_string(src), "ssh-dss"))
 	return NULL;
 
@@ -85,6 +85,12 @@ static char *dss_cache_str(ssh_key *key)
     return strbuf_to_str(sb);
 }
 
+static char *dss_invalid(ssh_key *key, unsigned flags)
+{
+    /* No validity criterion will stop us from using a DSA key at all */
+    return NULL;
+}
+
 static bool dss_verify(ssh_key *key, ptrlen sig, ptrlen data)
 {
     struct dss_key *dss = container_of(key, struct dss_key, sshk);
@@ -95,7 +101,7 @@ static bool dss_verify(ssh_key *key, ptrlen sig, ptrlen data)
     if (!dss->p)
 	return false;
 
-    BinarySource_BARE_INIT(src, sig.ptr, sig.len);
+    BinarySource_BARE_INIT_PL(src, sig);
 
     /*
      * Commercial SSH (2.0.13) and OpenSSH disagree over the format
@@ -129,7 +135,13 @@ static bool dss_verify(ssh_key *key, ptrlen sig, ptrlen data)
 	return false;
     }
 
-    if (mp_eq_integer(s, 0)) {
+    /* Basic sanity checks: 0 < r,s < q */
+    unsigned invalid = 0;
+    invalid |= mp_eq_integer(r, 0);
+    invalid |= mp_eq_integer(s, 0);
+    invalid |= mp_cmp_hs(r, dss->q);
+    invalid |= mp_cmp_hs(s, dss->q);
+    if (invalid) {
         mp_free(r);
         mp_free(s);
         return false;
@@ -222,7 +234,7 @@ static ssh_key *dss_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv)
         return NULL;
 
     dss = container_of(sshk, struct dss_key, sshk);
-    BinarySource_BARE_INIT(src, priv.ptr, priv.len);
+    BinarySource_BARE_INIT_PL(src, priv);
     dss->x = get_mp_ssh2(src);
     if (get_err(src)) {
         dss_freekey(&dss->sshk);
@@ -448,11 +460,12 @@ static void dss_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs)
 
     { // WINSCP
     mp_int *hash = mp_from_bytes_be(make_ptrlen(digest, 20));
-    mp_int *hxr = mp_mul(dss->x, r);
-    mp_add_into(hxr, hxr, hash);         /* hash + x*r */
+    mp_int *xr = mp_mul(dss->x, r);
+    mp_int *hxr = mp_add(xr, hash);         /* hash + x*r */
     { // WINSCP
     mp_int *s = mp_modmul(kinv, hxr, dss->q); /* s = k^-1 * (hash+x*r) mod q */
     mp_free(hxr);
+    mp_free(xr);
     mp_free(kinv);
     mp_free(k);
     mp_free(hash);
@@ -476,6 +489,7 @@ const ssh_keyalg ssh_dss = {
     dss_new_priv_openssh,
 
     dss_freekey,
+    dss_invalid,
     dss_sign,
     dss_verify,
     dss_public_blob,

+ 24 - 13
source/putty/sshecc.c

@@ -434,7 +434,7 @@ static WeierstrassPoint *ecdsa_decode(
     pinitassert(curve->type == EC_WEIERSTRASS);
     BinarySource src[1];
 
-    BinarySource_BARE_INIT(src, encoded.ptr, encoded.len);
+    BinarySource_BARE_INIT_PL(src, encoded);
     { // WINSCP
     unsigned char format_type = get_byte(src);
 
@@ -647,6 +647,13 @@ static void eddsa_freekey(ssh_key *key)
     sfree(ek);
 }
 
+static char *ec_signkey_invalid(ssh_key *key, unsigned flags)
+{
+    /* All validity criteria for both ECDSA and EdDSA were checked
+     * when we loaded the key in the first place */
+    return NULL;
+}
+
 static ssh_key *ecdsa_new_pub(const ssh_keyalg *alg, ptrlen data)
 {
     const struct ecsign_extra *extra =
@@ -655,7 +662,7 @@ static ssh_key *ecdsa_new_pub(const ssh_keyalg *alg, ptrlen data)
     pinitassert(curve->type == EC_WEIERSTRASS);
 
     BinarySource src[1];
-    BinarySource_BARE_INIT(src, data.ptr, data.len);
+    BinarySource_BARE_INIT_PL(src, data);
     get_string(src);
 
     /* Curve name is duplicated for Weierstrass form */
@@ -666,6 +673,7 @@ static ssh_key *ecdsa_new_pub(const ssh_keyalg *alg, ptrlen data)
     struct ecdsa_key *ek = snew(struct ecdsa_key);
     ek->sshk.vt = alg;
     ek->curve = curve;
+    ek->privateKey = NULL;
 
     ek->publicKey = get_wpoint(src, curve);
     if (!ek->publicKey) {
@@ -673,8 +681,6 @@ static ssh_key *ecdsa_new_pub(const ssh_keyalg *alg, ptrlen data)
         return NULL;
     }
 
-    ek->privateKey = NULL;
-
     return &ek->sshk;
     } // WINSCP
 }
@@ -687,7 +693,7 @@ static ssh_key *eddsa_new_pub(const ssh_keyalg *alg, ptrlen data)
     pinitassert(curve->type == EC_EDWARDS);
 
     BinarySource src[1];
-    BinarySource_BARE_INIT(src, data.ptr, data.len);
+    BinarySource_BARE_INIT_PL(src, data);
     get_string(src);
 
     { // WINSCP
@@ -797,7 +803,7 @@ static ssh_key *ecdsa_new_priv(const ssh_keyalg *alg, ptrlen pub, ptrlen priv)
     struct ecdsa_key *ek = container_of(sshk, struct ecdsa_key, sshk);
 
     BinarySource src[1];
-    BinarySource_BARE_INIT(src, priv.ptr, priv.len);
+    BinarySource_BARE_INIT_PL(src, priv);
     ek->privateKey = get_mp_ssh2(src);
 
     return &ek->sshk;
@@ -813,7 +819,7 @@ static ssh_key *eddsa_new_priv(const ssh_keyalg *alg, ptrlen pub, ptrlen priv)
     struct eddsa_key *ek = container_of(sshk, struct eddsa_key, sshk);
 
     BinarySource src[1];
-    BinarySource_BARE_INIT(src, priv.ptr, priv.len);
+    BinarySource_BARE_INIT_PL(src, priv);
     ek->privateKey = get_mp_le(src);
 
     return &ek->sshk;
@@ -844,8 +850,7 @@ static ssh_key *eddsa_new_priv_openssh(
      */
     { // WINSCP
     BinarySource subsrc[1];
-    BinarySource_BARE_INIT(
-        subsrc, privkey_extended_pl.ptr, privkey_extended_pl.len);
+    BinarySource_BARE_INIT_PL(subsrc, privkey_extended_pl);
     { // WINSCP
     ptrlen privkey_pl = get_data(subsrc, curve->fieldBytes);
     ptrlen pubkey_copy_pl = get_data(subsrc, curve->fieldBytes);
@@ -858,6 +863,7 @@ static ssh_key *eddsa_new_priv_openssh(
     struct eddsa_key *ek = snew(struct eddsa_key);
     ek->sshk.vt = alg;
     ek->curve = curve;
+    ek->privateKey = NULL;
 
     ek->publicKey = eddsa_decode(pubkey_pl, curve);
     if (!ek->publicKey) {
@@ -920,6 +926,7 @@ static ssh_key *ecdsa_new_priv_openssh(
     struct ecdsa_key *ek = snew(struct ecdsa_key);
     ek->sshk.vt = alg;
     ek->curve = curve;
+    ek->privateKey = NULL;
 
     ek->publicKey = get_wpoint(src, curve);
     if (!ek->publicKey) {
@@ -987,7 +994,7 @@ static bool ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data)
         (const struct ecsign_extra *)ek->sshk.vt->extra;
 
     BinarySource src[1];
-    BinarySource_BARE_INIT(src, sig.ptr, sig.len);
+    BinarySource_BARE_INIT_PL(src, sig);
 
     /* Check the signature starts with the algorithm name */
     if (!ptrlen_eq_string(get_string(src), ek->sshk.vt->ssh_id))
@@ -998,7 +1005,7 @@ static bool ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data)
     ptrlen sigstr = get_string(src);
     if (get_err(src))
         return false;
-    BinarySource_BARE_INIT(src, sigstr.ptr, sigstr.len);
+    BinarySource_BARE_INIT_PL(src, sigstr);
 
     /* Extract the signature integers r,s */
     { // WINSCP
@@ -1092,7 +1099,7 @@ static bool eddsa_verify(ssh_key *key, ptrlen sig, ptrlen data)
         (const struct ecsign_extra *)ek->sshk.vt->extra;
 
     BinarySource src[1];
-    BinarySource_BARE_INIT(src, sig.ptr, sig.len);
+    BinarySource_BARE_INIT_PL(src, sig);
 
     /* Check the signature starts with the algorithm name */
     if (!ptrlen_eq_string(get_string(src), ek->sshk.vt->ssh_id))
@@ -1104,7 +1111,7 @@ static bool eddsa_verify(ssh_key *key, ptrlen sig, ptrlen data)
     ptrlen sigstr = get_string(src);
     if (get_err(src))
         return false;
-    BinarySource_BARE_INIT(src, sigstr.ptr, sigstr.len);
+    BinarySource_BARE_INIT_PL(src, sigstr);
     { // WINSCP
     ptrlen rstr = get_data(src, ek->curve->fieldBytes);
     ptrlen sstr = get_data(src, ek->curve->fieldBytes);
@@ -1320,6 +1327,7 @@ const ssh_keyalg ssh_ecdsa_ed25519 = {
     eddsa_new_priv_openssh,
 
     eddsa_freekey,
+    ec_signkey_invalid,
     eddsa_sign,
     eddsa_verify,
     eddsa_public_blob,
@@ -1349,6 +1357,7 @@ const ssh_keyalg ssh_ecdsa_nistp256 = {
     ecdsa_new_priv_openssh,
 
     ecdsa_freekey,
+    ec_signkey_invalid,
     ecdsa_sign,
     ecdsa_verify,
     ecdsa_public_blob,
@@ -1378,6 +1387,7 @@ const ssh_keyalg ssh_ecdsa_nistp384 = {
     ecdsa_new_priv_openssh,
 
     ecdsa_freekey,
+    ec_signkey_invalid,
     ecdsa_sign,
     ecdsa_verify,
     ecdsa_public_blob,
@@ -1407,6 +1417,7 @@ const ssh_keyalg ssh_ecdsa_nistp521 = {
     ecdsa_new_priv_openssh,
 
     ecdsa_freekey,
+    ec_signkey_invalid,
     ecdsa_sign,
     ecdsa_verify,
     ecdsa_public_blob,

+ 6 - 0
source/putty/sshprng.c

@@ -297,3 +297,9 @@ void prng_add_entropy(prng *pr, unsigned source_id, ptrlen data)
         } // WINSCP
     }
 }
+
+size_t prng_seed_bits(prng *pr)
+{
+    prng_impl *pi = container_of(pr, prng_impl, Prng);
+    return pi->hashalg->hlen * 8;
+}

+ 7 - 7
source/putty/sshpubk.c

@@ -952,7 +952,7 @@ bool rfc4716_loadpub(FILE *fp, char **algorithm,
         error = "not enough data in SSH-2 public key file";
         goto error;
     }
-    alglen = toint(GET_32BIT(pubblob));
+    alglen = toint(GET_32BIT_MSB_FIRST(pubblob));
     if (alglen < 0 || alglen > pubbloblen-4) {
         error = "invalid algorithm prefix in SSH-2 public key file";
         goto error;
@@ -1027,7 +1027,7 @@ bool openssh_loadpub_line(char * aline, char **algorithm, // WINSCP
      */
     alglen = strlen(line);
     if (pubbloblen < alglen + 4 ||
-        GET_32BIT(pubblob) != alglen ||
+        GET_32BIT_MSB_FIRST(pubblob) != alglen ||
         0 != memcmp(pubblob + 4, line, alglen)) {
         error = "key algorithms do not match in OpenSSH public key file";
         goto error;
@@ -1508,7 +1508,7 @@ void ssh2_write_pubkey(FILE *fp, const char *comment,
 /* ----------------------------------------------------------------------
  * Utility functions to compute SSH-2 fingerprints in a uniform way.
  */
-char *ssh2_fingerprint_blob(const void *blob, int bloblen)
+char *ssh2_fingerprint_blob(ptrlen blob)
 {
     unsigned char digest[32];
     char fingerprint_str_md5[16*3];
@@ -1521,7 +1521,7 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen)
     /*
      * The fingerprint hash itself is always just the MD5 of the blob.
      */
-    hash_simple(&ssh_md5, make_ptrlen(blob, bloblen), digest);
+    hash_simple(&ssh_md5, blob, digest);
     for (i = 0; i < 16; i++)
         sprintf(fingerprint_str_md5 + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
 
@@ -1531,12 +1531,12 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen)
     /*
      * Identify the key algorithm, if possible.
      */
-    BinarySource_BARE_INIT(src, blob, bloblen);
+    BinarySource_BARE_INIT_PL(src, blob);
     algname = get_string(src);
     if (!get_err(src)) {
         alg = find_pubkey_alg_len(algname);
         if (alg) {
-            int bits = ssh_key_public_bits(alg, make_ptrlen(blob, bloblen));
+            int bits = ssh_key_public_bits(alg, blob);
             return dupprintf("%.*s %d %s %s", PTRLEN_PRINTF(algname),
                              bits, fingerprint_str_md5, fingerprint_str_sha256);
         } else {
@@ -1557,7 +1557,7 @@ char *ssh2_fingerprint(ssh_key *data)
     strbuf *blob = strbuf_new();
     char *ret; //MPEXT
     ssh_key_public_blob(data, BinarySink_UPCAST(blob));
-    ret = ssh2_fingerprint_blob(blob->s, blob->len);
+    ret = ssh2_fingerprint_blob(ptrlen_from_strbuf(blob));
     strbuf_free(blob);
     return ret;
 }

+ 6 - 0
source/putty/sshrand.c

@@ -149,4 +149,10 @@ void random_get_savedata(void **data, int *len)
     WINSCP_PUTTY_SECTION_LEAVE;
 }
 
+size_t random_seed_bits(void)
+{
+    assert(random_active > 0);
+    return prng_seed_bits(global_prng);
+}
+
 #endif /* FUZZING */

+ 125 - 78
source/putty/sshrsa.c

@@ -375,7 +375,7 @@ int rsa_ssh1_public_blob_len(ptrlen data)
 {
     BinarySource src[1];
 
-    BinarySource_BARE_INIT(src, data.ptr, data.len);
+    BinarySource_BARE_INIT_PL(src, data);
 
     /* Expect a length word, then exponent and modulus. (It doesn't
      * even matter which order.) */
@@ -438,7 +438,7 @@ static ssh_key *rsa2_new_pub(const ssh_keyalg *self, ptrlen data)
     BinarySource src[1];
     RSAKey *rsa;
 
-    BinarySource_BARE_INIT(src, data.ptr, data.len);
+    BinarySource_BARE_INIT_PL(src, data);
     if (!ptrlen_eq_string(get_string(src), "ssh-rsa"))
 	return NULL;
 
@@ -502,7 +502,7 @@ static ssh_key *rsa2_new_priv(const ssh_keyalg *self,
         return NULL;
 
     rsa = container_of(sshk, RSAKey, sshk);
-    BinarySource_BARE_INIT(src, priv.ptr, priv.len);
+    BinarySource_BARE_INIT_PL(src, priv);
     rsa->private_exponent = get_mp_ssh2(src);
     rsa->p = get_mp_ssh2(src);
     rsa->q = get_mp_ssh2(src);
@@ -569,76 +569,109 @@ static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
     return ret;
 }
 
-/*
- * This is the magic ASN.1/DER prefix that goes in the decoded
- * signature, between the string of FFs and the actual SHA hash
- * value. The meaning of it is:
- * 
- * 00 -- this marks the end of the FFs; not part of the ASN.1 bit itself
- * 
- * 30 21 -- a constructed SEQUENCE of length 0x21
- *    30 09 -- a constructed sub-SEQUENCE of length 9
- *       06 05 -- an object identifier, length 5
- *          2B 0E 03 02 1A -- object id { 1 3 14 3 2 26 }
- *                            (the 1,3 comes from 0x2B = 43 = 40*1+3)
- *       05 00 -- NULL
- *    04 14 -- a primitive OCTET STRING of length 0x14
- *       [0x14 bytes of hash data follows]
- * 
- * The object id in the middle there is listed as `id-sha1' in
- * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1d2.asn (the
- * ASN module for PKCS #1) and its expanded form is as follows:
- * 
- * id-sha1                OBJECT IDENTIFIER ::= {
- *    iso(1) identified-organization(3) oiw(14) secsig(3)
- *    algorithms(2) 26 }
- */
-static const unsigned char sha1_asn1_prefix[] = {
-    0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B,
-    0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14,
-};
+static inline const ssh_hashalg *rsa2_hash_alg_for_flags(
+    unsigned flags, const char **protocol_id_out)
+{
+    const ssh_hashalg *halg;
+    const char *protocol_id;
 
-/*
- * Two more similar pieces of ASN.1 used for signatures using SHA-256
- * and SHA-512, in the same format but differing only in various
- * length fields and OID.
- */
-static const unsigned char sha256_asn1_prefix[] = {
-    0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
-    0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
-    0x05, 0x00, 0x04, 0x20,
-};
-static const unsigned char sha512_asn1_prefix[] = {
-    0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
-    0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
-    0x05, 0x00, 0x04, 0x40,
-};
+    if (flags & SSH_AGENT_RSA_SHA2_256) {
+        halg = &ssh_sha256;
+        protocol_id = "rsa-sha2-256";
+    } else if (flags & SSH_AGENT_RSA_SHA2_512) {
+        halg = &ssh_sha512;
+        protocol_id = "rsa-sha2-512";
+    } else {
+        halg = &ssh_sha1;
+        protocol_id = "ssh-rsa";
+    }
 
-#define SHA1_ASN1_PREFIX_LEN sizeof(sha1_asn1_prefix)
+    if (protocol_id_out)
+        *protocol_id_out = protocol_id;
 
-static unsigned char *rsa_pkcs1_signature_string(
-    size_t nbytes, const ssh_hashalg *halg, ptrlen data)
+    return halg;
+}
+
+static inline ptrlen rsa_pkcs1_prefix_for_hash(const ssh_hashalg *halg)
 {
-    const unsigned char *asn1_prefix;
-    unsigned asn1_prefix_size;
+    if (halg == &ssh_sha1) {
+        /*
+         * This is the magic ASN.1/DER prefix that goes in the decoded
+         * signature, between the string of FFs and the actual SHA-1
+         * hash value. The meaning of it is:
+         *
+         * 00 -- this marks the end of the FFs; not part of the ASN.1
+         * bit itself
+         *
+         * 30 21 -- a constructed SEQUENCE of length 0x21
+         *    30 09 -- a constructed sub-SEQUENCE of length 9
+         *       06 05 -- an object identifier, length 5
+         *          2B 0E 03 02 1A -- object id { 1 3 14 3 2 26 }
+         *                            (the 1,3 comes from 0x2B = 43 = 40*1+3)
+         *       05 00 -- NULL
+         *    04 14 -- a primitive OCTET STRING of length 0x14
+         *       [0x14 bytes of hash data follows]
+         *
+         * The object id in the middle there is listed as `id-sha1' in
+         * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1d2.asn
+         * (the ASN module for PKCS #1) and its expanded form is as
+         * follows:
+         *
+         * id-sha1                OBJECT IDENTIFIER ::= {
+         *    iso(1) identified-organization(3) oiw(14) secsig(3)
+         *    algorithms(2) 26 }
+         */
+        static const unsigned char sha1_asn1_prefix[] = {
+            0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B,
+            0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14,
+        };
+        return PTRLEN_FROM_CONST_BYTES(sha1_asn1_prefix);
+    }
 
     if (halg == &ssh_sha256) {
-        asn1_prefix = sha256_asn1_prefix;
-        asn1_prefix_size = sizeof(sha256_asn1_prefix);
-    } else if (halg == &ssh_sha512) {
-        asn1_prefix = sha512_asn1_prefix;
-        asn1_prefix_size = sizeof(sha512_asn1_prefix);
-    } else {
-        assert(halg == &ssh_sha1);
-        asn1_prefix = sha1_asn1_prefix;
-        asn1_prefix_size = sizeof(sha1_asn1_prefix);
+        /*
+         * A similar piece of ASN.1 used for signatures using SHA-256,
+         * in the same format but differing only in various length
+         * fields and OID.
+         */
+        static const unsigned char sha256_asn1_prefix[] = {
+            0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
+            0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+            0x05, 0x00, 0x04, 0x20,
+        };
+        return PTRLEN_FROM_CONST_BYTES(sha256_asn1_prefix);
     }
 
-    { // WINSCP
-    size_t fixed_parts = halg->hlen + asn1_prefix_size + 2;
+    if (halg == &ssh_sha512) {
+        /*
+         * And one more for SHA-512.
+         */
+        static const unsigned char sha512_asn1_prefix[] = {
+            0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
+            0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
+            0x05, 0x00, 0x04, 0x40,
+        };
+        return PTRLEN_FROM_CONST_BYTES(sha512_asn1_prefix);
+    }
+
+    unreachable("bad hash algorithm for RSA PKCS#1");
+}
+
+static inline size_t rsa_pkcs1_length_of_fixed_parts(const ssh_hashalg *halg)
+{
+    ptrlen asn1_prefix = rsa_pkcs1_prefix_for_hash(halg);
+    return halg->hlen + asn1_prefix.len + 2;
+}
+
+static unsigned char *rsa_pkcs1_signature_string(
+    size_t nbytes, const ssh_hashalg *halg, ptrlen data)
+{
+    size_t fixed_parts = rsa_pkcs1_length_of_fixed_parts(halg);
     pinitassert(nbytes >= fixed_parts);
     size_t padding = nbytes - fixed_parts;
 
+    ptrlen asn1_prefix = rsa_pkcs1_prefix_for_hash(halg);
+
     unsigned char *bytes = snewn(nbytes, unsigned char);
 
     bytes[0] = 0;
@@ -646,16 +679,15 @@ static unsigned char *rsa_pkcs1_signature_string(
 
     memset(bytes + 2, 0xFF, padding);
 
-    memcpy(bytes + 2 + padding, asn1_prefix, asn1_prefix_size);
+    memcpy(bytes + 2 + padding, asn1_prefix.ptr, asn1_prefix.len);
 
     { // WINSCP
     ssh_hash *h = ssh_hash_new(halg);
     put_datapl(h, data);
-    ssh_hash_final(h, bytes + 2 + padding + asn1_prefix_size);
+    ssh_hash_final(h, bytes + 2 + padding + asn1_prefix.len);
     } // WINSCP
 
     return bytes;
-    } // WINSCP
 }
 
 static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
@@ -665,7 +697,16 @@ static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
     ptrlen type, in_pl;
     mp_int *in, *out;
 
-    BinarySource_BARE_INIT(src, sig.ptr, sig.len);
+    /* If we need to support variable flags on verify, this is where they go */
+    const ssh_hashalg *halg = rsa2_hash_alg_for_flags(0, NULL);
+
+    /* Start by making sure the key is even long enough to encode a
+     * signature. If not, everything fails to verify. */
+    size_t nbytes = (mp_get_nbits(rsa->modulus) + 7) / 8;
+    if (nbytes < rsa_pkcs1_length_of_fixed_parts(halg))
+        return false;
+
+    BinarySource_BARE_INIT_PL(src, sig);
     type = get_string(src);
     /*
      * RFC 4253 section 6.6: the signature integer in an ssh-rsa
@@ -689,8 +730,7 @@ static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
     { // WINSCP
     unsigned diff = 0;
 
-    size_t nbytes = (mp_get_nbits(rsa->modulus) + 7) / 8;
-    unsigned char *bytes = rsa_pkcs1_signature_string(nbytes, &ssh_sha1, data);
+    unsigned char *bytes = rsa_pkcs1_signature_string(nbytes, halg, data);
     size_t i; // WINSCP
     for (i = 0; i < nbytes; i++)
         diff |= bytes[nbytes-1 - i] ^ mp_get_byte(out, i);
@@ -712,16 +752,7 @@ static void rsa2_sign(ssh_key *key, ptrlen data,
     const ssh_hashalg *halg;
     const char *sign_alg_name;
 
-    if (flags & SSH_AGENT_RSA_SHA2_256) {
-        halg = &ssh_sha256;
-        sign_alg_name = "rsa-sha2-256";
-    } else if (flags & SSH_AGENT_RSA_SHA2_512) {
-        halg = &ssh_sha512;
-        sign_alg_name = "rsa-sha2-512";
-    } else {
-        halg = &ssh_sha1;
-        sign_alg_name = "ssh-rsa";
-    }
+    halg = rsa2_hash_alg_for_flags(flags, &sign_alg_name);
 
     nbytes = (mp_get_nbits(rsa->modulus) + 7) / 8;
 
@@ -745,12 +776,28 @@ static void rsa2_sign(ssh_key *key, ptrlen data,
     mp_free(out);
 }
 
+char *rsa2_invalid(ssh_key *key, unsigned flags)
+{
+    RSAKey *rsa = container_of(key, RSAKey, sshk);
+    size_t bits = mp_get_nbits(rsa->modulus), nbytes = (bits + 7) / 8;
+    const char *sign_alg_name;
+    const ssh_hashalg *halg = rsa2_hash_alg_for_flags(flags, &sign_alg_name);
+    if (nbytes < rsa_pkcs1_length_of_fixed_parts(halg)) {
+        return dupprintf(
+            "%zu-bit RSA key is too short to generate %s signatures",
+            bits, sign_alg_name);
+    }
+
+    return NULL;
+}
+
 const ssh_keyalg ssh_rsa = {
     rsa2_new_pub,
     rsa2_new_priv,
     rsa2_new_priv_openssh,
 
     rsa2_freekey,
+    rsa2_invalid,
     rsa2_sign,
     rsa2_verify,
     rsa2_public_blob,

+ 2 - 1
source/putty/sshsh256.c

@@ -22,7 +22,8 @@
 #       define HW_SHA256 HW_SHA256_NI
 #   endif
 #elif defined(__GNUC__)
-#    if (__GNUC__ >= 5) && (defined(__x86_64__) || defined(__i386))
+#    if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
+        (defined(__x86_64__) || defined(__i386))
 #       define HW_SHA256 HW_SHA256_NI
 #    endif
 #elif defined (_MSC_VER)

+ 2 - 1
source/putty/sshsha.c

@@ -22,7 +22,8 @@
 #       define HW_SHA1 HW_SHA1_NI
 #   endif
 #elif defined(__GNUC__)
-#    if (__GNUC__ >= 5) && (defined(__x86_64__) || defined(__i386))
+#    if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
+        (defined(__x86_64__) || defined(__i386))
 #       define HW_SHA1 HW_SHA1_NI
 #    endif
 #elif defined (_MSC_VER)

+ 13 - 13
source/putty/sshshare.c

@@ -164,7 +164,7 @@ struct ssh_sharing_connstate {
     int curr_packetlen;
 
     unsigned char recvbuf[0x4010];
-    int recvlen;
+    size_t recvlen;
 
     /*
      * Assorted state we have to remember about this downstream, so
@@ -776,7 +776,7 @@ static void send_packet_to_downstream(struct ssh_sharing_connstate *cs,
             put_data(packet, data.ptr, this_len);
             data.ptr = (const char *)data.ptr + this_len;
             data.len -= this_len;
-            PUT_32BIT(packet->s, packet->len-4);
+            PUT_32BIT_MSB_FIRST(packet->s, packet->len-4);
             sk_write(cs->sock, packet->s, packet->len);
             strbuf_free(packet);
         } while (data.len > 0);
@@ -788,7 +788,7 @@ static void send_packet_to_downstream(struct ssh_sharing_connstate *cs,
         put_uint32(packet, 0);     /* placeholder for length field */
         put_byte(packet, type);
         put_data(packet, pkt, pktlen);
-        PUT_32BIT(packet->s, packet->len-4);
+        PUT_32BIT_MSB_FIRST(packet->s, packet->len-4);
         sk_write(cs->sock, packet->s, packet->len);
         strbuf_free(packet);
     }
@@ -1052,7 +1052,7 @@ void share_xchannel_confirmation(struct ssh_sharing_connstate *cs,
         xc->msghead = msg->next;
 
         if (msg->datalen >= 4)
-            PUT_32BIT(msg->data, chan->downstream_id);
+            PUT_32BIT_MSB_FIRST(msg->data, chan->downstream_id);
         send_packet_to_downstream(cs, msg->type,
                                   msg->data, msg->datalen, chan);
 
@@ -1239,7 +1239,7 @@ void share_got_pkt_from_server(ssh_sharing_connstate *cs, int type,
              */
             unsigned char *rewritten = snewn(pktlen, unsigned char);
             memcpy(rewritten, pkt, pktlen);
-            PUT_32BIT(rewritten + id_pos, chan->downstream_id);
+            PUT_32BIT_MSB_FIRST(rewritten + id_pos, chan->downstream_id);
             send_packet_to_downstream(cs, type, rewritten, pktlen, chan);
             sfree(rewritten);
 
@@ -1248,8 +1248,8 @@ void share_got_pkt_from_server(ssh_sharing_connstate *cs, int type,
              */
             if (type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
                 if (chan->state == UNACKNOWLEDGED && pktlen >= 8) {
-                    share_channel_set_server_id(cs, chan, GET_32BIT(pkt+4),
-                                                OPEN);
+                    share_channel_set_server_id(
+                        cs, chan, GET_32BIT_MSB_FIRST(pkt+4), OPEN);
                     if (!cs->sock) {
                         /* Retry cleaning up this connection, so that we
                          * can send an immediate CLOSE on this channel for
@@ -1490,7 +1490,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
             goto confused;
         }
         share_add_channel(cs, old_id, new_id, 0, UNACKNOWLEDGED, maxpkt);
-        PUT_32BIT(pkt + id_pos, new_id);
+        PUT_32BIT_MSB_FIRST(pkt + id_pos, new_id);
         ssh_send_packet_from_downstream(cs->parent->cl, cs->id,
                                         type, pkt, pktlen, NULL);
         break;
@@ -1523,7 +1523,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
             goto confused;
         }
             
-        PUT_32BIT(pkt + id_pos, new_id);
+        PUT_32BIT_MSB_FIRST(pkt + id_pos, new_id);
 
         chan = share_add_channel(cs, old_id, new_id, server_id, OPEN, maxpkt);
 
@@ -1532,7 +1532,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
                                             type, pkt, pktlen, NULL);
             share_remove_halfchannel(cs, hc);
         } else if (xc) {
-            unsigned downstream_window = GET_32BIT(pkt + 8);
+            unsigned downstream_window = GET_32BIT_MSB_FIRST(pkt + 8);
             if (downstream_window < 256) {
                 err = dupprintf("Initial window size for x11 channel must be at least 256 (got %u)", downstream_window);
                 goto confused;
@@ -1754,7 +1754,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
         (c) = (unsigned char)*data++;                           \
     } while (0)
 
-static void share_receive(Plug *plug, int urgent, char *data, int len)
+static void share_receive(Plug *plug, int urgent, const char *data, size_t len)
 {
     ssh_sharing_connstate *cs = container_of(
         plug, ssh_sharing_connstate, plug);
@@ -1808,7 +1808,7 @@ static void share_receive(Plug *plug, int urgent, char *data, int len)
             crGetChar(c);
             cs->recvbuf[cs->recvlen++] = c;
         }
-        cs->curr_packetlen = toint(GET_32BIT(cs->recvbuf) + 4);
+        cs->curr_packetlen = toint(GET_32BIT_MSB_FIRST(cs->recvbuf) + 4);
         if (cs->curr_packetlen < 5 ||
             cs->curr_packetlen > sizeof(cs->recvbuf)) {
             char *buf = dupprintf("Bad packet length %u\n",
@@ -1830,7 +1830,7 @@ static void share_receive(Plug *plug, int urgent, char *data, int len)
     crFinishV;
 }
 
-static void share_sent(Plug *plug, int bufsize)
+static void share_sent(Plug *plug, size_t bufsize)
 {
     /* ssh_sharing_connstate *cs = container_of(
         plug, ssh_sharing_connstate, plug); */

+ 16 - 17
source/putty/sshverstring.c

@@ -29,7 +29,7 @@ struct ssh_verstring_state {
     char prefix[PREFIX_MAXLEN];
     char *impl_name;
     char *vstring;
-    int vslen, vstrsize;
+    size_t vslen, vstrsize;
     char *protoversion;
     const char *softwareversion;
 
@@ -249,19 +249,18 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp)
          * If we didn't find it, consume data until we see a newline.
          */
         while (1) {
-            int len;
-            void *data;
+            ptrlen data;
             char *nl;
 
             /* Wait to receive at least 1 byte, but then consume more
              * than that if it's there. */
             BPP_WAITFOR(1);
-            bufchain_prefix(s->bpp.in_raw, &data, &len);
-            if ((nl = memchr(data, '\012', len)) != NULL) {
-                bufchain_consume(s->bpp.in_raw, nl - (char *)data + 1);
+            data = bufchain_prefix(s->bpp.in_raw);
+            if ((nl = memchr(data.ptr, '\012', data.len)) != NULL) {
+                bufchain_consume(s->bpp.in_raw, nl - (char *)data.ptr + 1);
                 break;
             } else {
-                bufchain_consume(s->bpp.in_raw, len);
+                bufchain_consume(s->bpp.in_raw, data.len);
             }
         }
     }
@@ -281,24 +280,24 @@ void ssh_verstring_handle_input(BinaryPacketProtocol *bpp)
      */
     s->i = 0;
     do {
-        int len;
-        void *data;
+        ptrlen data;
         char *nl;
 
         BPP_WAITFOR(1);
-        bufchain_prefix(s->bpp.in_raw, &data, &len);
-        if ((nl = memchr(data, '\012', len)) != NULL) {
-            len = nl - (char *)data + 1;
+        data = bufchain_prefix(s->bpp.in_raw);
+        if ((nl = memchr(data.ptr, '\012', data.len)) != NULL) {
+            data.len = nl - (char *)data.ptr + 1;
         }
 
-        if (s->vslen + len >= s->vstrsize - 1) {
-            s->vstrsize = (s->vslen + len) * 5 / 4 + 32;
+        if (s->vslen >= s->vstrsize - 1 ||
+            data.len >= s->vstrsize - 1 - s->vslen) {
+            s->vstrsize = (s->vslen + data.len) * 5 / 4 + 32;
             s->vstring = sresize(s->vstring, s->vstrsize, char);
         }
 
-        memcpy(s->vstring + s->vslen, data, len);
-        s->vslen += len;
-        bufchain_consume(s->bpp.in_raw, len);
+        memcpy(s->vstring + s->vslen, data.ptr, data.len);
+        s->vslen += data.len;
+        bufchain_consume(s->bpp.in_raw, data.len);
 
     } while (s->vstring[s->vslen-1] != '\012');
 

+ 13 - 15
source/putty/utils.c

@@ -654,7 +654,7 @@ void bufchain_clear(bufchain *ch)
     ch->buffersize = 0;
 }
 
-int bufchain_size(bufchain *ch)
+size_t bufchain_size(bufchain *ch)
 {
     return ch->buffersize;
 }
@@ -667,7 +667,7 @@ void bufchain_set_callback_inner(
     ch->ic = ic;
 }
 
-void bufchain_add(bufchain *ch, const void *data, int len)
+void bufchain_add(bufchain *ch, const void *data, size_t len)
 {
     const char *buf = (const char *)data;
 
@@ -677,14 +677,14 @@ void bufchain_add(bufchain *ch, const void *data, int len)
 
     while (len > 0) {
 	if (ch->tail && ch->tail->bufend < ch->tail->bufmax) {
-	    int copylen = min(len, ch->tail->bufmax - ch->tail->bufend);
+	    size_t copylen = min(len, ch->tail->bufmax - ch->tail->bufend);
 	    memcpy(ch->tail->bufend, buf, copylen);
 	    buf += copylen;
 	    len -= copylen;
 	    ch->tail->bufend += copylen;
 	}
 	if (len > 0) {
-	    int grainlen =
+	    size_t grainlen =
 		max(sizeof(struct bufchain_granule) + len, BUFFER_MIN_GRANULE);
 	    struct bufchain_granule *newbuf;
 	    newbuf = smalloc(grainlen);
@@ -704,7 +704,7 @@ void bufchain_add(bufchain *ch, const void *data, int len)
         ch->queue_idempotent_callback(ch->ic);
 }
 
-void bufchain_consume(bufchain *ch, int len)
+void bufchain_consume(bufchain *ch, size_t len)
 {
     struct bufchain_granule *tmp;
 
@@ -726,13 +726,12 @@ void bufchain_consume(bufchain *ch, int len)
     }
 }
 
-void bufchain_prefix(bufchain *ch, void **data, int *len)
+ptrlen bufchain_prefix(bufchain *ch)
 {
-    *len = ch->head->bufend - ch->head->bufpos;
-    *data = ch->head->bufpos;
+    return make_ptrlen(ch->head->bufpos, ch->head->bufend - ch->head->bufpos);
 }
 
-void bufchain_fetch(bufchain *ch, void *data, int len)
+void bufchain_fetch(bufchain *ch, void *data, size_t len)
 {
     struct bufchain_granule *tmp;
     char *data_c = (char *)data;
@@ -754,13 +753,13 @@ void bufchain_fetch(bufchain *ch, void *data, int len)
     }
 }
 
-void bufchain_fetch_consume(bufchain *ch, void *data, int len)
+void bufchain_fetch_consume(bufchain *ch, void *data, size_t len)
 {
     bufchain_fetch(ch, data, len);
     bufchain_consume(ch, len);
 }
 
-bool bufchain_try_fetch_consume(bufchain *ch, void *data, int len)
+bool bufchain_try_fetch_consume(bufchain *ch, void *data, size_t len)
 {
     if (ch->buffersize >= len) {
         bufchain_fetch_consume(ch, data, len);
@@ -770,7 +769,7 @@ bool bufchain_try_fetch_consume(bufchain *ch, void *data, int len)
     }
 }
 
-int bufchain_fetch_consume_up_to(bufchain *ch, void *data, int len)
+size_t bufchain_fetch_consume_up_to(bufchain *ch, void *data, size_t len)
 {
     if (len > ch->buffersize)
         len = ch->buffersize;
@@ -786,10 +785,9 @@ int bufchain_fetch_consume_up_to(bufchain *ch, void *data, int len)
  * sequences.
  */
 
-void sanitise_term_data(bufchain *out, const void *vdata, int len)
+void sanitise_term_data(bufchain *out, const void *vdata, size_t len)
 {
     const char *data = (const char *)vdata;
-    int i;
 
     /*
      * FIXME: this method of sanitisation is ASCII-centric. It would
@@ -798,7 +796,7 @@ void sanitise_term_data(bufchain *out, const void *vdata, int len)
      * (not to mention knowing what character set it should interpret
      * the data as).
      */
-    for (i = 0; i < len; i++) {
+    for (size_t i = 0; i < len; i++) {
         if (data[i] == '\n')
             bufchain_add(out, "\r\n", 2);
         else if (data[i] >= ' ' && data[i] < 0x7F)

+ 11 - 14
source/putty/windows/winhandl.c

@@ -257,7 +257,7 @@ struct handle_output {
      * Data set by the main thread before signalling ev_from_main,
      * and read by the input thread after receiving that signal.
      */
-    char *buffer;		       /* the data to write */
+    const char *buffer;                /* the data to write */
     DWORD len;			       /* how much data there is */
 
     /*
@@ -347,13 +347,10 @@ static DWORD WINAPI handle_output_threadfunc(void *param)
 
 static void handle_try_output(struct handle_output *ctx)
 {
-    void *senddata;
-    int sendlen;
-
     if (!ctx->busy && bufchain_size(&ctx->queued_data)) {
-	bufchain_prefix(&ctx->queued_data, &senddata, &sendlen);
-	ctx->buffer = senddata;
-	ctx->len = sendlen;
+	ptrlen data = bufchain_prefix(&ctx->queued_data);
+	ctx->buffer = data.ptr;
+	ctx->len = min(data.len, ~(DWORD)0);
 	SetEvent(ctx->ev_from_main);
 	ctx->busy = true;
     } else if (!ctx->busy && bufchain_size(&ctx->queued_data) == 0 &&
@@ -515,7 +512,7 @@ struct handle *handle_add_foreign_event(HANDLE event,
     return h;
 }
 
-int handle_write(struct handle *h, const void *data, int len)
+size_t handle_write(struct handle *h, const void *data, size_t len)
 {
     assert(h->type == HT_OUTPUT);
     assert(h->u.o.outgoingeof == EOF_NO);
@@ -676,9 +673,9 @@ void handle_got_event(HANDLE event)
 	     * EOF, or (nearly equivalently) read error.
 	     */
 	    h->u.i.defunct = true;
-	    h->u.i.gotdata(h, NULL, -h->u.i.readerr);
+	    h->u.i.gotdata(h, NULL, 0, h->u.i.readerr);
 	} else {
-	    backlog = h->u.i.gotdata(h, h->u.i.buffer, h->u.i.len);
+	    backlog = h->u.i.gotdata(h, h->u.i.buffer, h->u.i.len, 0);
 	    handle_throttle(&h->u.i, backlog);
 	}
     #ifdef MPEXT
@@ -702,11 +699,11 @@ void handle_got_event(HANDLE event)
 	     * thread is terminating by now).
 	     */
 	    h->u.o.defunct = true;
-	    h->u.o.sentdata(h, -h->u.o.writeerr);
+	    h->u.o.sentdata(h, 0, h->u.o.writeerr);
 	} else {
 	    bufchain_consume(&h->u.o.queued_data, h->u.o.lenwritten);
             noise_ultralight(NOISE_SOURCE_IOLEN, h->u.o.lenwritten);
-	    h->u.o.sentdata(h, bufchain_size(&h->u.o.queued_data));
+	    h->u.o.sentdata(h, bufchain_size(&h->u.o.queued_data), 0);
 	    handle_try_output(&h->u.o);
 	}
     #ifdef MPEXT
@@ -726,13 +723,13 @@ void handle_got_event(HANDLE event)
     }
 }
 
-void handle_unthrottle(struct handle *h, int backlog)
+void handle_unthrottle(struct handle *h, size_t backlog)
 {
     assert(h->type == HT_INPUT);
     handle_throttle(&h->u.i, backlog);
 }
 
-int handle_backlog(struct handle *h)
+size_t handle_backlog(struct handle *h)
 {
     assert(h->type == HT_OUTPUT);
     return bufchain_size(&h->u.o.queued_data);

+ 15 - 18
source/putty/windows/winhsock.c

@@ -49,11 +49,12 @@ typedef struct HandleSocket {
     Socket sock;
 } HandleSocket;
 
-static int handle_gotdata(struct handle *h, void *data, int len)
+static size_t handle_gotdata(
+    struct handle *h, const void *data, size_t len, int err)
 {
     HandleSocket *hs = (HandleSocket *)handle_get_privdata(h);
 
-    if (len < 0) {
+    if (err) {
 	plug_closing(hs->plug, "Read error from handle", 0, 0);
 	return 0;
     } else if (len == 0) {
@@ -83,11 +84,12 @@ static int handle_gotdata(struct handle *h, void *data, int len)
     }
 }
 
-static int handle_stderr(struct handle *h, void *data, int len)
+static size_t handle_stderr(
+    struct handle *h, const void *data, size_t len, int err)
 {
     HandleSocket *hs = (HandleSocket *)handle_get_privdata(h);
 
-    if (len > 0)
+    if (!err && len > 0)
     {
         log_proxy_stderr(hs->plug, &hs->stderrdata, data, len);
     }
@@ -95,15 +97,12 @@ static int handle_stderr(struct handle *h, void *data, int len)
     return 0;
 }
 
-static void handle_sentdata(struct handle *h, int new_backlog)
+static void handle_sentdata(struct handle *h, size_t new_backlog, int err)
 {
     HandleSocket *hs = (HandleSocket *)handle_get_privdata(h);
 
-    if (new_backlog < 0) {
-        /* Special case: this is actually reporting an error writing
-         * to the underlying handle, and our input value is the error
-         * code itself, negated. */
-        plug_closing(hs->plug, win_strerror(-new_backlog), -new_backlog, 0);
+    if (err) {
+        plug_closing(hs->plug, win_strerror(err), err, 0);
         return;
     }
 
@@ -154,14 +153,14 @@ static void sk_handle_close(Socket *s)
     sfree(hs);
 }
 
-static int sk_handle_write(Socket *s, const void *data, int len)
+static size_t sk_handle_write(Socket *s, const void *data, size_t len)
 {
     HandleSocket *hs = container_of(s, HandleSocket, sock);
 
     return handle_write(hs->send_h, data, len);
 }
 
-static int sk_handle_write_oob(Socket *s, const void *data, int len)
+static size_t sk_handle_write_oob(Socket *s, const void *data, size_t len)
 {
     /*
      * oob data is treated as inband; nasty, but nothing really
@@ -186,8 +185,6 @@ static void sk_handle_flush(Socket *s)
 static void handle_socket_unfreeze(void *hsv)
 {
     HandleSocket *hs = (HandleSocket *)hsv;
-    void *data;
-    int len;
 
     /*
      * If we've been put into a state other than THAWING since the
@@ -199,16 +196,16 @@ static void handle_socket_unfreeze(void *hsv)
     /*
      * Get some of the data we've buffered.
      */
-    bufchain_prefix(&hs->inputdata, &data, &len);
-    assert(len > 0);
+    ptrlen data = bufchain_prefix(&hs->inputdata);
+    assert(data.len > 0);
 
     /*
      * Hand it off to the plug. Be careful of re-entrance - that might
      * have the effect of trying to close this socket.
      */
     hs->defer_close = true;
-    plug_receive(hs->plug, 0, data, len);
-    bufchain_consume(&hs->inputdata, len);
+    plug_receive(hs->plug, 0, data.ptr, data.len);
+    bufchain_consume(&hs->inputdata, data.len);
     hs->defer_close = false;
     if (hs->deferred_close) {
         sk_handle_close(&hs->sock);

+ 12 - 8
source/putty/windows/winnet.c

@@ -64,7 +64,7 @@ struct NetSocket {
                            * notification while we were frozen */
     bool localhost_only;               /* for listening sockets */
     char oobdata[1];
-    int sending_oob;
+    size_t sending_oob;
     bool oobinline, nodelay, keepalive, privport;
     enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;
     SockAddr *addr;
@@ -856,8 +856,8 @@ static void sk_net_flush(Socket *s)
 }
 
 static void sk_net_close(Socket *s);
-static int sk_net_write(Socket *s, const void *data, int len);
-static int sk_net_write_oob(Socket *s, const void *data, int len);
+static size_t sk_net_write(Socket *s, const void *data, size_t len);
+static size_t sk_net_write_oob(Socket *s, const void *data, size_t len);
 static void sk_net_write_eof(Socket *s);
 static void sk_net_set_frozen(Socket *s, bool is_frozen);
 static const char *sk_net_socket_error(Socket *s);
@@ -1486,8 +1486,9 @@ void try_send(NetSocket *s)
     while (s->sending_oob || bufchain_size(&s->output_data) > 0) {
 	int nsent;
 	DWORD err;
-	void *data;
-	int len, urgentflag;
+	const void *data;
+	size_t len;
+        int urgentflag;
 
 	if (s->sending_oob) {
 	    urgentflag = MSG_OOB;
@@ -1495,8 +1496,11 @@ void try_send(NetSocket *s)
 	    data = &s->oobdata;
 	} else {
 	    urgentflag = 0;
-	    bufchain_prefix(&s->output_data, &data, &len);
+            ptrlen bufdata = bufchain_prefix(&s->output_data);
+            data = bufdata.ptr;
+            len = bufdata.len;
 	}
+        len = min(len, INT_MAX);       /* WinSock send() takes an int */
 	nsent = p_send(s->s, data, len, urgentflag);
 	noise_ultralight(NOISE_SOURCE_IOLEN, nsent);
 	if (nsent <= 0) {
@@ -1552,7 +1556,7 @@ void try_send(NetSocket *s)
     }
 }
 
-static int sk_net_write(Socket *sock, const void *buf, int len)
+static size_t sk_net_write(Socket *sock, const void *buf, size_t len)
 {
     NetSocket *s = container_of(sock, NetSocket, sock);
 
@@ -1572,7 +1576,7 @@ static int sk_net_write(Socket *sock, const void *buf, int len)
     return bufchain_size(&s->output_data);
 }
 
-static int sk_net_write_oob(Socket *sock, const void *buf, int len)
+static size_t sk_net_write_oob(Socket *sock, const void *buf, size_t len)
 {
     NetSocket *s = container_of(sock, NetSocket, sock);
 

+ 1 - 1
source/putty/windows/winpgntc.c

@@ -109,7 +109,7 @@ agent_pending_query *agent_query(
      */
     id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
     if (id > 0) {
-	retlen = 4 + GET_32BIT(p);
+	retlen = 4 + GET_32BIT_MSB_FIRST(p);
 	ret = snewn(retlen, unsigned char);
 	if (ret) {
 	    memcpy(ret, p, retlen);

+ 7 - 5
source/putty/windows/winstuff.h

@@ -614,13 +614,15 @@ void init_ucs(Conf *, struct unicode_data *);
 #define HANDLE_FLAG_IGNOREEOF 2
 #define HANDLE_FLAG_UNITBUFFER 4
 struct handle;
-typedef int (*handle_inputfn_t)(struct handle *h, void *data, int len);
-typedef void (*handle_outputfn_t)(struct handle *h, int new_backlog);
+typedef size_t (*handle_inputfn_t)(
+    struct handle *h, const void *data, size_t len, int err);
+typedef void (*handle_outputfn_t)(
+    struct handle *h, size_t new_backlog, int err);
 struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata,
 				void *privdata, int flags);
 struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,
 				 void *privdata, int flags);
-int handle_write(struct handle *h, const void *data, int len);
+size_t handle_write(struct handle *h, const void *data, size_t len);
 void handle_write_eof(struct handle *h);
 HANDLE *handle_get_events(int *nevents);
 void handle_free(struct handle *h);
@@ -629,8 +631,8 @@ int handle_got_event(HANDLE event);
 #else
 void handle_got_event(HANDLE event);
 #endif
-void handle_unthrottle(struct handle *h, int backlog);
-int handle_backlog(struct handle *h);
+void handle_unthrottle(struct handle *h, size_t backlog);
+size_t handle_backlog(struct handle *h);
 void *handle_get_privdata(struct handle *h);
 struct handle *handle_add_foreign_event(HANDLE event,
                                         void (*callback)(void *), void *ctx);

+ 28 - 17
source/putty/x11fwd.c

@@ -12,11 +12,18 @@
 #include "sshchan.h"
 #include "tree234.h"
 
-#define GET_16BIT(endian, cp) \
-  (endian=='B' ? GET_16BIT_MSB_FIRST(cp) : GET_16BIT_LSB_FIRST(cp))
+static inline uint16_t GET_16BIT_X11(char endian, const void *p)
+{
+    return endian == 'B' ? GET_16BIT_MSB_FIRST(p) : GET_16BIT_LSB_FIRST(p);
+}
 
-#define PUT_16BIT(endian, cp, val) \
-  (endian=='B' ? PUT_16BIT_MSB_FIRST(cp, val) : PUT_16BIT_LSB_FIRST(cp, val))
+static inline void PUT_16BIT_X11(char endian, void *p, uint16_t value)
+{
+    if (endian == 'B')
+        PUT_16BIT_MSB_FIRST(p, value);
+    else
+        PUT_16BIT_LSB_FIRST(p, value);
+}
 
 const char *const x11_authnames[] = {
     "", "MIT-MAGIC-COOKIE-1", "XDM-AUTHORIZATION-1"
@@ -723,7 +730,7 @@ static void x11_closing(Plug *plug, const char *error_msg, int error_code,
     }
 }
 
-static void x11_receive(Plug *plug, int urgent, char *data, int len)
+static void x11_receive(Plug *plug, int urgent, const char *data, size_t len)
 {
     struct X11Connection *xconn = container_of(
         plug, struct X11Connection, plug);
@@ -732,7 +739,7 @@ static void x11_receive(Plug *plug, int urgent, char *data, int len)
     sshfwd_write(xconn->c, data, len);
 }
 
-static void x11_sent(Plug *plug, int bufsize)
+static void x11_sent(Plug *plug, size_t bufsize)
 {
     struct X11Connection *xconn = container_of(
         plug, struct X11Connection, plug);
@@ -767,7 +774,8 @@ static const PlugVtable X11Connection_plugvt = {
 };
 
 static void x11_chan_free(Channel *chan);
-static int x11_send(Channel *chan, bool is_stderr, const void *vdata, int len);
+static size_t x11_send(
+    Channel *chan, bool is_stderr, const void *vdata, size_t len);
 static void x11_send_eof(Channel *chan);
 static void x11_set_input_wanted(Channel *chan, bool wanted);
 static char *x11_log_close_msg(Channel *chan);
@@ -885,7 +893,7 @@ static void x11_send_init_error(struct X11Connection *xconn,
     reply[0] = 0;	       /* failure */
     reply[1] = msglen;	       /* length of reason string */
     memcpy(reply + 2, xconn->firstpkt + 2, 4);	/* major/minor proto vsn */
-    PUT_16BIT(xconn->firstpkt[0], reply + 6, msgsize >> 2);/* data len */
+    PUT_16BIT_X11(xconn->firstpkt[0], reply + 6, msgsize >> 2);/* data len */
     memset(reply + 8, 0, msgsize);
     memcpy(reply + 8, full_message, msglen);
     sshfwd_write(xconn->c, reply, 8 + msgsize);
@@ -915,7 +923,8 @@ static bool x11_parse_ip(const char *addr_string, unsigned long *ip)
 /*
  * Called to send data down the raw connection.
  */
-static int x11_send(Channel *chan, bool is_stderr, const void *vdata, int len)
+static size_t x11_send(
+    Channel *chan, bool is_stderr, const void *vdata, size_t len)
 {
     pinitassert(chan->vt == &X11Connection_channelvt);
     X11Connection *xconn = container_of(chan, X11Connection, chan);
@@ -934,8 +943,9 @@ static int x11_send(Channel *chan, bool is_stderr, const void *vdata, int len)
      * strings, do so now.
      */
     if (!xconn->auth_protocol) {
-	xconn->auth_plen = GET_16BIT(xconn->firstpkt[0], xconn->firstpkt + 6);
-	xconn->auth_dlen = GET_16BIT(xconn->firstpkt[0], xconn->firstpkt + 8);
+        char endian = xconn->firstpkt[0];
+	xconn->auth_plen = GET_16BIT_X11(endian, xconn->firstpkt + 6);
+	xconn->auth_dlen = GET_16BIT_X11(endian, xconn->firstpkt + 8);
 	xconn->auth_psize = (xconn->auth_plen + 3) & ~3;
 	xconn->auth_dsize = (xconn->auth_dlen + 3) & ~3;
 	/* Leave room for a terminating zero, to make our lives easier. */
@@ -971,9 +981,10 @@ static int x11_send(Channel *chan, bool is_stderr, const void *vdata, int len)
         int socketdatalen;
         char new_peer_addr[32];
         int new_peer_port;
+        char endian = xconn->firstpkt[0];
 
-        protomajor = GET_16BIT(xconn->firstpkt[0], xconn->firstpkt + 2);
-        protominor = GET_16BIT(xconn->firstpkt[0], xconn->firstpkt + 4);
+        protomajor = GET_16BIT_X11(endian, xconn->firstpkt + 2);
+        protominor = GET_16BIT_X11(endian, xconn->firstpkt + 4);
 
         assert(!xconn->s);
 
@@ -1185,10 +1196,10 @@ void *x11_make_greeting(int endian, int protomajor, int protominor,
     greeting = snewn(greeting_len, unsigned char);
     memset(greeting, 0, greeting_len);
     greeting[0] = endian;
-    PUT_16BIT(endian, greeting+2, protomajor);
-    PUT_16BIT(endian, greeting+4, protominor);
-    PUT_16BIT(endian, greeting+6, authnamelen);
-    PUT_16BIT(endian, greeting+8, authdatalen);
+    PUT_16BIT_X11(endian, greeting+2, protomajor);
+    PUT_16BIT_X11(endian, greeting+4, protominor);
+    PUT_16BIT_X11(endian, greeting+6, authnamelen);
+    PUT_16BIT_X11(endian, greeting+8, authdatalen);
     memcpy(greeting+12, authname, authnamelen);
     memcpy(greeting+12+authnamelen_pad, authdata, authdatalen);