Explorar el Código

Merge branch 'thirdparty_dev' into dev

# Conflicts:
#	source/putty/WINDOWS/winmisc.c
#	source/putty/mpint.c
#	source/putty/mpint_i.h
#	source/putty/ssh.h
#	source/putty/ssh2userauth.c
#	source/putty/sshdh.c
#	source/putty/sshecc.c
#	source/putty/sshpubk.c

Source commit: 7eeee2713f7f5e2189aebfa7b530c8d7bb9e3027
Martin Prikryl hace 6 años
padre
commit
2c7aa640d5

+ 51 - 1
source/putty/defs.h

@@ -21,6 +21,8 @@
 /* Work around lack of inttypes.h in older MSVC */
 #define PRIx32 "x"
 #define PRIu64 "I64u"
+#define PRIdMAX "I64d"
+#define PRIXMAX "I64X"
 #define SCNu64 "I64u"
 #else
 #include <inttypes.h>
@@ -37,7 +39,7 @@ typedef struct bufchain_tag bufchain;
 
 typedef struct strbuf strbuf;
 
-struct RSAKey;
+typedef struct RSAKey RSAKey;
 
 typedef struct BinarySink BinarySink;
 typedef struct BinarySource BinarySource;
@@ -91,6 +93,26 @@ typedef struct PortFwdManager PortFwdManager;
 typedef struct PortFwdRecord PortFwdRecord;
 typedef struct ConnectionLayer ConnectionLayer;
 
+typedef struct ssh_hashalg ssh_hashalg;
+typedef struct ssh_hash ssh_hash;
+typedef struct ssh_kex ssh_kex;
+typedef struct ssh_kexes ssh_kexes;
+typedef struct ssh_keyalg ssh_keyalg;
+typedef struct ssh_key ssh_key;
+typedef struct ssh_compressor ssh_compressor;
+typedef struct ssh_decompressor ssh_decompressor;
+typedef struct ssh_compression_alg ssh_compression_alg;
+typedef struct ssh2_userkey ssh2_userkey;
+typedef struct ssh2_macalg ssh2_macalg;
+typedef struct ssh2_mac ssh2_mac;
+typedef struct ssh2_cipheralg ssh2_cipheralg;
+typedef struct ssh2_cipher ssh2_cipher;
+typedef struct ssh2_ciphers ssh2_ciphers;
+typedef struct ssh1_cipheralg ssh1_cipheralg;
+typedef struct ssh1_cipher ssh1_cipher;
+typedef struct dh_ctx dh_ctx;
+typedef struct ecdh_key ecdh_key;
+
 typedef struct dlgparam dlgparam;
 
 typedef struct settings_w settings_w;
@@ -132,4 +154,32 @@ typedef struct PacketProtocolLayer PacketProtocolLayer;
 #define NORETURN
 #endif
 
+/* ----------------------------------------------------------------------
+ * Platform-specific definitions.
+ *
+ * Most of these live in the per-platform header files, of which
+ * puttyps.h selects the appropriate one. But some of the sources
+ * (particularly standalone test applications) would prefer not to
+ * have to include a per-platform header at all, because that makes it
+ * more portable to platforms not supported by the code base as a
+ * whole (for example, compiling purely computational parts of the
+ * code for specialist platforms for test and analysis purposes). So
+ * any definition that has to affect even _those_ modules will have to
+ * go here, with the key constraint being that this code has to come
+ * to _some_ decision even if the compilation platform is not a
+ * recognised one at all.
+ */
+
+/* Purely computational code uses smemclr(), so we have to make the
+ * decision here about whether that's provided by utils.c or by a
+ * platform implementation. We define PLATFORM_HAS_SMEMCLR to suppress
+ * utils.c's definition. */
+#ifdef _WINDOWS
+/* Windows provides the API function 'SecureZeroMemory', which we use
+ * unless the user has told us not to by defining NO_SECUREZEROMEMORY. */
+#ifndef NO_SECUREZEROMEMORY
+#define PLATFORM_HAS_SMEMCLR
+#endif
+#endif
+
 #endif /* PUTTY_DEFS_H */

+ 42 - 15
source/putty/ecc.c

@@ -130,19 +130,6 @@ void ecc_weierstrass_point_free(WeierstrassPoint *wp)
     sfree(wp);
 }
 
-static mp_int *ecc_weierstrass_equation_rhs(
-    WeierstrassCurve *wc, mp_int *monty_x)
-{
-    mp_int *x2 = monty_mul(wc->mc, monty_x, monty_x);
-    mp_int *x2_plus_a = monty_add(wc->mc, x2, wc->a);
-    mp_int *x3_plus_ax = monty_mul(wc->mc, x2_plus_a, monty_x);
-    mp_int *rhs = monty_add(wc->mc, x3_plus_ax, wc->b);
-    mp_free(x2);
-    mp_free(x2_plus_a);
-    mp_free(x3_plus_ax);
-    return rhs;
-}
-
 WeierstrassPoint *ecc_weierstrass_point_new_from_x(
     WeierstrassCurve *wc, mp_int *xorig, unsigned desired_y_parity)
 {
@@ -156,7 +143,20 @@ WeierstrassPoint *ecc_weierstrass_point_new_from_x(
     unsigned success;
 
     mp_int *x = monty_import(wc->mc, xorig);
-    mp_int *rhs = ecc_weierstrass_equation_rhs(wc, x);
+
+    /*
+     * Compute the RHS of the curve equation. We don't need to take
+     * account of z here, because we're constructing the point from
+     * scratch. So it really is just x^3 + ax + b.
+     */
+    mp_int *x2 = monty_mul(wc->mc, x, x);
+    mp_int *x2_plus_a = monty_add(wc->mc, x2, wc->a);
+    mp_int *x3_plus_ax = monty_mul(wc->mc, x2_plus_a, x);
+    mp_int *rhs = monty_add(wc->mc, x3_plus_ax, wc->b);
+    mp_free(x2);
+    mp_free(x2_plus_a);
+    mp_free(x3_plus_ax);
+
     mp_int *y = monty_modsqrt(wc->sc, rhs, &success);
     mp_free(rhs);
 
@@ -518,11 +518,38 @@ void ecc_weierstrass_get_affine(
 
 unsigned ecc_weierstrass_point_valid(WeierstrassPoint *P)
 {
-    mp_int *rhs = ecc_weierstrass_equation_rhs(P->wc, P->X);
+    WeierstrassCurve *wc = P->wc;
+
+    /*
+     * The projective version of the curve equation is
+     * Y^2 = X^3 + a X Z^4 + b Z^6
+     */
     mp_int *lhs = monty_mul(P->wc->mc, P->Y, P->Y);
+    mp_int *x2 = monty_mul(wc->mc, P->X, P->X);
+    mp_int *x3 = monty_mul(wc->mc, x2, P->X);
+    mp_int *z2 = monty_mul(wc->mc, P->Z, P->Z);
+    mp_int *z4 = monty_mul(wc->mc, z2, z2);
+    mp_int *az4 = monty_mul(wc->mc, wc->a, z4);
+    mp_int *axz4 = monty_mul(wc->mc, az4, P->X);
+    mp_int *x3_plus_axz4 = monty_add(wc->mc, x3, axz4);
+    mp_int *z6 = monty_mul(wc->mc, z2, z4);
+    mp_int *bz6 = monty_mul(wc->mc, wc->b, z6);
+    mp_int *rhs = monty_add(wc->mc, x3_plus_axz4, bz6);
+    
     unsigned valid = mp_cmp_eq(lhs, rhs);
+
     mp_free(lhs);
+    mp_free(x2);
+    mp_free(x3);
+    mp_free(z2);
+    mp_free(z4);
+    mp_free(az4);
+    mp_free(axz4);
+    mp_free(x3_plus_axz4);
+    mp_free(z6);
+    mp_free(bz6);
     mp_free(rhs);
+
     return valid;
 }
 

+ 1 - 1
source/putty/ecc.h

@@ -108,7 +108,7 @@ void ecc_weierstrass_get_affine(WeierstrassPoint *wp, mp_int **x, mp_int **y);
  * Montgomery curves.
  *
  * A curve in this form is defined by two parameters a,b, and the
- * curve equation is y^2 = x^3 + ax^2 + bx.
+ * curve equation is by^2 = x^3 + ax^2 + x.
  *
  * As with Weierstrass curves, there's an additional point at infinity
  * that is the identity element, and the inverse of (x,y) is (x,-y).

+ 28 - 28
source/putty/import.c

@@ -15,22 +15,22 @@
 
 static bool openssh_pem_encrypted(const Filename *file);
 static bool openssh_new_encrypted(const Filename *file);
-static struct ssh2_userkey *openssh_pem_read(
+static ssh2_userkey *openssh_pem_read(
     const Filename *file, const char *passphrase, const char **errmsg_p);
-static struct ssh2_userkey *openssh_new_read(
+static ssh2_userkey *openssh_new_read(
     const Filename *file, const char *passphrase, const char **errmsg_p);
 static bool openssh_auto_write(
-    const Filename *file, struct ssh2_userkey *key, const char *passphrase);
+    const Filename *file, ssh2_userkey *key, const char *passphrase);
 static bool openssh_pem_write(
-    const Filename *file, struct ssh2_userkey *key, const char *passphrase);
+    const Filename *file, ssh2_userkey *key, const char *passphrase);
 static bool openssh_new_write(
-    const Filename *file, struct ssh2_userkey *key, const char *passphrase);
+    const Filename *file, ssh2_userkey *key, const char *passphrase);
 
 static bool sshcom_encrypted(const Filename *file, char **comment);
-static struct ssh2_userkey *sshcom_read(
+static ssh2_userkey *sshcom_read(
     const Filename *file, const char *passphrase, const char **errmsg_p);
 static bool sshcom_write(
-    const Filename *file, struct ssh2_userkey *key, const char *passphrase);
+    const Filename *file, ssh2_userkey *key, const char *passphrase);
 
 /*
  * Given a key type, determine whether we know how to import it.
@@ -83,7 +83,7 @@ bool import_encrypted(const Filename *filename, int type, char **comment)
  * Import an SSH-1 key.
  */
 int import_ssh1(const Filename *filename, int type,
-		struct RSAKey *key, char *passphrase, const char **errmsg_p)
+		RSAKey *key, char *passphrase, const char **errmsg_p)
 {
     return 0;
 }
@@ -91,7 +91,7 @@ int import_ssh1(const Filename *filename, int type,
 /*
  * Import an SSH-2 key.
  */
-struct ssh2_userkey *import_ssh2(const Filename *filename, int type,
+ssh2_userkey *import_ssh2(const Filename *filename, int type,
 				 char *passphrase, const char **errmsg_p)
 {
     if (type == SSH_KEYTYPE_OPENSSH_PEM)
@@ -106,7 +106,7 @@ struct ssh2_userkey *import_ssh2(const Filename *filename, int type,
 /*
  * Export an SSH-1 key.
  */
-bool export_ssh1(const Filename *filename, int type, struct RSAKey *key,
+bool export_ssh1(const Filename *filename, int type, RSAKey *key,
                  char *passphrase)
 {
     return false;
@@ -116,7 +116,7 @@ bool export_ssh1(const Filename *filename, int type, struct RSAKey *key,
  * Export an SSH-2 key.
  */
 bool export_ssh2(const Filename *filename, int type,
-                 struct ssh2_userkey *key, char *passphrase)
+                 ssh2_userkey *key, char *passphrase)
 {
     if (type == SSH_KEYTYPE_OPENSSH_AUTO)
 	return openssh_auto_write(filename, key, passphrase);
@@ -495,15 +495,15 @@ static bool openssh_pem_encrypted(const Filename *filename)
     return ret;
 }
 
-static struct ssh2_userkey *openssh_pem_read(
+static ssh2_userkey *openssh_pem_read(
     const Filename *filename, const char *passphrase, const char **errmsg_p)
 {
     struct openssh_pem_key *key = load_openssh_pem_key(filename, errmsg_p);
-    struct ssh2_userkey *retkey;
+    ssh2_userkey *retkey;
     const ssh_keyalg *alg;
     BinarySource src[1];
     int i, num_integers;
-    struct ssh2_userkey *retval = NULL;
+    ssh2_userkey *retval = NULL;
     const char *errmsg;
     strbuf *blob = strbuf_new();
     int privptr = 0, publen;
@@ -659,7 +659,7 @@ static struct ssh2_userkey *openssh_pem_read(
         pubkey.data.len -= 1;
 
         /* Construct the key */
-        retkey = snew(struct ssh2_userkey);
+        retkey = snew(ssh2_userkey);
 
         put_stringz(blob, alg->ssh_id);
         put_stringz(blob, curve->name);
@@ -737,7 +737,7 @@ static struct ssh2_userkey *openssh_pem_read(
          * the sanity checks for free.
          */
         assert(privptr > 0);          /* should have bombed by now if not */
-        retkey = snew(struct ssh2_userkey);
+        retkey = snew(ssh2_userkey);
         alg = (key->keytype == OP_RSA ? &ssh_rsa : &ssh_dss);
         retkey->key = ssh_key_new_priv(
             alg, make_ptrlen(blob->u, privptr),
@@ -774,7 +774,7 @@ static struct ssh2_userkey *openssh_pem_read(
 }
 
 static bool openssh_pem_write(
-    const Filename *filename, struct ssh2_userkey *key, const char *passphrase)
+    const Filename *filename, ssh2_userkey *key, const char *passphrase)
 {
     strbuf *pubblob, *privblob, *outblob;
     unsigned char *spareblob;
@@ -905,7 +905,7 @@ static bool openssh_pem_write(
         seq = strbuf_new();
         for (i = 0; i < nnumbers; i++) {
             put_ber_id_len(seq, 2, numbers[i].len, 0);
-            put_data(seq, numbers[i].ptr, numbers[i].len);
+            put_datapl(seq, numbers[i]);
         }
         put_ber_id_len(outblob, 16, seq->len, ASN1_CONSTRUCTED);
         put_data(outblob, seq->s, seq->len);
@@ -1331,12 +1331,12 @@ static bool openssh_new_encrypted(const Filename *filename)
     return ret;
 }
 
-static struct ssh2_userkey *openssh_new_read(
+static ssh2_userkey *openssh_new_read(
     const Filename *filename, const char *passphrase, const char **errmsg_p)
 {
     struct openssh_new_key *key = load_openssh_new_key(filename, errmsg_p);
-    struct ssh2_userkey *retkey = NULL;
-    struct ssh2_userkey *retval = NULL;
+    ssh2_userkey *retkey = NULL;
+    ssh2_userkey *retval = NULL;
     const char *errmsg;
     unsigned checkint;
     BinarySource src[1];
@@ -1423,7 +1423,7 @@ static struct ssh2_userkey *openssh_new_read(
         goto error;
     }
 
-    retkey = snew(struct ssh2_userkey);
+    retkey = snew(ssh2_userkey);
     retkey->key = NULL;
     retkey->comment = NULL;
 
@@ -1512,7 +1512,7 @@ static struct ssh2_userkey *openssh_new_read(
 }
 
 static bool openssh_new_write(
-    const Filename *filename, struct ssh2_userkey *key, const char *passphrase)
+    const Filename *filename, ssh2_userkey *key, const char *passphrase)
 {
     strbuf *pubblob, *privblob, *cblob;
     int padvalue, i;
@@ -1641,7 +1641,7 @@ static bool openssh_new_write(
  * concrete OpenSSH output formats based on the key type.
  */
 static bool openssh_auto_write(
-    const Filename *filename, struct ssh2_userkey *key, const char *passphrase)
+    const Filename *filename, ssh2_userkey *key, const char *passphrase)
 {
     /*
      * The old OpenSSH format supports a fixed list of key types. We
@@ -1966,7 +1966,7 @@ static ptrlen BinarySource_get_mp_sshcom_as_string(BinarySource *src)
 #define get_mp_sshcom_as_string(bs) \
     BinarySource_get_mp_sshcom_as_string(BinarySource_UPCAST(bs))
 
-static struct ssh2_userkey *sshcom_read(
+static ssh2_userkey *sshcom_read(
     const Filename *filename, const char *passphrase, const char **errmsg_p)
 {
     struct sshcom_key *key = load_sshcom_key(filename, errmsg_p);
@@ -1978,7 +1978,7 @@ static struct ssh2_userkey *sshcom_read(
     const char prefix_dsa[] = "dl-modp{sign{dsa";
     enum { RSA, DSA } type;
     bool encrypted;
-    struct ssh2_userkey *ret = NULL, *retkey;
+    ssh2_userkey *ret = NULL, *retkey;
     const ssh_keyalg *alg;
     strbuf *blob = NULL;
 
@@ -2151,7 +2151,7 @@ static struct ssh2_userkey *sshcom_read(
         put_mp_ssh2_from_string(blob, x.ptr, x.len);
     }
 
-    retkey = snew(struct ssh2_userkey);
+    retkey = snew(ssh2_userkey);
     retkey->key = ssh_key_new_priv(
         alg, make_ptrlen(blob->u, publen),
         make_ptrlen(blob->u + publen, blob->len - publen));
@@ -2178,7 +2178,7 @@ static struct ssh2_userkey *sshcom_read(
 }
 
 static bool sshcom_write(
-    const Filename *filename, struct ssh2_userkey *key, const char *passphrase)
+    const Filename *filename, ssh2_userkey *key, const char *passphrase)
 {
     strbuf *pubblob, *privblob, *outblob;
     ptrlen numbers[6];

+ 5 - 0
source/putty/marshal.c

@@ -10,6 +10,11 @@ void BinarySink_put_data(BinarySink *bs, const void *data, size_t len)
     bs->write(bs, data, len);
 }
 
+void BinarySink_put_datapl(BinarySink *bs, ptrlen pl)
+{
+    BinarySink_put_data(bs, pl.ptr, pl.len);
+}
+
 void BinarySink_put_padding(BinarySink *bs, size_t len, unsigned char padbyte)
 {
     char buf[16];

+ 3 - 0
source/putty/marshal.h

@@ -128,6 +128,8 @@ struct BinarySink {
  * rest of these macros. */
 #define put_data(bs, val, len) \
     BinarySink_put_data(BinarySink_UPCAST(bs), val, len)
+#define put_datapl(bs, pl) \
+    BinarySink_put_datapl(BinarySink_UPCAST(bs), pl)
 
 /*
  * The underlying real C functions that implement most of those
@@ -140,6 +142,7 @@ struct BinarySink {
  * declaration(s) of their other parameter type(s) are in scope.
  */
 void BinarySink_put_data(BinarySink *, const void *data, size_t len);
+void BinarySink_put_datapl(BinarySink *, ptrlen);
 void BinarySink_put_padding(BinarySink *, size_t len, unsigned char padbyte);
 void BinarySink_put_byte(BinarySink *, unsigned char);
 void BinarySink_put_bool(BinarySink *, bool);

+ 1 - 0
source/putty/misc.h

@@ -157,6 +157,7 @@ static inline ptrlen ptrlen_from_strbuf(strbuf *sb)
 
 bool ptrlen_eq_string(ptrlen pl, const char *str);
 bool ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2);
+int ptrlen_strcmp(ptrlen pl1, ptrlen pl2);
 bool ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail);
 char *mkstr(ptrlen pl);
 int string_length_for_printf(size_t);

+ 95 - 91
source/putty/mpint.c

@@ -1,4 +1,5 @@
 #include <assert.h>
+#include <limits.h>
 #include <stdio.h>
 
 #include "defs.h"
@@ -10,6 +11,8 @@
 
 #pragma warn -ngu // WINSCP
 
+#define SIZE_T_BITS (CHAR_BIT * sizeof(size_t))
+
 /*
  * Inline helpers to take min and max of size_t values, used
  * throughout this code.
@@ -222,8 +225,10 @@ mp_int *mp_from_hex_pl(ptrlen hex)
     for (nibble = 0; nibble < hex.len; nibble++) {
         BignumInt digit = ((char *)hex.ptr)[hex.len-1 - nibble];
 
-        BignumInt lmask = ~-(((digit-'a')|('f'-digit)) >> (BIGNUM_INT_BITS-1));
-        BignumInt umask = ~-(((digit-'A')|('F'-digit)) >> (BIGNUM_INT_BITS-1));
+        BignumInt lmask = ~-((BignumInt)((digit-'a')|('f'-digit))
+                             >> (BIGNUM_INT_BITS-1));
+        BignumInt umask = ~-((BignumInt)((digit-'A')|('F'-digit))
+                             >> (BIGNUM_INT_BITS-1));
 
         BignumInt digitval = digit - '0';
         digitval ^= (digitval ^ (digit - 'a' + 10)) & lmask;
@@ -279,7 +284,13 @@ void mp_set_bit(mp_int *x, size_t bit, unsigned val)
 static inline unsigned normalise_to_1(BignumInt n)
 {
     n = (n >> 1) | (n & 1);            /* ensure top bit is clear */
-    n = (-n) >> (BIGNUM_INT_BITS - 1); /* normalise to 0 or 1 */
+    n = (BignumInt)(-n) >> (BIGNUM_INT_BITS - 1); /* normalise to 0 or 1 */
+    return n;
+}
+static inline unsigned normalise_to_1_u64(uint64_t n)
+{
+    n = (n >> 1) | (n & 1);            /* ensure top bit is clear */
+    n = (-n) >> 63;                    /* normalise to 0 or 1 */
     return n;
 }
 
@@ -340,7 +351,8 @@ size_t mp_get_nbits(mp_int *x)
     size_t i; // WINSCP
     for (i = (1 << (BIGNUM_INT_BITS_BITS-1)); i != 0; i >>= 1) {
         BignumInt shifted_word = hiword >> i;
-        BignumInt indicator = (-shifted_word) >> (BIGNUM_INT_BITS-1);
+        BignumInt indicator =
+            (BignumInt)(-shifted_word) >> (BIGNUM_INT_BITS-1);
         hiword ^= (shifted_word ^ hiword ) & -indicator;
         hibit_index += i & -(size_t)indicator;
     }
@@ -372,7 +384,7 @@ static void trim_leading_zeroes(char *buf, size_t bufsize, size_t maxtrim)
         size_t pos; // WINSCP
         for (pos = trim; pos-- > 0 ;) {
             uint8_t diff = buf[pos] ^ '0';
-            size_t mask = -((((size_t)diff) - 1) >> (BIGNUM_INT_BITS - 1));
+            size_t mask = -((((size_t)diff) - 1) >> (SIZE_T_BITS - 1));
             trim ^= (trim ^ pos) & ~mask;
         }
     }
@@ -831,7 +843,7 @@ unsigned mp_hs_integer(mp_int *x, uintmax_t n)
     size_t i; // WINSCP
     for (i = 0; i < x->nw; i++) {
         size_t shift = i * BIGNUM_INT_BITS;
-        BignumInt nword = shift < BIGNUM_INT_BYTES ? n >> shift : 0;
+        BignumInt nword = shift < CHAR_BIT*sizeof(n) ? n >> shift : 0;
         BignumInt dummy_out;
         BignumADC(dummy_out, carry, x->w[i], ~nword, carry);
         (void)dummy_out;
@@ -859,7 +871,7 @@ unsigned mp_eq_integer(mp_int *x, uintmax_t n)
     size_t i; // WINSCP
     for (i = 0; i < x->nw; i++) {
         size_t shift = i * BIGNUM_INT_BITS;
-        BignumInt nword = shift < BIGNUM_INT_BYTES ? n >> shift : 0;
+        BignumInt nword = shift < CHAR_BIT*sizeof(n) ? n >> shift : 0;
         diff |= x->w[i] ^ nword;
     }
     return 1 ^ normalise_to_1(diff);   /* return 1 if diff _is_ zero */
@@ -916,12 +928,12 @@ static void mp_mul_add_simple(mp_int *r, mp_int *a, mp_int *b)
         } // WINSCP
 
         for (; rq < rend; rq++)
-            BignumADC(*rq, carry, 0, *rq, carry);
+            BignumADC(*rq, carry, carry, *rq, 0);
     }
 }
 
 #ifndef KARATSUBA_THRESHOLD      /* allow redefinition via -D for testing */
-#define KARATSUBA_THRESHOLD 50
+#define KARATSUBA_THRESHOLD 24
 #endif
 
 static inline size_t mp_mul_scratchspace_unary(size_t n)
@@ -1090,7 +1102,7 @@ void mp_lshift_fixed_into(mp_int *r, mp_int *a, size_t bits)
     size_t bitoff = bits % BIGNUM_INT_BITS;
 
     size_t i; // WINSCP
-    for (i = 0; i < r->nw; i++) {
+    for (i = r->nw; i-- > 0 ;) {
         if (i < words) {
             r->w[i] = 0;
         } else {
@@ -1189,7 +1201,7 @@ void mp_reduce_mod_2to(mp_int *x, size_t p)
     size_t mask = ((size_t)1 << (p % BIGNUM_INT_BITS)) - 1;
     for (; word < x->nw; word++) {
         x->w[word] &= mask;
-        mask = -(size_t)1;
+        mask = 0;
     }
 }
 
@@ -1340,22 +1352,7 @@ MontyContext *monty_new(mp_int *modulus)
     } // WINSCP
 }
 
-MontyContext *monty_copy(MontyContext *orig)
-{
     size_t j; // WINSCP
-    MontyContext *mc = snew(MontyContext);
-
-    mc->rw = orig->rw;
-    mc->pw = orig->pw;
-    mc->rbits = orig->rbits;
-    mc->m = mp_copy(orig->m);
-    mc->minus_minv_mod_r = mp_copy(orig->minus_minv_mod_r);
-    for (j = 0; j < 3; j++)
-        mc->powers_of_r_mod_m[j] = mp_copy(orig->powers_of_r_mod_m[j]);
-    mc->scratch = mp_make_sized(monty_scratch_size(mc));
-    return mc;
-}
-
 void monty_free(MontyContext *mc)
 {
     size_t j; // WINSCP
@@ -1579,17 +1576,17 @@ mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus)
  *    gcd(b,(a-b)/2).
  *
  * For this application, I always expect the actual gcd to be coprime,
- * so we can rule out the 'both even' initial case. For simplicity
- * I've changed the 'both odd' case to turn (a,b) into (b,a-b) without
- * the division by 2 (the next iteration would divide by 2 anyway).
+ * so we can rule out the 'both even' initial case. So this function
+ * just performs a sequence of reductions in the following form:
  *
- * But the big change is that we need the Bezout coefficients as
- * output, not just the gcd. So we need to know how to generate those
- * in each case, based on the coefficients from the reduced pair of
- * numbers:
+ *  - if a,b are both odd, sort them so that a > b, and replace a with
+ *    b-a; otherwise sort them so that a is the even one
+ *  - either way, now a is even and b is odd, so divide a by 2.
  *
- *  - If a,b are both odd, and u,v are such that u*b + v*(a-b) = 1,
- *    then v*a + (u-v)*b = 1.
+ * The big change to Stein's algorithm is that we need the Bezout
+ * coefficients as output, not just the gcd. So we need to know how to
+ * generate those in each case, based on the coefficients from the
+ * reduced pair of numbers:
  *
  *  - If a is even, and u,v are such that u*(a/2) + v*b = 1:
  *     + if u is also even, then this is just (u/2)*a + v*b = 1
@@ -1597,13 +1594,21 @@ mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus)
  *       since u and b are both odd, (u+b)/2 is an integer, so we have
  *       ((u+b)/2)*a + (v-a/2)*b = 1.
  *
+ *  - If a,b are both odd, and u,v are such that u*b + v*(a-b) = 1,
+ *    then v*a + (u-v)*b = 1.
+ *
+ * In the case where we passed from (a,b) to (b,(a-b)/2), we regard it
+ * as having first subtracted b from a and then halved a, so both of
+ * these transformations must be done in sequence.
+ *
  * The code below transforms this from a recursive to an iterative
  * algorithm. We first reduce a,b to 0,1, recording at each stage
- * whether one of them was even, and whether we had to swap them; then
- * we iterate backwards over that record of what we did, applying the
- * above rules for building up the Bezout coefficients as we go. Of
- * course, all the case analysis is done by the usual bit-twiddling
- * conditionalisation to avoid data-dependent control flow.
+ * whether we did the initial subtraction, and whether we had to swap
+ * the two values; then we iterate backwards over that record of what
+ * we did, applying the above rules for building up the Bezout
+ * coefficients as we go. Of course, all the case analysis is done by
+ * the usual bit-twiddling conditionalisation to avoid data-dependent
+ * control flow.
  *
  * Also, since these mp_ints are generally treated as unsigned, we
  * store the coefficients by absolute value, with the semantics that
@@ -1618,25 +1623,17 @@ mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus)
  * constant time, we just need to find the maximum number we could
  * _possibly_ require, and do that many.
  *
- * If a,b < 2^n, at most 3n iterations are required. Proof: consider
- * the quantity Q = log_2(min(a,b)) + 2 log_2(max(a,b)).
- *  - If the smaller number is even, then the next iteration halves
- *    it, decreasing Q by 1.
- *  - If the larger number is even, then the next iteration halves
- *    it, decreasing Q by 2.
- *  - If the two numbers are both odd, then the combined effect of the
- *    next two steps will be to replace the larger number with
- *    something less than half its original value.
- * In any of these cases, the effect is that in k steps (where k = 1
- * or 2 depending on the case) Q decreases by at least k. So on
- * average it decreases by at least 1 per step, and since it starts
- * off at 3n, that's how many steps it might take.
+ * If a,b < 2^n, at most 2n iterations are required. Proof: consider
+ * the quantity Q = log_2(a) + log_2(b). Every step halves one of the
+ * numbers (and may also reduce one of them further by doing a
+ * subtraction beforehand, but in the worst case, not by much or not
+ * at all). So Q reduces by at least 1 per iteration, and it starts
+ * off with a value at most 2n.
  *
  * The worst case inputs (I think) are where x=2^{n-1} and y=2^n-1
  * (i.e. x is a power of 2 and y is all 1s). In that situation, the
  * first n-1 steps repeatedly halve x until it's 1, and then there are
- * n pairs of steps each of which subtracts 1 from y and then halves
- * it.
+ * n further steps each of which subtracts 1 from y and halves it.
  */
 static void mp_bezout_into(mp_int *a_coeff_out, mp_int *b_coeff_out,
                            mp_int *a_in, mp_int *b_in)
@@ -1662,7 +1659,7 @@ static void mp_bezout_into(mp_int *a_coeff_out, mp_int *b_coeff_out,
      * mp_make_sized conveniently zeroes the allocation and mp_free
      * wipes it, and (b) this way I can use mp_dump() if I have to
      * debug this code. */
-    size_t steps = 3 * nw * BIGNUM_INT_BITS;
+    size_t steps = 2 * nw * BIGNUM_INT_BITS;
     mp_int *record = mp_make_sized(
         (steps*2 + BIGNUM_INT_BITS - 1) / BIGNUM_INT_BITS);
     size_t step; // WINSCP
@@ -1682,13 +1679,15 @@ static void mp_bezout_into(mp_int *a_coeff_out, mp_int *b_coeff_out,
         mp_cond_swap(a, b, swap);
 
         /*
-         * Now, if we've made a the even number, divide it by two; if
-         * we've made it the larger of two odd numbers, subtract the
-         * smaller one from it.
+         * If a,b are both odd, then a is the larger number, so
+         * subtract the smaller one from it.
+         */
+        mp_cond_sub_into(a, a, b, both_odd);
+
+        /*
+         * Now a is even, so divide it by two.
          */
-        mp_rshift_fixed_into(tmp, a, 1);
-        mp_sub_into(a, a, b);
-        mp_select_into(a, tmp, a, both_odd);
+        mp_rshift_fixed_into(a, a, 1);
 
         /*
          * Record the two 1-bit values both_odd and swap.
@@ -1733,37 +1732,35 @@ static void mp_bezout_into(mp_int *a_coeff_out, mp_int *b_coeff_out,
         unsigned swap = mp_get_bit(record, step*2+1);
 
         /*
-         * If this was a division step (!both_odd), and our
-         * coefficient of a is not the even one, we need to adjust the
-         * coefficients by +b and +a respectively.
+         * Unwind the division: if our coefficient of a is odd, we
+         * adjust the coefficients by +b and +a respectively.
          */
-        unsigned adjust = (ac->w[0] & 1) & ~both_odd;
+        unsigned adjust = ac->w[0] & 1;
         mp_cond_add_into(ac, ac, b, adjust);
         mp_cond_add_into(bc, bc, a, adjust);
 
         /*
-         * Now, if it was a division step, then ac is even, and we
-         * divide it by two.
+         * Now ac is definitely even, so we divide it by two.
          */
-        mp_rshift_fixed_into(tmp, ac, 1);
-        mp_select_into(ac, tmp, ac, both_odd);
+        mp_rshift_fixed_into(ac, ac, 1);
 
         /*
-         * But if it was a subtraction step, we add ac to bc instead.
+         * Now unwind the subtraction, if there was one, by adding
+         * ac to bc.
          */
         mp_cond_add_into(bc, bc, ac, both_odd);
 
         /*
-         * Undo the transformation of the input numbers, by adding b
-         * to a (if both_odd) or multiplying a by 2 (otherwise).
+         * Undo the transformation of the input numbers, by
+         * multiplying a by 2 and then adding b to a (the latter
+         * only if both_odd).
          */
-        mp_lshift_fixed_into(tmp, a, 1);
-        mp_add_into(a, a, b);
-        mp_select_into(a, tmp, a, both_odd);
+        mp_lshift_fixed_into(a, a, 1);
+        mp_cond_add_into(a, a, b, both_odd);
 
         /*
-         * Finally, undo the swap. If we do swap, this also reverses
-         * the sign of the current result ac*a+bc*b.
+         * Finally, undo the swap. If we do swap, this also
+         * reverses the sign of the current result ac*a+bc*b.
          */
         mp_cond_swap(a, b, swap);
         mp_cond_swap(ac, bc, swap);
@@ -1939,10 +1936,10 @@ void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q_out, mp_int *r_out)
     size_t i; // WINSCP
     for (i = BIGNUM_INT_BITS_BITS; i-- > 0;) {
         size_t sl = 1 << i;               /* left shift count */
-        size_t sr = BIGNUM_INT_BITS - sl; /* complementary right-shift count */
+        size_t sr = 64 - sl;     /* complementary right-shift count */
 
         /* Should we shift up? */
-        unsigned indicator = 1 ^ normalise_to_1(hibits >> sr);
+        unsigned indicator = 1 ^ normalise_to_1_u64(hibits >> sr);
 
         /* If we do, what will we get? */
         uint64_t new_hibits = (hibits << sl) | (lobits >> sr);
@@ -1950,9 +1947,9 @@ void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q_out, mp_int *r_out)
         size_t new_shift_up = shift_up + sl;
 
         /* Conditionally swap those values in. */
-        hibits    ^= (hibits    ^ new_hibits   ) & -(BignumInt)indicator;
-        lobits    ^= (lobits    ^ new_lobits   ) & -(BignumInt)indicator;
-        shift_up  ^= (shift_up  ^ new_shift_up ) & -(size_t)   indicator;
+        hibits    ^= (hibits    ^ new_hibits   ) & -(uint64_t)indicator;
+        lobits    ^= (lobits    ^ new_lobits   ) & -(uint64_t)indicator;
+        shift_up  ^= (shift_up  ^ new_shift_up ) & -(size_t)  indicator;
     }
 
     /*
@@ -1977,7 +1974,7 @@ void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q_out, mp_int *r_out)
      */
     for (i = BIGNUM_INT_BITS_BITS; i-- > 0;) {
         size_t sl = 1 << i;               /* left shift count */
-        size_t sr = BIGNUM_INT_BITS - sl; /* complementary right-shift count */
+        size_t sr = 64 - sl;     /* complementary right-shift count */
 
         /* Should we shift up? */
         unsigned indicator = 1 & (shift_up >> i);
@@ -1987,8 +1984,8 @@ void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q_out, mp_int *r_out)
         uint64_t new_lobits = lobits << sl;
 
         /* Conditionally swap those values in. */
-        hibits    ^= (hibits    ^ new_hibits   ) & -(BignumInt)indicator;
-        lobits    ^= (lobits    ^ new_lobits   ) & -(BignumInt)indicator;
+        hibits    ^= (hibits    ^ new_hibits   ) & -(uint64_t)indicator;
+        lobits    ^= (lobits    ^ new_lobits   ) & -(uint64_t)indicator;
     }
 
     /*
@@ -2198,11 +2195,15 @@ mp_int *mp_modsub(mp_int *x, mp_int *y, mp_int *modulus)
     unsigned negate = mp_cmp_hs(y, x);
     mp_cond_negate(diff, diff, negate);
     { // WINSCP
-    mp_int *reduced = mp_mod(diff, modulus);
-    mp_cond_negate(reduced, reduced, negate);
-    mp_cond_add_into(reduced, reduced, modulus, negate);
+    mp_int *residue = mp_mod(diff, modulus);
+    mp_cond_negate(residue, residue, negate);
+    /* If we've just negated the residue, then it will be < 0 and need
+     * the modulus adding to it to make it positive - *except* if the
+     * residue was zero when we negated it. */
+    unsigned make_positive = negate & ~mp_eq_integer(residue, 0);
+    mp_cond_add_into(residue, residue, modulus, make_positive);
     mp_free(diff);
-    return reduced;
+    return residue;
     } // WINSCP
     } // WINSCP
 }
@@ -2417,7 +2418,10 @@ mp_int *monty_modsqrt(ModsqrtContext *sc, mp_int *x, unsigned *success)
         unsigned eq1 = mp_cmp_eq(&tmp, monty_identity(sc->mc));
 
         if (i == 0) {
-            *success = eq1;
+            /* One special case: if x=0, then no power of x will ever
+             * equal 1, but we should still report success on the
+             * grounds that 0 does have a square root mod p. */
+            *success = eq1 | mp_eq_integer(x, 0);
         } else {
             monty_mul_into(sc->mc, &tmp, toret, &power_of_zk);
             mp_select_into(toret, &tmp, toret, eq1);

+ 0 - 1
source/putty/mpint.h

@@ -313,7 +313,6 @@ mp_int *mp_modsqrt(ModsqrtContext *sc, mp_int *x, unsigned *success);
  * pointers are still owned by the MontyContext, so don't free them!
  */
 MontyContext *monty_new(mp_int *modulus);
-MontyContext *monty_copy(MontyContext *mc);
 void monty_free(MontyContext *mc);
 mp_int *monty_modulus(MontyContext *mc); /* doesn't transfer ownership */
 mp_int *monty_identity(MontyContext *mc); /* doesn't transfer ownership */

+ 26 - 13
source/putty/mpint_i.h

@@ -17,12 +17,12 @@
  *    type used to hold the carry flag taken as input and output by
  *    the BignumADC macro (see below).
  *
- *  - four constant macros: BIGNUM_INT_BITS, BIGNUM_INT_BYTES,
- *    BIGNUM_TOP_BIT, BIGNUM_INT_MASK. These should be more or less
- *    self-explanatory, but just in case, they give the number of bits
- *    in BignumInt, the number of bytes that works out to, the
- *    BignumInt value consisting of only the top bit, and the
- *    BignumInt value with all bits set.
+ *  - five constant macros:
+ *     + BIGNUM_INT_BITS, the number of bits in BignumInt,
+ *     + BIGNUM_INT_BYTES, the number of bytes that works out to
+ *     + BIGNUM_TOP_BIT, the BignumInt value consisting of only the top bit
+ *     + BIGNUM_INT_MASK, the BignumInt value with all bits set
+ *     + BIGNUM_INT_BITS_BITS, log to the base 2 of BIGNUM_INT_BITS.
  *
  *  - four statement macros: BignumADC, BignumMUL, BignumMULADD,
  *    BignumMULADD2. These do various kinds of multi-word arithmetic,
@@ -39,7 +39,7 @@
  *       halves of the double-width value a*b + addend1 + addend2.
  *
  * Every branch of the main ifdef below defines the type BignumInt and
- * the value BIGNUM_INT_BITS. The other three constant macros are
+ * the value BIGNUM_INT_BITS_BITS. The other constant macros are
  * filled in by common code further down.
  *
  * Most branches also define a macro DEFINE_BIGNUMDBLINT containing a
@@ -57,7 +57,11 @@
  * too.
  */
 
-#if defined __SIZEOF_INT128__
+/* You can lower the BignumInt size by defining BIGNUM_OVERRIDE on the
+ * command line to be your chosen max value of BIGNUM_INT_BITS_BITS */
+#define BB_OK(b) (!defined BIGNUM_OVERRIDE || BIGNUM_OVERRIDE >= b)
+
+#if defined __SIZEOF_INT128__ && BB_OK(6)
 
   /*
    * 64-bit BignumInt using gcc/clang style 128-bit BignumDblInt.
@@ -72,7 +76,7 @@
   #define BIGNUM_INT_BITS_BITS 6
   #define DEFINE_BIGNUMDBLINT typedef __uint128_t BignumDblInt
 
-#elif defined _MSC_VER && defined _M_AMD64
+#elif defined _MSC_VER && defined _M_AMD64 && BB_OK(6)
 
   /*
    * 64-bit BignumInt, using Visual Studio x86-64 compiler intrinsics.
@@ -119,7 +123,7 @@
           (rh) = MULADD_hi;                                               \
       } while (0)
 
-#elif defined __GNUC__ || defined _LLP64 || __STDC__ >= 199901L
+#elif (defined __GNUC__ || defined _LLP64 || __STDC__ >= 199901L) && BB_OK(5)
 
   /* 32-bit BignumInt, using C99 unsigned long long as BignumDblInt */
 
@@ -127,7 +131,7 @@
   #define BIGNUM_INT_BITS_BITS 5
   #define DEFINE_BIGNUMDBLINT typedef unsigned long long BignumDblInt
 
-#elif (defined _MSC_VER && defined _M_IX86) || defined(MPEXT)
+#elif (defined _MSC_VER && defined _M_IX86 && BB_OK(5)) || defined(MPEXT)
 
   /* 32-bit BignumInt, using Visual Studio __int64 as BignumDblInt */
 
@@ -135,7 +139,7 @@
   #define BIGNUM_INT_BITS_BITS 5
   #define DEFINE_BIGNUMDBLINT typedef unsigned __int64 BignumDblInt
 
-#elif defined _LP64
+#elif defined _LP64 && BB_OK(5)
 
   /*
    * 32-bit BignumInt, using unsigned long itself as BignumDblInt.
@@ -147,7 +151,7 @@
   #define BIGNUM_INT_BITS_BITS 5
   #define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
 
-#else
+#elif BB_OK(4)
 
   /*
    * 16-bit BignumInt, using unsigned long as BignumDblInt.
@@ -163,8 +167,17 @@
   #define BIGNUM_INT_BITS_BITS 4
   #define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
 
+#else
+
+  /* Should only get here if BB_OK(4) evaluated false, i.e. the
+   * command line defined BIGNUM_OVERRIDE to an absurdly small
+   * value. */
+  #error Must define BIGNUM_OVERRIDE to at least 4
+
 #endif
 
+#undef BB_OK
+
 /*
  * Common code across all branches of that ifdef: define all the
  * easy constant macros in terms of BIGNUM_INT_BITS_BITS.

+ 6 - 6
source/putty/pageant.h

@@ -56,14 +56,14 @@ void pageant_make_keylist2(BinarySink *);
  * on success, in which case the ownership of the key structure is
  * passed back to the client).
  */
-struct RSAKey *pageant_nth_ssh1_key(int i);
-struct ssh2_userkey *pageant_nth_ssh2_key(int i);
+RSAKey *pageant_nth_ssh1_key(int i);
+ssh2_userkey *pageant_nth_ssh2_key(int i);
 int pageant_count_ssh1_keys(void);
 int pageant_count_ssh2_keys(void);
-bool pageant_add_ssh1_key(struct RSAKey *rkey);
-bool pageant_add_ssh2_key(struct ssh2_userkey *skey);
-bool pageant_delete_ssh1_key(struct RSAKey *rkey);
-bool pageant_delete_ssh2_key(struct ssh2_userkey *skey);
+bool pageant_add_ssh1_key(RSAKey *rkey);
+bool pageant_add_ssh2_key(ssh2_userkey *skey);
+bool pageant_delete_ssh1_key(RSAKey *rkey);
+bool pageant_delete_ssh2_key(ssh2_userkey *skey);
 
 /*
  * This callback must be provided by the Pageant front end code.

+ 7 - 14
source/putty/puttymem.h

@@ -22,23 +22,16 @@ void safefree(void *);
 
 /*
  * Direct use of smalloc within the code should be avoided where
- * possible, in favour of these type-casting macros which ensure
- * you don't mistakenly allocate enough space for one sort of
- * structure and assign it to a different sort of pointer.
- *
- * The nasty trick in sresize with sizeof arranges for the compiler,
- * in passing, to type-check the expression ((type *)0 == (ptr)), i.e.
- * to type-check that the input pointer is a pointer to the correct
- * type. The construction sizeof(stuff) ? (b) : (b) looks like a
- * violation of the first principle of safe macros, but in fact it's
- * OK - although it _expands_ the macro parameter more than once, it
- * only _evaluates_ it once, so it's still side-effect safe.
+ * possible, in favour of these type-casting macros which ensure you
+ * don't mistakenly allocate enough space for one sort of structure
+ * and assign it to a different sort of pointer. sresize also uses
+ * TYPECHECK to verify that the _input_ pointer is a pointer to the
+ * correct type.
  */
 #define snew(type) ((type *)snmalloc(1, sizeof(type)))
 #define snewn(n, type) ((type *)snmalloc((n), sizeof(type)))
-#define sresize(ptr, n, type)                                           \
-    ((type *)snrealloc(sizeof((type *)0 == (ptr)) ? (ptr) : (ptr),      \
-                       (n), sizeof(type)))
+#define sresize(ptr, n, type) TYPECHECK((type *)0 == (ptr), \
+    ((type *)snrealloc((ptr), (n), sizeof(type))))
 
 /*
  * For cases where you want to allocate a struct plus a subsidiary

+ 129 - 124
source/putty/ssh.h

@@ -396,10 +396,9 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...);
 #define SSH_CIPHER_3DES		3
 #define SSH_CIPHER_BLOWFISH	6
 
-typedef struct ssh_keyalg ssh_keyalg;
-typedef struct ssh_key {
-    const struct ssh_keyalg *vt;
-} ssh_key;
+struct ssh_key {
+    const ssh_keyalg *vt;
+};
 
 struct RSAKey {
     int bits;
@@ -505,21 +504,19 @@ EdwardsPoint *eddsa_public(mp_int *private_key, const ssh_keyalg *alg);
 typedef enum { RSA_SSH1_EXPONENT_FIRST, RSA_SSH1_MODULUS_FIRST } RsaSsh1Order;
 
 void BinarySource_get_rsa_ssh1_pub(
-    BinarySource *src, struct RSAKey *result, RsaSsh1Order order);
+    BinarySource *src, RSAKey *result, RsaSsh1Order order);
 void BinarySource_get_rsa_ssh1_priv(
-    BinarySource *src, struct RSAKey *rsa);
-bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key);
-mp_int *rsa_ssh1_decrypt(mp_int *input, struct RSAKey *key);
-bool rsa_ssh1_decrypt_pkcs1(mp_int *input, struct RSAKey *key,
-                            strbuf *outbuf);
-char *rsastr_fmt(struct RSAKey *key);
-char *rsa_ssh1_fingerprint(struct RSAKey *key);
-bool rsa_verify(struct RSAKey *key);
-void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
-                          RsaSsh1Order order);
-int rsa_ssh1_public_blob_len(void *data, int maxlen);
-void freersapriv(struct RSAKey *key);
-void freersakey(struct RSAKey *key);
+    BinarySource *src, RSAKey *rsa);
+bool rsa_ssh1_encrypt(unsigned char *data, int length, RSAKey *key);
+mp_int *rsa_ssh1_decrypt(mp_int *input, RSAKey *key);
+bool rsa_ssh1_decrypt_pkcs1(mp_int *input, RSAKey *key, strbuf *outbuf);
+char *rsastr_fmt(RSAKey *key);
+char *rsa_ssh1_fingerprint(RSAKey *key);
+bool rsa_verify(RSAKey *key);
+void rsa_ssh1_public_blob(BinarySink *bs, RSAKey *key, RsaSsh1Order order);
+int rsa_ssh1_public_blob_len(ptrlen data);
+void freersapriv(RSAKey *key);
+void freersakey(RSAKey *key);
 #endif // WINSCP_VS
 
 #ifndef WINSCP_VS
@@ -536,26 +533,22 @@ bool detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32_t len,
 /*
  * SSH2 RSA key exchange functions
  */
-struct ssh_hashalg;
 struct ssh_rsa_kex_extra {
     int minklen;
 };
-struct RSAKey *ssh_rsakex_newkey(const void *data, int len);
-void ssh_rsakex_freekey(struct RSAKey *key);
-int ssh_rsakex_klen(struct RSAKey *key);
-void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
-                        unsigned char *in, int inlen,
-                        unsigned char *out, int outlen, struct RSAKey *key);
-mp_int *ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext,
-                              struct RSAKey *rsa);
+RSAKey *ssh_rsakex_newkey(ptrlen data);
+void ssh_rsakex_freekey(RSAKey *key);
+int ssh_rsakex_klen(RSAKey *key);
+strbuf *ssh_rsakex_encrypt(
+    RSAKey *key, const ssh_hashalg *h, ptrlen plaintext);
+mp_int *ssh_rsakex_decrypt(
+    RSAKey *key, const ssh_hashalg *h, ptrlen ciphertext);
 
 /*
  * SSH2 ECDH key exchange functions
  */
-struct ssh_kex;
-typedef struct ecdh_key ecdh_key;
-const char *ssh_ecdhkex_curve_textname(const struct ssh_kex *kex);
-ecdh_key *ssh_ecdhkex_newkey(const struct ssh_kex *kex);
+const char *ssh_ecdhkex_curve_textname(const ssh_kex *kex);
+ecdh_key *ssh_ecdhkex_newkey(const ssh_kex *kex);
 void ssh_ecdhkex_freekey(ecdh_key *key);
 void ssh_ecdhkex_getpublic(ecdh_key *key, BinarySink *bs);
 mp_int *ssh_ecdhkex_getkey(ecdh_key *key, ptrlen remoteKey);
@@ -567,10 +560,9 @@ mp_int *dss_gen_k(const char *id_string,
                      mp_int *modulus, mp_int *private_key,
                      unsigned char *digest, int digest_len);
 
-struct ssh2_cipheralg;
-typedef struct ssh2_cipher {
-    const struct ssh2_cipheralg *vt;
-} ssh2_cipher;
+struct ssh2_cipher {
+    const ssh2_cipheralg *vt;
+};
 
 typedef struct {
     uint32_t h[4];
@@ -651,12 +643,9 @@ void SHA384_Init(SHA384_State * s);
 void SHA384_Final(SHA384_State * s, unsigned char *output);
 void SHA384_Simple(const void *p, int len, unsigned char *output);
 
-struct ssh2_macalg;
-
-struct ssh1_cipheralg;
-typedef struct ssh1_cipher {
-    const struct ssh1_cipheralg *vt;
-} ssh1_cipher;
+struct ssh1_cipher {
+    const ssh1_cipheralg *vt;
+};
 
 struct ssh1_cipheralg {
     ssh1_cipher *(*new)(void);
@@ -675,7 +664,7 @@ struct ssh1_cipheralg {
 #define ssh1_cipher_decrypt(ctx, blk, len) ((ctx)->vt->decrypt(ctx, blk, len))
 
 struct ssh2_cipheralg {
-    ssh2_cipher *(*new)(const struct ssh2_cipheralg *alg);
+    ssh2_cipher *(*new)(const ssh2_cipheralg *alg);
     void (*free)(ssh2_cipher *);
     void (*setiv)(ssh2_cipher *, const void *iv);
     void (*setkey)(ssh2_cipher *, const void *key);
@@ -706,7 +695,7 @@ struct ssh2_cipheralg {
 #define SSH_CIPHER_SEPARATE_LENGTH      2
     const char *text_name;
     /* If set, this takes priority over other MAC. */
-    const struct ssh2_macalg *required_mac;
+    const ssh2_macalg *required_mac;
 };
 
 #define ssh2_cipher_new(alg) ((alg)->new(alg))
@@ -723,20 +712,19 @@ struct ssh2_cipheralg {
 
 struct ssh2_ciphers {
     int nciphers;
-    const struct ssh2_cipheralg *const *list;
+    const ssh2_cipheralg *const *list;
 };
 
-struct ssh2_macalg;
-typedef struct ssh2_mac {
-    const struct ssh2_macalg *vt;
+struct ssh2_mac {
+    const ssh2_macalg *vt;
     BinarySink_DELEGATE_IMPLEMENTATION;
-} ssh2_mac;
+};
 
 struct ssh2_macalg {
     /* Passes in the cipher context */
-    ssh2_mac *(*new)(const struct ssh2_macalg *alg, ssh2_cipher *cipher);
+    ssh2_mac *(*new)(const ssh2_macalg *alg, ssh2_cipher *cipher);
     void (*free)(ssh2_mac *);
-    void (*setkey)(ssh2_mac *, const void *key);
+    void (*setkey)(ssh2_mac *, ptrlen key);
     void (*start)(ssh2_mac *);
     void (*genresult)(ssh2_mac *, unsigned char *);
     const char *name, *etm_name;
@@ -756,19 +744,19 @@ bool ssh2_mac_verresult(ssh2_mac *, const void *);
 void ssh2_mac_generate(ssh2_mac *, void *, int, unsigned long seq);
 bool ssh2_mac_verify(ssh2_mac *, const void *, int, unsigned long seq);
 
-typedef struct ssh_hash {
-    const struct ssh_hashalg *vt;
+struct ssh_hash {
+    const ssh_hashalg *vt;
     BinarySink_DELEGATE_IMPLEMENTATION;
-} ssh_hash;
+};
 
-typedef struct ssh_hashalg {
-    ssh_hash *(*new)(const struct ssh_hashalg *alg);
+struct ssh_hashalg {
+    ssh_hash *(*new)(const ssh_hashalg *alg);
     ssh_hash *(*copy)(ssh_hash *);
     void (*final)(ssh_hash *, unsigned char *); /* ALSO FREES THE ssh_hash! */
     void (*free)(ssh_hash *);
     int hlen; /* output length in bytes */
     const char *text_name;
-} ssh_hashalg;
+};
 
 #define ssh_hash_new(alg) ((alg)->new(alg))
 #define ssh_hash_copy(ctx) ((ctx)->vt->copy(ctx))
@@ -779,13 +767,13 @@ typedef struct ssh_hashalg {
 struct ssh_kex {
     const char *name, *groupname;
     enum { KEXTYPE_DH, KEXTYPE_RSA, KEXTYPE_ECDH, KEXTYPE_GSS } main_type;
-    const struct ssh_hashalg *hash;
+    const ssh_hashalg *hash;
     const void *extra;                 /* private to the kex methods */
 };
 
 struct ssh_kexes {
     int nkexes;
-    const struct ssh_kex *const *list;
+    const ssh_kex *const *list;
 };
 
 struct ssh_keyalg {
@@ -796,8 +784,7 @@ struct ssh_keyalg {
 
     /* Methods that operate on an existing ssh_key */
     void (*freekey) (ssh_key *key);
-    void (*sign) (ssh_key *key, const void *data, int datalen,
-                  unsigned flags, BinarySink *);
+    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 *);
     void (*private_blob)(ssh_key *key, BinarySink *);
@@ -819,8 +806,8 @@ 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_sign(key, data, len, flags, bs) \
-    ((key)->vt->sign(key, data, len, flags, bs))
+#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))
 #define ssh_key_public_blob(key, bs) ((key)->vt->public_blob(key, bs))
 #define ssh_key_private_blob(key, bs) ((key)->vt->private_blob(key, bs))
@@ -839,12 +826,12 @@ struct ssh_keyalg {
 #define SSH_AGENT_RSA_SHA2_256 2
 #define SSH_AGENT_RSA_SHA2_512 4
 
-typedef struct ssh_compressor {
-    const struct ssh_compression_alg *vt;
-} ssh_compressor;
-typedef struct ssh_decompressor {
-    const struct ssh_compression_alg *vt;
-} ssh_decompressor;
+struct ssh_compressor {
+    const ssh_compression_alg *vt;
+};
+struct ssh_decompressor {
+    const ssh_compression_alg *vt;
+};
 
 struct ssh_compression_alg {
     const char *name;
@@ -882,38 +869,59 @@ struct ssh2_userkey {
 /* The maximum length of any hash algorithm. (bytes) */
 #define MAX_HASH_LEN (64)              /* longest is SHA-512 */
 
-extern const struct ssh1_cipheralg ssh1_3des;
-extern const struct ssh1_cipheralg ssh1_des;
-extern const struct ssh1_cipheralg ssh1_blowfish;
-extern const struct ssh2_ciphers ssh2_3des;
-extern const struct ssh2_ciphers ssh2_des;
-extern const struct ssh2_ciphers ssh2_aes;
-extern const struct ssh2_ciphers ssh2_blowfish;
-extern const struct ssh2_ciphers ssh2_arcfour;
-extern const struct ssh2_ciphers ssh2_ccp;
-extern const struct ssh_hashalg ssh_sha1;
-extern const struct ssh_hashalg ssh_sha256;
-extern const struct ssh_hashalg ssh_sha384;
-extern const struct ssh_hashalg ssh_sha512;
-extern const struct ssh_kexes ssh_diffiehellman_group1;
-extern const struct ssh_kexes ssh_diffiehellman_group14;
-extern const struct ssh_kexes ssh_diffiehellman_gex;
-extern const struct ssh_kexes ssh_gssk5_sha1_kex;
-extern const struct ssh_kexes ssh_rsa_kex;
-extern const struct ssh_kexes ssh_ecdh_kex;
+extern const ssh1_cipheralg ssh1_3des;
+extern const ssh1_cipheralg ssh1_des;
+extern const ssh1_cipheralg ssh1_blowfish;
+extern const ssh2_cipheralg ssh_3des_ssh2_ctr;
+extern const ssh2_cipheralg ssh_3des_ssh2;
+extern const ssh2_cipheralg ssh_des_ssh2;
+extern const ssh2_cipheralg ssh_des_sshcom_ssh2;
+extern const ssh2_cipheralg ssh_aes256_ctr;
+extern const ssh2_cipheralg ssh_aes256;
+extern const ssh2_cipheralg ssh_aes192_ctr;
+extern const ssh2_cipheralg ssh_aes192;
+extern const ssh2_cipheralg ssh_aes128_ctr;
+extern const ssh2_cipheralg ssh_aes128;
+extern const ssh2_cipheralg ssh_blowfish_ssh2_ctr;
+extern const ssh2_cipheralg ssh_blowfish_ssh2;
+extern const ssh2_cipheralg ssh_arcfour256_ssh2;
+extern const ssh2_cipheralg ssh_arcfour128_ssh2;
+extern const ssh2_cipheralg ssh2_chacha20_poly1305;
+extern const ssh2_ciphers ssh2_3des;
+extern const ssh2_ciphers ssh2_des;
+extern const ssh2_ciphers ssh2_aes;
+extern const ssh2_ciphers ssh2_blowfish;
+extern const ssh2_ciphers ssh2_arcfour;
+extern const ssh2_ciphers ssh2_ccp;
+extern const ssh_hashalg ssh_md5;
+extern const ssh_hashalg ssh_sha1;
+extern const ssh_hashalg ssh_sha256;
+extern const ssh_hashalg ssh_sha384;
+extern const ssh_hashalg ssh_sha512;
+extern const ssh_kexes ssh_diffiehellman_group1;
+extern const ssh_kexes ssh_diffiehellman_group14;
+extern const ssh_kexes ssh_diffiehellman_gex;
+extern const ssh_kexes ssh_gssk5_sha1_kex;
+extern const ssh_kexes ssh_rsa_kex;
+extern const ssh_kex ssh_ec_kex_curve25519;
+extern const ssh_kex ssh_ec_kex_nistp256;
+extern const ssh_kex ssh_ec_kex_nistp384;
+extern const ssh_kex ssh_ec_kex_nistp521;
+extern const ssh_kexes ssh_ecdh_kex;
 extern const ssh_keyalg ssh_dss;
 extern const ssh_keyalg ssh_rsa;
 extern const ssh_keyalg ssh_ecdsa_ed25519;
 extern const ssh_keyalg ssh_ecdsa_nistp256;
 extern const ssh_keyalg ssh_ecdsa_nistp384;
 extern const ssh_keyalg ssh_ecdsa_nistp521;
-extern const struct ssh2_macalg ssh_hmac_md5;
-extern const struct ssh2_macalg ssh_hmac_sha1;
-extern const struct ssh2_macalg ssh_hmac_sha1_buggy;
-extern const struct ssh2_macalg ssh_hmac_sha1_96;
-extern const struct ssh2_macalg ssh_hmac_sha1_96_buggy;
-extern const struct ssh2_macalg ssh_hmac_sha256;
-extern const struct ssh_compression_alg ssh_zlib;
+extern const ssh2_macalg ssh_hmac_md5;
+extern const ssh2_macalg ssh_hmac_sha1;
+extern const ssh2_macalg ssh_hmac_sha1_buggy;
+extern const ssh2_macalg ssh_hmac_sha1_96;
+extern const ssh2_macalg ssh_hmac_sha1_96_buggy;
+extern const ssh2_macalg ssh_hmac_sha256;
+extern const ssh2_macalg ssh2_poly1305;
+extern const ssh_compression_alg ssh_zlib;
 
 typedef struct AESContext AESContext;
 AESContext *aes_make_context(void);
@@ -1078,23 +1086,21 @@ void *x11_dehexify(ptrlen hex, int *outlen);
 
 Channel *agentf_new(SshChannel *c);
 
-bool dh_is_gex(const struct ssh_kex *kex);
-struct dh_ctx;
-struct dh_ctx *dh_setup_group(const struct ssh_kex *kex);
-struct dh_ctx *dh_setup_gex(mp_int *pval, mp_int *gval);
-int dh_modulus_bit_size(const struct dh_ctx *ctx);
-void dh_cleanup(struct dh_ctx *);
-mp_int *dh_create_e(struct dh_ctx *, int nbits);
-const char *dh_validate_f(struct dh_ctx *, mp_int *f);
-mp_int *dh_find_K(struct dh_ctx *, mp_int *f);
+bool dh_is_gex(const ssh_kex *kex);
+dh_ctx *dh_setup_group(const ssh_kex *kex);
+dh_ctx *dh_setup_gex(mp_int *pval, mp_int *gval);
+int dh_modulus_bit_size(const dh_ctx *ctx);
+void dh_cleanup(dh_ctx *);
+mp_int *dh_create_e(dh_ctx *, int nbits);
+const char *dh_validate_f(dh_ctx *, mp_int *f);
+mp_int *dh_find_K(dh_ctx *, mp_int *f);
 
 bool rsa_ssh1_encrypted(const Filename *filename, char **comment);
 int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs,
                      char **commentptr, const char **errorstr);
-int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key,
+int rsa_ssh1_loadkey(const Filename *filename, RSAKey *key,
                      const char *passphrase, const char **errorstr);
-bool rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key,
-                      char *passphrase);
+bool rsa_ssh1_savekey(const Filename *filename, RSAKey *key, char *passphrase);
 
 static inline bool is_base64_char(char c)
 {
@@ -1111,18 +1117,17 @@ extern void base64_encode(FILE *fp, const unsigned char *data, int datalen,
                           int cpl);
 
 /* ssh2_load_userkey can return this as an error */
-extern struct ssh2_userkey ssh2_wrong_passphrase;
+extern ssh2_userkey ssh2_wrong_passphrase;
 #define SSH2_WRONG_PASSPHRASE (&ssh2_wrong_passphrase)
 
 bool ssh2_userkey_encrypted(const Filename *filename, char **comment);
-struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
-				       const char *passphrase,
-                                       const char **errorstr);
-bool ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
-                          BinarySink *bs,
-                          char **commentptr, const char **errorstr);
-bool ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
-                       char *passphrase);
+ssh2_userkey *ssh2_load_userkey(
+    const Filename *filename, const char *passphrase, const char **errorstr);
+bool ssh2_userkey_loadpub(
+    const Filename *filename, char **algorithm, BinarySink *bs,
+    char **commentptr, const char **errorstr);
+bool ssh2_save_userkey(
+    const Filename *filename, ssh2_userkey *key, char *passphrase);
 const ssh_keyalg *find_pubkey_alg(const char *name);
 const ssh_keyalg *find_pubkey_alg_len(ptrlen name);
 
@@ -1169,9 +1174,9 @@ enum {
     SSH_KEYTYPE_SSH2_PUBLIC_RFC4716,
     SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH
 };
-char *ssh1_pubkey_str(struct RSAKey *ssh1key);
-void ssh1_write_pubkey(FILE *fp, struct RSAKey *ssh1key);
-char *ssh2_pubkey_openssh_str(struct ssh2_userkey *key);
+char *ssh1_pubkey_str(RSAKey *ssh1key);
+void ssh1_write_pubkey(FILE *fp, RSAKey *ssh1key);
+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);
@@ -1187,13 +1192,13 @@ bool import_possible(int type);
 int import_target_type(int type);
 bool import_encrypted(const Filename *filename, int type, char **comment);
 int import_ssh1(const Filename *filename, int type,
-		struct RSAKey *key, char *passphrase, const char **errmsg_p);
-struct ssh2_userkey *import_ssh2(const Filename *filename, int type,
-				 char *passphrase, const char **errmsg_p);
+		RSAKey *key, char *passphrase, const char **errmsg_p);
+ssh2_userkey *import_ssh2(const Filename *filename, int type,
+                          char *passphrase, const char **errmsg_p);
 bool export_ssh1(const Filename *filename, int type,
-                 struct RSAKey *key, char *passphrase);
+                 RSAKey *key, char *passphrase);
 bool export_ssh2(const Filename *filename, int type,
-                 struct ssh2_userkey *key, char *passphrase);
+                 ssh2_userkey *key, char *passphrase);
 
 void des3_decrypt_pubkey(const void *key, void *blk, int len);
 void des3_encrypt_pubkey(const void *key, void *blk, int len);
@@ -1222,7 +1227,7 @@ void openssh_bcrypt(const char *passphrase,
 #define PROGFN_PROGRESS 6
 typedef void (*progfn_t) (void *param, int action, int phase, int progress);
 
-int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
+int rsa_generate(RSAKey *key, int bits, progfn_t pfn,
 		 void *pfnparam);
 int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
 		 void *pfnparam);

+ 1 - 1
source/putty/ssh1bpp.c

@@ -69,7 +69,7 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp)
 }
 
 void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
-                         const struct ssh1_cipheralg *cipher,
+                         const ssh1_cipheralg *cipher,
                          const void *session_key)
 {
     struct ssh1_bpp_state *s;

+ 7 - 7
source/putty/ssh1login.c

@@ -49,12 +49,12 @@ struct ssh1_login_state {
     BinarySource asrc[1];          /* response from SSH agent */
     int keyi, nkeys;
     bool authed;
-    struct RSAKey key;
+    RSAKey key;
     mp_int *challenge;
     ptrlen comment;
     int dlgret;
     Filename *keyfile;
-    struct RSAKey servkey, hostkey;
+    RSAKey servkey, hostkey;
     bool want_user_input;
 
     PacketProtocolLayer ppl;
@@ -264,10 +264,10 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
     }
 
     {
-        struct RSAKey *smaller = (s->hostkey.bytes > s->servkey.bytes ?
-                                  &s->servkey : &s->hostkey);
-        struct RSAKey *larger = (s->hostkey.bytes > s->servkey.bytes ?
-                                 &s->hostkey : &s->servkey);
+        RSAKey *smaller = (s->hostkey.bytes > s->servkey.bytes ?
+                           &s->servkey : &s->hostkey);
+        RSAKey *larger = (s->hostkey.bytes > s->servkey.bytes ?
+                          &s->hostkey : &s->servkey);
 
         if (!rsa_ssh1_encrypt(s->rsabuf, 32, smaller) ||
             !rsa_ssh1_encrypt(s->rsabuf, smaller->bytes, larger)) {
@@ -362,7 +362,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
     ssh_bpp_handle_output(s->ppl.bpp);
 
     {
-        const struct ssh1_cipheralg *cipher =
+        const ssh1_cipheralg *cipher =
             (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh1_blowfish :
              s->cipher_type == SSH_CIPHER_DES ? &ssh1_des : &ssh1_3des);
         ssh1_bpp_new_cipher(s->ppl.bpp, cipher, s->session_key);

+ 38 - 28
source/putty/ssh2bpp.c

@@ -14,7 +14,7 @@ struct ssh2_bpp_direction {
     ssh2_cipher *cipher;
     ssh2_mac *mac;
     bool etm_mode;
-    const struct ssh_compression_alg *pending_compression;
+    const ssh_compression_alg *pending_compression;
 };
 
 struct ssh2_bpp_state {
@@ -67,42 +67,57 @@ BinaryPacketProtocol *ssh2_bpp_new(
     return &s->bpp;
 }
 
-static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
+static void ssh2_bpp_free_outgoing_crypto(struct ssh2_bpp_state *s)
 {
-    struct ssh2_bpp_state *s = container_of(bpp, struct ssh2_bpp_state, bpp);
-    sfree(s->buf);
-    if (s->out.cipher)
-        ssh2_cipher_free(s->out.cipher);
+    /*
+     * We must free the MAC before the cipher, because sometimes the
+     * MAC is not actually separately allocated but just a different
+     * facet of the same object as the cipher, in which case
+     * ssh2_mac_free does nothing and ssh2_cipher_free does the actual
+     * freeing. So if we freed the cipher first and then tried to
+     * dereference the MAC's vtable pointer to find out how to free
+     * that too, we'd be accessing freed memory.
+     */
     if (s->out.mac)
         ssh2_mac_free(s->out.mac);
+    if (s->out.cipher)
+        ssh2_cipher_free(s->out.cipher);
     if (s->out_comp)
         ssh_compressor_free(s->out_comp);
-    if (s->in.cipher)
-        ssh2_cipher_free(s->in.cipher);
+}
+
+static void ssh2_bpp_free_incoming_crypto(struct ssh2_bpp_state *s)
+{
+    /* As above, take care to free in.mac before in.cipher */
     if (s->in.mac)
         ssh2_mac_free(s->in.mac);
+    if (s->in.cipher)
+        ssh2_cipher_free(s->in.cipher);
     if (s->in_decomp)
         ssh_decompressor_free(s->in_decomp);
+}
+
+static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
+{
+    struct ssh2_bpp_state *s = container_of(bpp, struct ssh2_bpp_state, bpp);
+    sfree(s->buf);
+    ssh2_bpp_free_outgoing_crypto(s);
+    ssh2_bpp_free_incoming_crypto(s);
     sfree(s->pktin);
     sfree(s);
 }
 
 void ssh2_bpp_new_outgoing_crypto(
     BinaryPacketProtocol *bpp,
-    const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
-    const struct ssh2_macalg *mac, bool etm_mode, const void *mac_key,
-    const struct ssh_compression_alg *compression, bool delayed_compression)
+    const ssh2_cipheralg *cipher, const void *ckey, const void *iv,
+    const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
+    const ssh_compression_alg *compression, bool delayed_compression)
 {
     struct ssh2_bpp_state *s;
     assert(bpp->vt == &ssh2_bpp_vtable);
     s = container_of(bpp, struct ssh2_bpp_state, bpp);
 
-    if (s->out.cipher)
-        ssh2_cipher_free(s->out.cipher);
-    if (s->out.mac)
-        ssh2_mac_free(s->out.mac);
-    if (s->out_comp)
-        ssh_compressor_free(s->out_comp);
+    ssh2_bpp_free_outgoing_crypto(s);
 
     if (cipher) {
         s->out.cipher = ssh2_cipher_new(cipher);
@@ -122,7 +137,7 @@ void ssh2_bpp_new_outgoing_crypto(
     s->out.etm_mode = etm_mode;
     if (mac) {
         s->out.mac = ssh2_mac_new(mac, s->out.cipher);
-        ssh2_mac_setkey(s->out.mac, mac_key);
+        ssh2_mac_setkey(s->out.mac, make_ptrlen(mac_key, mac->keylen));
 
         bpp_logevent("Initialised %s outbound MAC algorithm%s%s",
                      ssh2_mac_alg(s->out.mac)->text_name,
@@ -156,20 +171,15 @@ void ssh2_bpp_new_outgoing_crypto(
 
 void ssh2_bpp_new_incoming_crypto(
     BinaryPacketProtocol *bpp,
-    const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
-    const struct ssh2_macalg *mac, bool etm_mode, const void *mac_key,
-    const struct ssh_compression_alg *compression, bool delayed_compression)
+    const ssh2_cipheralg *cipher, const void *ckey, const void *iv,
+    const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
+    const ssh_compression_alg *compression, bool delayed_compression)
 {
     struct ssh2_bpp_state *s;
     assert(bpp->vt == &ssh2_bpp_vtable);
     s = container_of(bpp, struct ssh2_bpp_state, bpp);
 
-    if (s->in.cipher)
-        ssh2_cipher_free(s->in.cipher);
-    if (s->in.mac)
-        ssh2_mac_free(s->in.mac);
-    if (s->in_decomp)
-        ssh_decompressor_free(s->in_decomp);
+    ssh2_bpp_free_incoming_crypto(s);
 
     if (cipher) {
         s->in.cipher = ssh2_cipher_new(cipher);
@@ -184,7 +194,7 @@ void ssh2_bpp_new_incoming_crypto(
     s->in.etm_mode = etm_mode;
     if (mac) {
         s->in.mac = ssh2_mac_new(mac, s->in.cipher);
-        ssh2_mac_setkey(s->in.mac, mac_key);
+        ssh2_mac_setkey(s->in.mac, make_ptrlen(mac_key, mac->keylen));
 
         bpp_logevent("Initialised %s inbound MAC algorithm%s%s",
                      ssh2_mac_alg(s->in.mac)->text_name,

+ 6 - 11
source/putty/ssh2kex-client.c

@@ -537,7 +537,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
 
         rsakeydata = get_string(pktin);
 
-        s->rsa_kex_key = ssh_rsakex_newkey(rsakeydata.ptr, rsakeydata.len);
+        s->rsa_kex_key = ssh_rsakex_newkey(rsakeydata);
         if (!s->rsa_kex_key) {
             ssh_proto_error(s->ppl.ssh,
                             "Unable to parse RSA public key packet");
@@ -557,9 +557,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
             int klen = ssh_rsakex_klen(s->rsa_kex_key);
             int nbits = klen - (2*s->kex_alg->hash->hlen*8 + 49);
             int i, byte = 0;
-            strbuf *buf;
-            unsigned char *outstr;
-            int outstrlen;
+            strbuf *buf, *outstr;
 
             s->K = mp_power_2(nbits - 1);
 
@@ -579,22 +577,19 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
             /*
              * Encrypt it with the given RSA key.
              */
-            outstrlen = (klen + 7) / 8;
-            outstr = snewn(outstrlen, unsigned char);
-            ssh_rsakex_encrypt(s->kex_alg->hash, buf->u, buf->len,
-                               outstr, outstrlen, s->rsa_kex_key);
+            outstr = ssh_rsakex_encrypt(s->rsa_kex_key, s->kex_alg->hash,
+                                        ptrlen_from_strbuf(buf));
 
             /*
              * And send it off in a return packet.
              */
             pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXRSA_SECRET);
-            put_string(pktout, outstr, outstrlen);
+            put_stringpl(pktout, ptrlen_from_strbuf(outstr));
             pq_push(s->ppl.out_pq, pktout);
 
-            put_string(s->exhash, outstr, outstrlen);
+            put_stringsb(s->exhash, outstr); /* frees outstr */
 
             strbuf_free(buf);
-            sfree(outstr);
         }
 
         ssh_rsakex_freekey(s->rsa_kex_key);

+ 12 - 12
source/putty/ssh2transport.c

@@ -18,10 +18,10 @@ const struct ssh_signkey_with_user_pref_id ssh2_hostkey_algs[] = {
     HOSTKEY_ALGORITHMS(ARRAYENT_HOSTKEY_ALGORITHM)
 };
 
-const static struct ssh2_macalg *const macs[] = {
+const static ssh2_macalg *const macs[] = {
     &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
 };
-const static struct ssh2_macalg *const buggymacs[] = {
+const static ssh2_macalg *const buggymacs[] = {
     &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5
 };
 
@@ -51,13 +51,13 @@ static bool ssh_decomp_none_block(ssh_decompressor *handle,
 {
     return false;
 }
-const static struct ssh_compression_alg ssh_comp_none = {
+const static ssh_compression_alg ssh_comp_none = {
     "none", NULL,
     ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,
     ssh_decomp_none_init, ssh_decomp_none_cleanup, ssh_decomp_none_block,
     NULL
 };
-const static struct ssh_compression_alg *const compressions[] = {
+const static ssh_compression_alg *const compressions[] = {
     &ssh_zlib, &ssh_comp_none
 };
 
@@ -421,13 +421,13 @@ static void ssh2_write_kexinit_lists(
     bool warn;
 
     int n_preferred_kex;
-    const struct ssh_kexes *preferred_kex[KEX_MAX + 1]; /* +1 for GSSAPI */
+    const ssh_kexes *preferred_kex[KEX_MAX + 1]; /* +1 for GSSAPI */
     int n_preferred_hk;
     int preferred_hk[HK_MAX];
     int n_preferred_ciphers;
-    const struct ssh2_ciphers *preferred_ciphers[CIPHER_MAX];
-    const struct ssh_compression_alg *preferred_comp;
-    const struct ssh2_macalg *const *maclist;
+    const ssh2_ciphers *preferred_ciphers[CIPHER_MAX];
+    const ssh_compression_alg *preferred_comp;
+    const ssh2_macalg *const *maclist;
     int nmacs;
 
     struct kexinit_algorithm *alg;
@@ -533,7 +533,7 @@ static void ssh2_write_kexinit_lists(
     /* List key exchange algorithms. */
     warn = false;
     for (i = 0; i < n_preferred_kex; i++) {
-        const struct ssh_kexes *k = preferred_kex[i];
+        const ssh_kexes *k = preferred_kex[i];
         if (!k) warn = true;
         else for (j = 0; j < k->nkexes; j++) {
                 alg = ssh2_kexinit_addalg(kexlists[KEXLIST_KEX],
@@ -653,7 +653,7 @@ static void ssh2_write_kexinit_lists(
         alg->u.cipher.warn = warn;
 #endif /* FUZZING */
         for (i = 0; i < n_preferred_ciphers; i++) {
-            const struct ssh2_ciphers *c = preferred_ciphers[i];
+            const ssh2_ciphers *c = preferred_ciphers[i];
             if (!c) warn = true;
             else for (j = 0; j < c->nciphers; j++) {
                     alg = ssh2_kexinit_addalg(kexlists[k],
@@ -714,7 +714,7 @@ static void ssh2_write_kexinit_lists(
             alg->u.comp.delayed = true;
         }
         for (i = 0; i < lenof(compressions); i++) {
-            const struct ssh_compression_alg *c = compressions[i];
+            const ssh_compression_alg *c = compressions[i];
             alg = ssh2_kexinit_addalg(kexlists[j], c->name);
             alg->u.comp.comp = c;
             alg->u.comp.delayed = false;
@@ -747,7 +747,7 @@ static void ssh2_write_kexinit_lists(
 static bool ssh2_scan_kexinits(
     ptrlen client_kexinit, ptrlen server_kexinit,
     struct kexinit_algorithm kexlists[NKEXLIST][MAXKEXLIST],
-    const struct ssh_kex **kex_alg, const ssh_keyalg **hostkey_alg,
+    const ssh_kex **kex_alg, const ssh_keyalg **hostkey_alg,
     transport_direction *cs, transport_direction *sc,
     bool *warn_kex, bool *warn_hk, bool *warn_cscipher, bool *warn_sccipher,
     Ssh *ssh, bool *ignore_guess_cs_packet, bool *ignore_guess_sc_packet,

+ 10 - 10
source/putty/ssh2transport.h

@@ -28,7 +28,7 @@ struct kexinit_algorithm {
     const char *name;
     union {
         struct {
-            const struct ssh_kex *kex;
+            const ssh_kex *kex;
             bool warn;
         } kex;
         struct {
@@ -36,15 +36,15 @@ struct kexinit_algorithm {
             bool warn;
         } hk;
         struct {
-            const struct ssh2_cipheralg *cipher;
+            const ssh2_cipheralg *cipher;
             bool warn;
         } cipher;
         struct {
-            const struct ssh2_macalg *mac;
+            const ssh2_macalg *mac;
             bool etm;
         } mac;
         struct {
-            const struct ssh_compression_alg *comp;
+            const ssh_compression_alg *comp;
             bool delayed;
         } comp;
     } u;
@@ -104,10 +104,10 @@ typedef enum RekeyClass {
 } RekeyClass;
 
 typedef struct transport_direction {
-    const struct ssh2_cipheralg *cipher;
-    const struct ssh2_macalg *mac;
+    const ssh2_cipheralg *cipher;
+    const ssh2_macalg *mac;
     bool etm_mode;
-    const struct ssh_compression_alg *comp;
+    const ssh_compression_alg *comp;
     bool comp_delayed;
     int mkkey_adjust;
 } transport_direction;
@@ -128,14 +128,14 @@ struct ssh2_transport_state {
 
     unsigned long max_data_size;
 
-    const struct ssh_kex *kex_alg;
+    const ssh_kex *kex_alg;
     const ssh_keyalg *hostkey_alg;
     char *hostkey_str; /* string representation, for easy checking in rekeys */
     unsigned char session_id[MAX_HASH_LEN];
     int session_id_len;
     int dh_min_size, dh_max_size;
     bool dh_got_size_bounds;
-    struct dh_ctx *dh_ctx;
+    dh_ctx *dh_ctx;
     ssh_hash *exhash;
 
     struct DataTransferStats *stats;
@@ -176,7 +176,7 @@ struct ssh2_transport_state {
     strbuf *hostkeyblob;
     char *keystr, *fingerprint;
     ssh_key *hkey;                     /* actual host key */
-    struct RSAKey *rsa_kex_key;             /* for RSA kex */
+    RSAKey *rsa_kex_key;             /* for RSA kex */
     ecdh_key *ecdh_key;                     /* for ECDH kex */
     unsigned char exchange_hash[MAX_HASH_LEN];
     bool can_gssapi_keyex;

+ 5 - 5
source/putty/ssh2userauth.c

@@ -577,7 +577,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                  * Save the methods string for use in error messages.
                  */
                 s->last_methods_string->len = 0;
-                put_data(s->last_methods_string, methods.ptr, methods.len);
+                put_datapl(s->last_methods_string, methods);
 #ifdef WINSCP
                 ppl_logevent("Server offered these authentication methods: %s", s->last_methods_string->s);
 #endif
@@ -757,7 +757,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
             } else if (s->can_pubkey && s->publickey_blob &&
                        s->privatekey_available && !s->tried_pubkey_config) {
 
-                struct ssh2_userkey *key;   /* not live over crReturn */
+                ssh2_userkey *key;   /* not live over crReturn */
                 char *passphrase;           /* not live over crReturn */
 
                 s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY;
@@ -903,7 +903,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                     put_data(sigdata, s->pktout->data + 5,
                              s->pktout->length - 5);
                     sigblob = strbuf_new();
-                    ssh_key_sign(key->key, sigdata->s, sigdata->len, 0,
+                    ssh_key_sign(key->key, ptrlen_from_strbuf(sigdata), 0,
                                  BinarySink_UPCAST(sigblob));
                     strbuf_free(sigdata);
                     ssh2_userauth_add_sigblob(
@@ -1592,7 +1592,7 @@ static void ssh2_userauth_add_session_id(
     struct ssh2_userauth_state *s, strbuf *sigdata)
 {
     if (s->ppl.remote_bugs & BUG_SSH2_PK_SESSIONID) {
-        put_data(sigdata, s->session_id.ptr, s->session_id.len);
+        put_datapl(sigdata, s->session_id);
     } else {
         put_stringpl(sigdata, s->session_id);
     }
@@ -1678,7 +1678,7 @@ static void ssh2_userauth_add_sigblob(
 	    put_data(substr, sigblob.ptr, sig_prefix_len);
 	    put_uint32(substr, mod_mp.len);
 	    put_padding(substr, mod_mp.len - sig_mp.len, 0);
-	    put_data(substr, sig_mp.ptr, sig_mp.len);
+	    put_datapl(substr, sig_mp);
             put_stringsb(pkt, substr);
 	    return;
 	}

+ 15 - 16
source/putty/sshaes.c

@@ -1054,7 +1054,7 @@ struct aes_ssh2_ctx {
     ssh2_cipher ciph;
 };
 
-ssh2_cipher *aes_ssh2_new(const struct ssh2_cipheralg *alg)
+ssh2_cipher *aes_ssh2_new(const ssh2_cipheralg *alg)
 {
     struct aes_ssh2_ctx *ctx = snew(struct aes_ssh2_ctx);
     ctx->ciph.vt = alg;
@@ -1098,7 +1098,7 @@ static void aes_ssh2_sdctr_method(ssh2_cipher *cipher, void *blk, int len)
     aes_sdctr(blk, len, &ctx->context);
 }
 
-static const struct ssh2_cipheralg ssh_aes128_ctr = {
+const ssh2_cipheralg ssh_aes128_ctr = {
     aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey,
     aes_ssh2_sdctr_method, aes_ssh2_sdctr_method, NULL, NULL,
     "aes128-ctr",
@@ -1106,7 +1106,7 @@ static const struct ssh2_cipheralg ssh_aes128_ctr = {
     NULL
 };
 
-static const struct ssh2_cipheralg ssh_aes192_ctr = {
+const ssh2_cipheralg ssh_aes192_ctr = {
     aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey,
     aes_ssh2_sdctr_method, aes_ssh2_sdctr_method, NULL, NULL,
     "aes192-ctr",
@@ -1114,7 +1114,7 @@ static const struct ssh2_cipheralg ssh_aes192_ctr = {
     NULL
 };
 
-static const struct ssh2_cipheralg ssh_aes256_ctr = {
+const ssh2_cipheralg ssh_aes256_ctr = {
     aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey,
     aes_ssh2_sdctr_method, aes_ssh2_sdctr_method, NULL, NULL,
     "aes256-ctr",
@@ -1122,7 +1122,7 @@ static const struct ssh2_cipheralg ssh_aes256_ctr = {
     NULL
 };
 
-static const struct ssh2_cipheralg ssh_aes128 = {
+const ssh2_cipheralg ssh_aes128 = {
     aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey,
     aes_ssh2_encrypt, aes_ssh2_decrypt, NULL, NULL,
     "aes128-cbc",
@@ -1130,7 +1130,7 @@ static const struct ssh2_cipheralg ssh_aes128 = {
     NULL
 };
 
-static const struct ssh2_cipheralg ssh_aes192 = {
+const ssh2_cipheralg ssh_aes192 = {
     aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey,
     aes_ssh2_encrypt, aes_ssh2_decrypt, NULL, NULL,
     "aes192-cbc",
@@ -1138,7 +1138,7 @@ static const struct ssh2_cipheralg ssh_aes192 = {
     NULL
 };
 
-static const struct ssh2_cipheralg ssh_aes256 = {
+const ssh2_cipheralg ssh_aes256 = {
     aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey,
     aes_ssh2_encrypt, aes_ssh2_decrypt, NULL, NULL,
     "aes256-cbc",
@@ -1146,7 +1146,9 @@ static const struct ssh2_cipheralg ssh_aes256 = {
     NULL
 };
 
-static const struct ssh2_cipheralg ssh_rijndael_lysator = {
+/* This cipher is just ssh_aes256 under a different protocol
+ * identifier; we leave it 'static' because testcrypt won't need it */
+static const ssh2_cipheralg ssh_rijndael_lysator = {
     aes_ssh2_new, aes_ssh2_free, aes_ssh2_setiv, aes_ssh2_setkey,
     aes_ssh2_encrypt, aes_ssh2_decrypt, NULL, NULL,
     "[email protected]",
@@ -1154,7 +1156,7 @@ static const struct ssh2_cipheralg ssh_rijndael_lysator = {
     NULL
 };
 
-static const struct ssh2_cipheralg *const aes_list[] = {
+static const ssh2_cipheralg *const aes_list[] = {
     &ssh_aes256_ctr,
     &ssh_aes256,
     &ssh_rijndael_lysator,
@@ -1164,10 +1166,7 @@ static const struct ssh2_cipheralg *const aes_list[] = {
     &ssh_aes128,
 };
 
-const struct ssh2_ciphers ssh2_aes = {
-    sizeof(aes_list) / sizeof(*aes_list),
-    aes_list
-};
+const ssh2_ciphers ssh2_aes = { lenof(aes_list), aes_list };
 
 /*
  * Implementation of AES for PuTTY using AES-NI
@@ -1582,8 +1581,8 @@ static void aes_decrypt_cbc_ni(unsigned char *blk, int len, AESContext * ctx)
 FUNC_ISA
 static void aes_sdctr_ni(unsigned char *blk, int len, AESContext *ctx)
 {
-    const __m128i BSWAP_EPI64 = _mm_setr_epi8(3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12);
-    const __m128i ONE  = _mm_setr_epi32(0,0,0,1);
+    const __m128i BSWAP_EPI64 = _mm_setr_epi8(7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8);
+    const __m128i ONE  = _mm_setr_epi32(0,0,1,0);
     const __m128i ZERO = _mm_setzero_si128();
     __m128i iv;
     __m128i* block = (__m128i*)blk;
@@ -1630,7 +1629,7 @@ static void aes_sdctr_ni(unsigned char *blk, int len, AESContext *ctx)
         iv  = _mm_shuffle_epi8(iv, BSWAP_EPI64); /* Swap endianess     */
         iv  = _mm_add_epi64(iv, ONE);            /* Inc low part       */
         enc = _mm_cmpeq_epi64(iv, ZERO);         /* Check for carry    */
-        enc = _mm_unpacklo_epi64(ZERO, enc);     /* Pack carry reg     */
+        enc = _mm_unpackhi_epi64(enc, ZERO);     /* Pack carry reg     */
         iv  = _mm_sub_epi64(iv, enc);            /* Sub carry reg      */
         iv  = _mm_shuffle_epi8(iv, BSWAP_EPI64); /* Swap enianess back */
 

+ 5 - 8
source/putty/ssharcf.c

@@ -62,7 +62,7 @@ static void arcfour_setkey(ArcfourContext *ctx, unsigned char const *key,
  * to leak data about the key.
  */
 
-static ssh2_cipher *arcfour_new(const struct ssh2_cipheralg *alg)
+static ssh2_cipher *arcfour_new(const ssh2_cipheralg *alg)
 {
     ArcfourContext *ctx = snew(ArcfourContext);
     ctx->ciph.vt = alg;
@@ -103,7 +103,7 @@ static void arcfour_ssh2_block(ssh2_cipher *cipher, void *blk, int len)
     arcfour_block(ctx, blk, len);
 }
 
-const struct ssh2_cipheralg ssh_arcfour128_ssh2 = {
+const ssh2_cipheralg ssh_arcfour128_ssh2 = {
     arcfour_new, arcfour_free, arcfour_ssh2_setiv, arcfour_ssh2_setkey,
     arcfour_ssh2_block, arcfour_ssh2_block, NULL, NULL,
     "arcfour128",
@@ -111,7 +111,7 @@ const struct ssh2_cipheralg ssh_arcfour128_ssh2 = {
     NULL
 };
 
-const struct ssh2_cipheralg ssh_arcfour256_ssh2 = {
+const ssh2_cipheralg ssh_arcfour256_ssh2 = {
     arcfour_new, arcfour_free, arcfour_ssh2_setiv, arcfour_ssh2_setkey,
     arcfour_ssh2_block, arcfour_ssh2_block, NULL, NULL,
     "arcfour256",
@@ -119,12 +119,9 @@ const struct ssh2_cipheralg ssh_arcfour256_ssh2 = {
     NULL
 };
 
-static const struct ssh2_cipheralg *const arcfour_list[] = {
+static const ssh2_cipheralg *const arcfour_list[] = {
     &ssh_arcfour256_ssh2,
     &ssh_arcfour128_ssh2,
 };
 
-const struct ssh2_ciphers ssh2_arcfour = {
-    sizeof(arcfour_list) / sizeof(*arcfour_list),
-    arcfour_list
-};
+const ssh2_ciphers ssh2_arcfour = { lenof(arcfour_list), arcfour_list };

+ 6 - 9
source/putty/sshblowf.c

@@ -622,7 +622,7 @@ struct blowfish_ssh2_ctx {
     ssh2_cipher ciph;
 };
 
-static ssh2_cipher *blowfish_ssh2_new(const struct ssh2_cipheralg *alg)
+static ssh2_cipher *blowfish_ssh2_new(const ssh2_cipheralg *alg)
 {
     struct blowfish_ssh2_ctx *ctx = snew(struct blowfish_ssh2_ctx);
     ctx->ciph.vt = alg;
@@ -672,14 +672,14 @@ static void blowfish_ssh2_sdctr(ssh2_cipher *cipher, void *blk, int len)
     blowfish_msb_sdctr(blk, len, &ctx->context);
 }
 
-const struct ssh1_cipheralg ssh1_blowfish = {
+const ssh1_cipheralg ssh1_blowfish = {
     blowfish_ssh1_new, blowfish_ssh1_free,
     blowfish_ssh1_sesskey,
     blowfish_ssh1_encrypt_blk, blowfish_ssh1_decrypt_blk,
     8, "Blowfish-128 CBC"
 };
 
-static const struct ssh2_cipheralg ssh_blowfish_ssh2 = {
+const ssh2_cipheralg ssh_blowfish_ssh2 = {
     blowfish_ssh2_new, blowfish_ssh2_free,
     blowfish_ssh2_setiv, blowfish_ssh2_setkey,
     blowfish_ssh2_encrypt_blk, blowfish_ssh2_decrypt_blk, NULL, NULL,
@@ -688,7 +688,7 @@ static const struct ssh2_cipheralg ssh_blowfish_ssh2 = {
     NULL
 };
 
-static const struct ssh2_cipheralg ssh_blowfish_ssh2_ctr = {
+const ssh2_cipheralg ssh_blowfish_ssh2_ctr = {
     blowfish_ssh2_new, blowfish_ssh2_free,
     blowfish_ssh2_setiv, blowfish_ssh2_setkey,
     blowfish_ssh2_sdctr, blowfish_ssh2_sdctr, NULL, NULL,
@@ -697,12 +697,9 @@ static const struct ssh2_cipheralg ssh_blowfish_ssh2_ctr = {
     NULL
 };
 
-static const struct ssh2_cipheralg *const blowfish_list[] = {
+static const ssh2_cipheralg *const blowfish_list[] = {
     &ssh_blowfish_ssh2_ctr,
     &ssh_blowfish_ssh2
 };
 
-const struct ssh2_ciphers ssh2_blowfish = {
-    sizeof(blowfish_list) / sizeof(*blowfish_list),
-    blowfish_list
-};
+const ssh2_ciphers ssh2_blowfish = { lenof(blowfish_list), blowfish_list };

+ 7 - 7
source/putty/sshbpp.h

@@ -54,7 +54,7 @@ void ssh_bpp_free(BinaryPacketProtocol *bpp);
 
 BinaryPacketProtocol *ssh1_bpp_new(LogContext *logctx);
 void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
-                         const struct ssh1_cipheralg *cipher,
+                         const ssh1_cipheralg *cipher,
                          const void *session_key);
 /* This is only called from outside the BPP in server mode; in client
  * mode the BPP detects compression start time automatically by
@@ -104,14 +104,14 @@ BinaryPacketProtocol *ssh2_bpp_new(
     LogContext *logctx, struct DataTransferStats *stats, bool is_server);
 void ssh2_bpp_new_outgoing_crypto(
     BinaryPacketProtocol *bpp,
-    const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
-    const struct ssh2_macalg *mac, bool etm_mode, const void *mac_key,
-    const struct ssh_compression_alg *compression, bool delayed_compression);
+    const ssh2_cipheralg *cipher, const void *ckey, const void *iv,
+    const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
+    const ssh_compression_alg *compression, bool delayed_compression);
 void ssh2_bpp_new_incoming_crypto(
     BinaryPacketProtocol *bpp,
-    const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
-    const struct ssh2_macalg *mac, bool etm_mode, const void *mac_key,
-    const struct ssh_compression_alg *compression, bool delayed_compression);
+    const ssh2_cipheralg *cipher, const void *ckey, const void *iv,
+    const ssh2_macalg *mac, bool etm_mode, const void *mac_key,
+    const ssh_compression_alg *compression, bool delayed_compression);
 
 /*
  * A query method specific to the interface between ssh2transport and

+ 14 - 16
source/putty/sshccp.c

@@ -772,11 +772,12 @@ static void poly1305_init(struct poly1305 *ctx)
     bigval_clear(&ctx->h);
 }
 
-/* Takes a 256 bit key */
-static void poly1305_key(struct poly1305 *ctx, const unsigned char *key)
+static void poly1305_key(struct poly1305 *ctx, ptrlen key)
 {
+    assert(key.len == 32);             /* Takes a 256 bit key */
+
     unsigned char key_copy[16];
-    memcpy(key_copy, key, 16);
+    memcpy(key_copy, key.ptr, 16);
 
     /* Key the MAC itself
      * bytes 4, 8, 12 and 16 are required to have their top four bits clear */
@@ -791,8 +792,8 @@ static void poly1305_key(struct poly1305 *ctx, const unsigned char *key)
     bigval_import_le(&ctx->r, key_copy, 16);
     smemclr(key_copy, sizeof(key_copy));
 
-    /* Use second 128 bits are the nonce */
-    memcpy(ctx->nonce, key+16, 16);
+    /* Use second 128 bits as the nonce */
+    memcpy(ctx->nonce, (const char *)key.ptr + 16, 16);
 }
 
 /* Feed up to 16 bytes (should only be less for the last chunk) */
@@ -871,7 +872,7 @@ struct ccp_context {
 };
 
 static ssh2_mac *poly_ssh2_new(
-    const struct ssh2_macalg *alg, ssh2_cipher *cipher)
+    const ssh2_macalg *alg, ssh2_cipher *cipher)
 {
     struct ccp_context *ctx = container_of(cipher, struct ccp_context, ciph);
     ctx->mac_if.vt = alg;
@@ -884,7 +885,7 @@ static void poly_ssh2_free(ssh2_mac *mac)
     /* Not allocated, just forwarded, no need to free */
 }
 
-static void poly_setkey(ssh2_mac *mac, const void *key)
+static void poly_setkey(ssh2_mac *mac, ptrlen key)
 {
     /* Uses the same context as ChaCha20, so ignore */
 }
@@ -919,7 +920,7 @@ static void poly_BinarySink_write(BinarySink *bs, const void *blkv, size_t len)
         chacha20_round(&ctx->b_cipher);
 
         /* Set the poly key */
-        poly1305_key(&ctx->mac, ctx->b_cipher.current);
+        poly1305_key(&ctx->mac, make_ptrlen(ctx->b_cipher.current, 32));
 
         /* Set the first round as used */
         ctx->b_cipher.currentIndex = 64;
@@ -937,7 +938,7 @@ static void poly_genresult(ssh2_mac *mac, unsigned char *blk)
     poly1305_finalise(&ctx->mac, blk);
 }
 
-static const struct ssh2_macalg ssh2_poly1305 = {
+const ssh2_macalg ssh2_poly1305 = {
     poly_ssh2_new, poly_ssh2_free, poly_setkey,
     poly_start, poly_genresult,
 
@@ -945,7 +946,7 @@ static const struct ssh2_macalg ssh2_poly1305 = {
     16, 0, "Poly1305"
 };
 
-static ssh2_cipher *ccp_new(const struct ssh2_cipheralg *alg)
+static ssh2_cipher *ccp_new(const ssh2_cipheralg *alg)
 {
     struct ccp_context *ctx = snew(struct ccp_context);
     BinarySink_INIT(ctx, poly_BinarySink_write);
@@ -1025,7 +1026,7 @@ static void ccp_decrypt_length(ssh2_cipher *cipher, void *blk, int len,
     chacha20_decrypt(&ctx->a_cipher, blk, len);
 }
 
-static const struct ssh2_cipheralg ssh2_chacha20_poly1305 = {
+const ssh2_cipheralg ssh2_chacha20_poly1305 = {
 
     ccp_new,
     ccp_free,
@@ -1042,11 +1043,8 @@ static const struct ssh2_cipheralg ssh2_chacha20_poly1305 = {
     &ssh2_poly1305
 };
 
-static const struct ssh2_cipheralg *const ccp_list[] = {
+static const ssh2_cipheralg *const ccp_list[] = {
     &ssh2_chacha20_poly1305
 };
 
-const struct ssh2_ciphers ssh2_ccp = {
-    sizeof(ccp_list) / sizeof(*ccp_list),
-    ccp_list
-};
+const ssh2_ciphers ssh2_ccp = { lenof(ccp_list), ccp_list };

+ 1 - 1
source/putty/sshcommon.c

@@ -1038,7 +1038,7 @@ bool ssh1_common_filter_queue(PacketProtocolLayer *ppl)
 
 void ssh1_compute_session_id(
     unsigned char *session_id, const unsigned char *cookie,
-    struct RSAKey *hostkey, struct RSAKey *servkey)
+    RSAKey *hostkey, RSAKey *servkey)
 {
     struct MD5Context md5c;
     size_t i; // WINSCP

+ 12 - 73
source/putty/sshdes.c

@@ -869,14 +869,14 @@ struct des_ssh2_ctx {
     ssh2_cipher ciph;
 };
 
-static ssh2_cipher *des3_ssh2_new(const struct ssh2_cipheralg *alg)
+static ssh2_cipher *des3_ssh2_new(const ssh2_cipheralg *alg)
 {
     struct des3_ssh2_ctx *ctx = snew(struct des3_ssh2_ctx);
     ctx->ciph.vt = alg;
     return &ctx->ciph;
 }
 
-static ssh2_cipher *des_ssh2_new(const struct ssh2_cipheralg *alg)
+static ssh2_cipher *des_ssh2_new(const ssh2_cipheralg *alg)
 {
     struct des_ssh2_ctx *ctx = snew(struct des_ssh2_ctx);
     ctx->ciph.vt = alg;
@@ -1070,7 +1070,7 @@ void des_decrypt_xdmauth(const void *keydata, void *blk, int len)
     des_cbc_decrypt(blk, len, &dc);
 }
 
-static const struct ssh2_cipheralg ssh_3des_ssh2 = {
+const ssh2_cipheralg ssh_3des_ssh2 = {
     des3_ssh2_new, des3_ssh2_free, des3_ssh2_setiv, des3_ssh2_setkey,
     des3_ssh2_encrypt_blk, des3_ssh2_decrypt_blk, NULL, NULL,
     "3des-cbc",
@@ -1078,7 +1078,7 @@ static const struct ssh2_cipheralg ssh_3des_ssh2 = {
     NULL
 };
 
-static const struct ssh2_cipheralg ssh_3des_ssh2_ctr = {
+const ssh2_cipheralg ssh_3des_ssh2_ctr = {
     des3_ssh2_new, des3_ssh2_free, des3_ssh2_setiv, des3_ssh2_setkey,
     des3_ssh2_sdctr, des3_ssh2_sdctr, NULL, NULL,
     "3des-ctr",
@@ -1094,7 +1094,7 @@ static const struct ssh2_cipheralg ssh_3des_ssh2_ctr = {
  * apparently aren't the only people to do so, so we sigh 
  * and implement it anyway.
  */
-static const struct ssh2_cipheralg ssh_des_ssh2 = {
+const ssh2_cipheralg ssh_des_ssh2 = {
     des_ssh2_new, des_ssh2_free, des_ssh2_setiv, des_ssh2_setkey,
     des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, NULL, NULL,
     "des-cbc",
@@ -1102,7 +1102,7 @@ static const struct ssh2_cipheralg ssh_des_ssh2 = {
     NULL
 };
 
-static const struct ssh2_cipheralg ssh_des_sshcom_ssh2 = {
+const ssh2_cipheralg ssh_des_sshcom_ssh2 = {
     des_ssh2_new, des_ssh2_free, des_ssh2_setiv, des_ssh2_setkey,
     des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, NULL, NULL,
     "[email protected]",
@@ -1110,89 +1110,28 @@ static const struct ssh2_cipheralg ssh_des_sshcom_ssh2 = {
     NULL
 };
 
-static const struct ssh2_cipheralg *const des3_list[] = {
+static const ssh2_cipheralg *const des3_list[] = {
     &ssh_3des_ssh2_ctr,
     &ssh_3des_ssh2
 };
 
-const struct ssh2_ciphers ssh2_3des = {
-    sizeof(des3_list) / sizeof(*des3_list),
-    des3_list
-};
+const ssh2_ciphers ssh2_3des = { lenof(des3_list), des3_list };
 
-static const struct ssh2_cipheralg *const des_list[] = {
+static const ssh2_cipheralg *const des_list[] = {
     &ssh_des_ssh2,
     &ssh_des_sshcom_ssh2
 };
 
-const struct ssh2_ciphers ssh2_des = {
-    sizeof(des_list) / sizeof(*des_list),
-    des_list
-};
+const ssh2_ciphers ssh2_des = { lenof(des_list), des_list };
 
-const struct ssh1_cipheralg ssh1_3des = {
+const ssh1_cipheralg ssh1_3des = {
     des3_ssh1_new, des3_ssh1_free, des3_ssh1_sesskey,
     des3_ssh1_encrypt_blk, des3_ssh1_decrypt_blk,
     8, "triple-DES inner-CBC"
 };
 
-const struct ssh1_cipheralg ssh1_des = {
+const ssh1_cipheralg ssh1_des = {
     des_ssh1_new, des_ssh1_free, des_ssh1_sesskey,
     des_ssh1_encrypt_blk, des_ssh1_decrypt_blk,
     8, "single-DES CBC"
 };
-
-#ifdef TEST_XDM_AUTH
-
-/*
- * Small standalone utility which allows encryption and decryption of
- * single cipher blocks in the XDM-AUTHORIZATION-1 style. Written
- * during the rework of X authorisation for connection sharing, to
- * check the corner case when xa1_firstblock matches but the rest of
- * the authorisation is bogus.
- *
- * Just compile this file on its own with the above ifdef symbol
- * predefined:
-
-gcc -DTEST_XDM_AUTH -o sshdes sshdes.c
-
- */
-
-#include <stdlib.h>
-void *safemalloc(size_t n, size_t size) { return calloc(n, size); }
-void safefree(void *p) { return free(p); }
-void smemclr(void *p, size_t size) { memset(p, 0, size); }
-int main(int argc, char **argv)
-{
-    unsigned char words[2][8];
-    unsigned char out[8];
-    int i, j;
-
-    memset(words, 0, sizeof(words));
-
-    for (i = 0; i < 2; i++) {
-        for (j = 0; j < 8 && argv[i+1][2*j]; j++) {
-            char x[3];
-            unsigned u;
-            x[0] = argv[i+1][2*j];
-            x[1] = argv[i+1][2*j+1];
-            x[2] = 0;
-            sscanf(x, "%02x", &u);
-            words[i][j] = u;
-        }
-    }
-
-    memcpy(out, words[0], 8);
-    des_decrypt_xdmauth(words[1], out, 8);
-    printf("decrypt(%s,%s) = ", argv[1], argv[2]);
-    for (i = 0; i < 8; i++) printf("%02x", out[i]);
-    printf("\n");
-
-    memcpy(out, words[0], 8);
-    des_encrypt_xdmauth(words[1], out, 8);
-    printf("encrypt(%s,%s) = ", argv[1], argv[2]);
-    for (i = 0; i < 8; i++) printf("%02x", out[i]);
-    printf("\n");
-}
-
-#endif

+ 32 - 40
source/putty/sshdh.c

@@ -14,16 +14,16 @@ struct dh_ctx {
 
 struct dh_extra {
     bool gex;
-    void (*construct)(struct dh_ctx *ctx);
+    void (*construct)(dh_ctx *ctx);
 };
 
-static void dh_group1_construct(struct dh_ctx *ctx)
+static void dh_group1_construct(dh_ctx *ctx)
 {
     ctx->p = MP_LITERAL(0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF);
     ctx->g = mp_from_integer(2);
 }
 
-static void dh_group14_construct(struct dh_ctx *ctx)
+static void dh_group14_construct(dh_ctx *ctx)
 {
     ctx->p = MP_LITERAL(0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF);
     ctx->g = mp_from_integer(2);
@@ -33,65 +33,58 @@ static const struct dh_extra extra_group1 = {
     false, dh_group1_construct,
 };
 
-static const struct ssh_kex ssh_diffiehellman_group1_sha1 = {
+static const ssh_kex ssh_diffiehellman_group1_sha1 = {
     "diffie-hellman-group1-sha1", "group1",
     KEXTYPE_DH, &ssh_sha1, &extra_group1,
 };
 
-static const struct ssh_kex *const group1_list[] = {
+static const ssh_kex *const group1_list[] = {
     &ssh_diffiehellman_group1_sha1
 };
 
-const struct ssh_kexes ssh_diffiehellman_group1 = {
-    sizeof(group1_list) / sizeof(*group1_list),
-    group1_list
-};
+const ssh_kexes ssh_diffiehellman_group1 = { lenof(group1_list), group1_list };
 
 static const struct dh_extra extra_group14 = {
     false, dh_group14_construct,
 };
 
-static const struct ssh_kex ssh_diffiehellman_group14_sha256 = {
+static const ssh_kex ssh_diffiehellman_group14_sha256 = {
     "diffie-hellman-group14-sha256", "group14",
     KEXTYPE_DH, &ssh_sha256, &extra_group14,
 };
 
-static const struct ssh_kex ssh_diffiehellman_group14_sha1 = {
+static const ssh_kex ssh_diffiehellman_group14_sha1 = {
     "diffie-hellman-group14-sha1", "group14",
     KEXTYPE_DH, &ssh_sha1, &extra_group14,
 };
 
-static const struct ssh_kex *const group14_list[] = {
+static const ssh_kex *const group14_list[] = {
     &ssh_diffiehellman_group14_sha256,
     &ssh_diffiehellman_group14_sha1
 };
 
-const struct ssh_kexes ssh_diffiehellman_group14 = {
-    sizeof(group14_list) / sizeof(*group14_list),
-    group14_list
+const ssh_kexes ssh_diffiehellman_group14 = {
+    lenof(group14_list), group14_list
 };
 
 static const struct dh_extra extra_gex = { true };
 
-static const struct ssh_kex ssh_diffiehellman_gex_sha256 = {
+static const ssh_kex ssh_diffiehellman_gex_sha256 = {
     "diffie-hellman-group-exchange-sha256", NULL,
     KEXTYPE_DH, &ssh_sha256, &extra_gex,
 };
 
-static const struct ssh_kex ssh_diffiehellman_gex_sha1 = {
+static const ssh_kex ssh_diffiehellman_gex_sha1 = {
     "diffie-hellman-group-exchange-sha1", NULL,
     KEXTYPE_DH, &ssh_sha1, &extra_gex,
 };
 
-static const struct ssh_kex *const gex_list[] = {
+static const ssh_kex *const gex_list[] = {
     &ssh_diffiehellman_gex_sha256,
     &ssh_diffiehellman_gex_sha1
 };
 
-const struct ssh_kexes ssh_diffiehellman_gex = {
-    sizeof(gex_list) / sizeof(*gex_list),
-    gex_list
-};
+const ssh_kexes ssh_diffiehellman_gex = { lenof(gex_list), gex_list };
 
 /*
  * Suffix on GSSAPI SSH protocol identifiers that indicates Kerberos 5
@@ -107,42 +100,41 @@ const struct ssh_kexes ssh_diffiehellman_gex = {
  */
 #define GSS_KRB5_OID_HASH "toWM5Slw5Ew8Mqkay+al2g=="
 
-static const struct ssh_kex ssh_gssk5_diffiehellman_gex_sha1 = {
+static const ssh_kex ssh_gssk5_diffiehellman_gex_sha1 = {
     "gss-gex-sha1-" GSS_KRB5_OID_HASH, NULL,
     KEXTYPE_GSS, &ssh_sha1, &extra_gex,
 };
 
-static const struct ssh_kex ssh_gssk5_diffiehellman_group14_sha1 = {
+static const ssh_kex ssh_gssk5_diffiehellman_group14_sha1 = {
     "gss-group14-sha1-" GSS_KRB5_OID_HASH, "group14",
     KEXTYPE_GSS, &ssh_sha1, &extra_group14,
 };
 
-static const struct ssh_kex ssh_gssk5_diffiehellman_group1_sha1 = {
+static const ssh_kex ssh_gssk5_diffiehellman_group1_sha1 = {
     "gss-group1-sha1-" GSS_KRB5_OID_HASH, "group1",
     KEXTYPE_GSS, &ssh_sha1, &extra_group1,
 };
 
-static const struct ssh_kex *const gssk5_sha1_kex_list[] = {
+static const ssh_kex *const gssk5_sha1_kex_list[] = {
     &ssh_gssk5_diffiehellman_gex_sha1,
     &ssh_gssk5_diffiehellman_group14_sha1,
     &ssh_gssk5_diffiehellman_group1_sha1
 };
 
-const struct ssh_kexes ssh_gssk5_sha1_kex = {
-    sizeof(gssk5_sha1_kex_list) / sizeof(*gssk5_sha1_kex_list),
-    gssk5_sha1_kex_list
+const ssh_kexes ssh_gssk5_sha1_kex = {
+    lenof(gssk5_sha1_kex_list), gssk5_sha1_kex_list
 };
 
 /*
  * Common DH initialisation.
  */
-static void dh_init(struct dh_ctx *ctx)
+static void dh_init(dh_ctx *ctx)
 {
     ctx->q = mp_rshift_fixed(ctx->p, 1);
     ctx->x = ctx->e = NULL;
 }
 
-bool dh_is_gex(const struct ssh_kex *kex)
+bool dh_is_gex(const ssh_kex *kex)
 {
     const struct dh_extra *extra = (const struct dh_extra *)kex->extra;
     return extra->gex;
@@ -151,11 +143,11 @@ bool dh_is_gex(const struct ssh_kex *kex)
 /*
  * Initialise DH for a standard group.
  */
-struct dh_ctx *dh_setup_group(const struct ssh_kex *kex)
+dh_ctx *dh_setup_group(const ssh_kex *kex)
 {
     const struct dh_extra *extra = (const struct dh_extra *)kex->extra;
     pinitassert(!extra->gex);
-    struct dh_ctx *ctx = snew(struct dh_ctx);
+    dh_ctx *ctx = snew(dh_ctx);
     extra->construct(ctx);
     dh_init(ctx);
     return ctx;
@@ -164,9 +156,9 @@ struct dh_ctx *dh_setup_group(const struct ssh_kex *kex)
 /*
  * Initialise DH for a server-supplied group.
  */
-struct dh_ctx *dh_setup_gex(mp_int *pval, mp_int *gval)
+dh_ctx *dh_setup_gex(mp_int *pval, mp_int *gval)
 {
-    struct dh_ctx *ctx = snew(struct dh_ctx);
+    dh_ctx *ctx = snew(dh_ctx);
     ctx->p = mp_copy(pval);
     ctx->g = mp_copy(gval);
     dh_init(ctx);
@@ -176,7 +168,7 @@ struct dh_ctx *dh_setup_gex(mp_int *pval, mp_int *gval)
 /*
  * Return size of DH modulus p.
  */
-int dh_modulus_bit_size(const struct dh_ctx *ctx)
+int dh_modulus_bit_size(const dh_ctx *ctx)
 {
     return mp_get_nbits(ctx->p);
 }
@@ -184,7 +176,7 @@ int dh_modulus_bit_size(const struct dh_ctx *ctx)
 /*
  * Clean up and free a context.
  */
-void dh_cleanup(struct dh_ctx *ctx)
+void dh_cleanup(dh_ctx *ctx)
 {
     if (ctx->x)
         mp_free(ctx->x);
@@ -214,7 +206,7 @@ void dh_cleanup(struct dh_ctx *ctx)
  * Advances in Cryptology: Proceedings of Eurocrypt '96
  * Springer-Verlag, May 1996.
  */
-mp_int *dh_create_e(struct dh_ctx *ctx, int nbits)
+mp_int *dh_create_e(dh_ctx *ctx, int nbits)
 {
     /*
      * Lower limit is just 2.
@@ -256,7 +248,7 @@ mp_int *dh_create_e(struct dh_ctx *ctx, int nbits)
  * they lead to obviously weak keys that even a passive eavesdropper
  * can figure out.)
  */
-const char *dh_validate_f(struct dh_ctx *ctx, mp_int *f)
+const char *dh_validate_f(dh_ctx *ctx, mp_int *f)
 {
     if (!mp_hs_integer(f, 2)) {
         return "f value received is too small";
@@ -276,7 +268,7 @@ const char *dh_validate_f(struct dh_ctx *ctx, mp_int *f)
 /*
  * DH stage 2: given a number f, compute K = f^x mod p.
  */
-mp_int *dh_find_K(struct dh_ctx *ctx, mp_int *f)
+mp_int *dh_find_K(dh_ctx *ctx, mp_int *f)
 {
     return mp_modpow(f, ctx->x, ctx->p);
 }

+ 2 - 3
source/putty/sshdss.c

@@ -428,14 +428,13 @@ mp_int *dss_gen_k(const char *id_string, mp_int *modulus,
     } // WINSCP
 }
 
-static void dss_sign(ssh_key *key, const void *data, int datalen,
-                     unsigned flags, BinarySink *bs)
+static void dss_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs)
 {
     struct dss_key *dss = container_of(key, struct dss_key, sshk);
     unsigned char digest[20];
     int i;
 
-    SHA_Simple(data, datalen, digest);
+    SHA_Simple(data.ptr, data.len, digest);
 
     { // WINSCP
     mp_int *k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x,

+ 20 - 24
source/putty/sshecc.c

@@ -327,7 +327,7 @@ static struct ec_curve *ec_ed25519(void)
 
 struct ecsign_extra {
     struct ec_curve *(*curve)(void);
-    const struct ssh_hashalg *hash;
+    const ssh_hashalg *hash;
 
     /* These fields are used by the OpenSSH PEM format importer/exporter */
     const unsigned char *oid;
@@ -896,8 +896,8 @@ static void eddsa_openssh_blob(ssh_key *key, BinarySink *bs)
     /* Encode the private key as the concatenation of the
      * little-endian key integer and the public key again */
     put_uint32(bs, priv.len + pub.len);
-    put_data(bs, priv.ptr, priv.len);
-    put_data(bs, pub.ptr, pub.len);
+    put_datapl(bs, priv);
+    put_datapl(bs, pub);
 
     strbuf_free(pub_sb);
     strbuf_free(priv_sb);
@@ -956,7 +956,7 @@ static mp_int *ecdsa_signing_exponent_from_data(
     /* Hash the data being signed. */
     unsigned char hash[MAX_HASH_LEN];
     ssh_hash *h = ssh_hash_new(extra->hash);
-    put_data(h, data.ptr, data.len);
+    put_datapl(h, data);
     ssh_hash_final(h, hash);
 
     /*
@@ -1071,9 +1071,9 @@ static mp_int *eddsa_signing_exponent_from_data(
     /* Hash (r || public key || message) */
     unsigned char hash[MAX_HASH_LEN];
     ssh_hash *h = ssh_hash_new(extra->hash);
-    put_data(h, r_encoded.ptr, r_encoded.len);
+    put_datapl(h, r_encoded);
     put_epoint(h, ek->publicKey, ek->curve, true); /* omit string header */
-    put_data(h, data.ptr, data.len);
+    put_datapl(h, data);
     ssh_hash_final(h, hash);
 
     /* Convert to an integer */
@@ -1145,7 +1145,7 @@ static bool eddsa_verify(ssh_key *key, ptrlen sig, ptrlen data)
     } // WINSCP
 }
 
-static void ecdsa_sign(ssh_key *key, const void *data, int datalen,
+static void ecdsa_sign(ssh_key *key, ptrlen data,
                        unsigned flags, BinarySink *bs)
 {
     struct ecdsa_key *ek = container_of(key, struct ecdsa_key, sshk);
@@ -1154,15 +1154,14 @@ static void ecdsa_sign(ssh_key *key, const void *data, int datalen,
     assert(ek->privateKey);
 
     { // WINSCP
-    mp_int *z = ecdsa_signing_exponent_from_data(
-        ek->curve, extra, make_ptrlen(data, datalen));
+    mp_int *z = ecdsa_signing_exponent_from_data(ek->curve, extra, data);
 
     /* Generate k between 1 and curve->n, using the same deterministic
      * k generation system we use for conventional DSA. */
     mp_int *k;
     {
         unsigned char digest[20];
-        SHA_Simple(data, datalen, digest);
+        SHA_Simple(data.ptr, data.len, digest);
         k = dss_gen_k(
             "ECDSA deterministic k generator", ek->curve->w.G_order,
             ek->privateKey, digest, sizeof(digest));
@@ -1213,7 +1212,7 @@ static void ecdsa_sign(ssh_key *key, const void *data, int datalen,
     } // WINSCP
 }
 
-static void eddsa_sign(ssh_key *key, const void *data, int datalen,
+static void eddsa_sign(ssh_key *key, ptrlen data,
                        unsigned flags, BinarySink *bs)
 {
     struct eddsa_key *ek = container_of(key, struct eddsa_key, sshk);
@@ -1259,7 +1258,7 @@ static void eddsa_sign(ssh_key *key, const void *data, int datalen,
     h = ssh_hash_new(extra->hash);
     put_data(h, hash + ek->curve->fieldBytes,
              extra->hash->hlen - ek->curve->fieldBytes);
-    put_data(h, data, datalen);
+    put_datapl(h, data);
     ssh_hash_final(h, hash);
     { // WINSCP
     mp_int *log_r_unreduced = mp_from_bytes_le(
@@ -1283,7 +1282,7 @@ static void eddsa_sign(ssh_key *key, const void *data, int datalen,
      */
     { // WINSCP
     mp_int *H = eddsa_signing_exponent_from_data(
-        ek, extra, ptrlen_from_strbuf(r_enc), make_ptrlen(data, datalen));
+        ek, extra, ptrlen_from_strbuf(r_enc), data);
 
     /* And then s = (log(r) + H*a) mod order(G). */
     mp_int *Ha = mp_modmul(H, a, ek->curve->e.G_order);
@@ -1445,7 +1444,7 @@ struct ecdh_key {
     };
 };
 
-const char *ssh_ecdhkex_curve_textname(const struct ssh_kex *kex)
+const char *ssh_ecdhkex_curve_textname(const ssh_kex *kex)
 {
     const struct eckex_extra *extra = (const struct eckex_extra *)kex->extra;
     struct ec_curve *curve = extra->curve();
@@ -1477,7 +1476,7 @@ static void ssh_ecdhkex_m_setup(ecdh_key *dh)
     dh->m_public = ecc_montgomery_multiply(dh->curve->m.G, dh->private);
 }
 
-ecdh_key *ssh_ecdhkex_newkey(const struct ssh_kex *kex)
+ecdh_key *ssh_ecdhkex_newkey(const ssh_kex *kex)
 {
     const struct eckex_extra *extra = (const struct eckex_extra *)kex->extra;
     const struct ec_curve *curve = extra->curve();
@@ -1600,7 +1599,7 @@ static const struct eckex_extra kex_extra_curve25519 = {
     ssh_ecdhkex_m_getpublic,
     ssh_ecdhkex_m_getkey,
 };
-static const struct ssh_kex ssh_ec_kex_curve25519 = {
+const ssh_kex ssh_ec_kex_curve25519 = {
     "[email protected]", NULL, KEXTYPE_ECDH,
     &ssh_sha256, &kex_extra_curve25519,
 };
@@ -1612,7 +1611,7 @@ const struct eckex_extra kex_extra_nistp256 = {
     ssh_ecdhkex_w_getpublic,
     ssh_ecdhkex_w_getkey,
 };
-static const struct ssh_kex ssh_ec_kex_nistp256 = {
+const ssh_kex ssh_ec_kex_nistp256 = {
     "ecdh-sha2-nistp256", NULL, KEXTYPE_ECDH,
     &ssh_sha256, &kex_extra_nistp256,
 };
@@ -1624,7 +1623,7 @@ const struct eckex_extra kex_extra_nistp384 = {
     ssh_ecdhkex_w_getpublic,
     ssh_ecdhkex_w_getkey,
 };
-static const struct ssh_kex ssh_ec_kex_nistp384 = {
+const ssh_kex ssh_ec_kex_nistp384 = {
     "ecdh-sha2-nistp384", NULL, KEXTYPE_ECDH,
     &ssh_sha384, &kex_extra_nistp384,
 };
@@ -1636,22 +1635,19 @@ const struct eckex_extra kex_extra_nistp521 = {
     ssh_ecdhkex_w_getpublic,
     ssh_ecdhkex_w_getkey,
 };
-static const struct ssh_kex ssh_ec_kex_nistp521 = {
+const ssh_kex ssh_ec_kex_nistp521 = {
     "ecdh-sha2-nistp521", NULL, KEXTYPE_ECDH,
     &ssh_sha512, &kex_extra_nistp521,
 };
 
-static const struct ssh_kex *const ec_kex_list[] = {
+static const ssh_kex *const ec_kex_list[] = {
     &ssh_ec_kex_curve25519,
     &ssh_ec_kex_nistp256,
     &ssh_ec_kex_nistp384,
     &ssh_ec_kex_nistp521,
 };
 
-const struct ssh_kexes ssh_ecdh_kex = {
-    sizeof(ec_kex_list) / sizeof(*ec_kex_list),
-    ec_kex_list
-};
+const ssh_kexes ssh_ecdh_kex = { lenof(ec_kex_list), ec_kex_list };
 
 /* ----------------------------------------------------------------------
  * Helper functions for finding key algorithms and returning auxiliary

+ 55 - 4
source/putty/sshmd5.c

@@ -214,6 +214,57 @@ void MD5Simple(void const *p, unsigned len, unsigned char output[16])
     smemclr(&s, sizeof(s));
 }
 
+/* ----------------------------------------------------------------------
+ * Thin abstraction for things where hashes are pluggable.
+ */
+
+struct md5_hash {
+    struct MD5Context state;
+    ssh_hash hash;
+};
+
+static ssh_hash *md5_new(const ssh_hashalg *alg)
+{
+    struct md5_hash *h = snew(struct md5_hash);
+    MD5Init(&h->state);
+    h->hash.vt = alg;
+    BinarySink_DELEGATE_INIT(&h->hash, &h->state);
+    return &h->hash;
+}
+
+static ssh_hash *md5_copy(ssh_hash *hashold)
+{
+    struct md5_hash *hold, *hnew;
+    ssh_hash *hashnew = md5_new(hashold->vt);
+
+    hold = container_of(hashold, struct md5_hash, hash);
+    hnew = container_of(hashnew, struct md5_hash, hash);
+
+    hnew->state = hold->state;
+    BinarySink_COPIED(&hnew->state);
+
+    return hashnew;
+}
+
+static void md5_free(ssh_hash *hash)
+{
+    struct md5_hash *h = container_of(hash, struct md5_hash, hash);
+
+    smemclr(h, sizeof(*h));
+    sfree(h);
+}
+
+static void md5_final(ssh_hash *hash, unsigned char *output)
+{
+    struct md5_hash *h = container_of(hash, struct md5_hash, hash);
+    MD5Final(output, &h->state);
+    md5_free(hash);
+}
+
+const ssh_hashalg ssh_md5 = {
+    md5_new, md5_copy, md5_final, md5_free, 16, "MD5"
+};
+
 /* ----------------------------------------------------------------------
  * The above is the MD5 algorithm itself. Now we implement the
  * HMAC wrapper on it.
@@ -234,7 +285,7 @@ struct hmacmd5_context *hmacmd5_make_context(void)
     return ctx;
 }
 
-static ssh2_mac *hmacmd5_ssh2_new(const struct ssh2_macalg *alg,
+static ssh2_mac *hmacmd5_ssh2_new(const ssh2_macalg *alg,
                                   ssh2_cipher *cipher)
 {
     struct hmacmd5_context *ctx = hmacmd5_make_context();
@@ -276,11 +327,11 @@ void hmacmd5_key(struct hmacmd5_context *ctx, void const *keyv, int len)
     smemclr(foo, 64);		       /* burn the evidence */
 }
 
-static void hmacmd5_ssh2_setkey(ssh2_mac *mac, const void *key)
+static void hmacmd5_ssh2_setkey(ssh2_mac *mac, ptrlen key)
 {
     struct hmacmd5_context *ctx =
         container_of(mac, struct hmacmd5_context, mac);
-    hmacmd5_key(ctx, key, ctx->mac.vt->keylen);
+    hmacmd5_key(ctx, key.ptr, key.len);
 }
 
 static void hmacmd5_start(ssh2_mac *mac)
@@ -317,7 +368,7 @@ void hmacmd5_do_hmac(struct hmacmd5_context *ctx,
     ssh2_mac_genresult(&ctx->mac, hmac);
 }
 
-const struct ssh2_macalg ssh_hmac_md5 = {
+const ssh2_macalg ssh_hmac_md5 = {
     hmacmd5_ssh2_new, hmacmd5_ssh2_free, hmacmd5_ssh2_setkey,
     hmacmd5_start, hmacmd5_genresult,
     "hmac-md5", "[email protected]",

+ 1 - 1
source/putty/sshppl.h

@@ -154,7 +154,7 @@ bool ssh1_common_get_specials(PacketProtocolLayer *, add_special_fn_t, void *);
 bool ssh1_common_filter_queue(PacketProtocolLayer *ppl);
 void ssh1_compute_session_id(
     unsigned char *session_id, const unsigned char *cookie,
-    struct RSAKey *hostkey, struct RSAKey *servkey);
+    RSAKey *hostkey, RSAKey *servkey);
 
 /* Method used by the SSH server */
 void ssh2_transport_provide_hostkeys(PacketProtocolLayer *ssh2_transport_ptr,

+ 14 - 15
source/putty/sshpubk.c

@@ -24,7 +24,7 @@
 
 static int key_type_fp(FILE *fp);
 
-static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, bool pub_only,
+static int rsa_ssh1_load_main(FILE * fp, RSAKey *key, bool pub_only,
                               char **commentptr, const char *passphrase,
                               const char **error)
 {
@@ -141,7 +141,7 @@ static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, bool pub_only,
     return ret;
 }
 
-int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key,
+int rsa_ssh1_loadkey(const Filename *filename, RSAKey *key,
                      const char *passphrase, const char **errorstr)
 {
     FILE *fp;
@@ -218,7 +218,7 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs,
 {
     FILE *fp;
     char buf[64];
-    struct RSAKey key;
+    RSAKey key;
     int ret;
     const char *error = NULL;
 
@@ -310,7 +310,7 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs,
 /*
  * Save an RSA key file. Return true on success.
  */
-bool rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key,
+bool rsa_ssh1_savekey(const Filename *filename, RSAKey *key,
                       char *passphrase)
 {
     strbuf *buf = strbuf_new();
@@ -563,7 +563,7 @@ static bool read_blob(FILE *fp, int nlines, BinarySink *bs)
 /*
  * Magic error return value for when the passphrase is wrong.
  */
-struct ssh2_userkey ssh2_wrong_passphrase = { NULL, NULL };
+ssh2_userkey ssh2_wrong_passphrase = { NULL, NULL };
 
 const ssh_keyalg *find_pubkey_alg_len(ptrlen name)
 {
@@ -588,14 +588,13 @@ const ssh_keyalg *find_pubkey_alg(const char *name)
     return find_pubkey_alg_len(ptrlen_from_asciz(name));
 }
 
-struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
-				       const char *passphrase,
-                                       const char **errorstr)
+ssh2_userkey *ssh2_load_userkey(
+    const Filename *filename, const char *passphrase, const char **errorstr)
 {
     FILE *fp;
     char header[40], *b, *encryption, *comment, *mac;
     const ssh_keyalg *alg;
-    struct ssh2_userkey *ret;
+    ssh2_userkey *ret;
     int cipher, cipherblk;
     strbuf *public_blob, *private_blob;
     int i;
@@ -797,7 +796,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
     /*
      * Create and return the key.
      */
-    ret = snew(struct ssh2_userkey);
+    ret = snew(ssh2_userkey);
     ret->comment = comment;
     ret->key = ssh_key_new_priv(
         alg, ptrlen_from_strbuf(public_blob),
@@ -1265,8 +1264,8 @@ void base64_encode_buf(const unsigned char *data, int datalen, unsigned char *ou
     *out = 0;
 }
 
-bool ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
-                       char *passphrase)
+bool ssh2_save_userkey(
+    const Filename *filename, ssh2_userkey *key, char *passphrase)
 {
     FILE *fp;
     strbuf *pub_blob, *priv_blob;
@@ -1386,7 +1385,7 @@ bool ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
 /* ----------------------------------------------------------------------
  * Output public keys.
  */
-char *ssh1_pubkey_str(struct RSAKey *key)
+char *ssh1_pubkey_str(RSAKey *key)
 {
     char *buffer;
     char *dec1, *dec2;
@@ -1401,7 +1400,7 @@ char *ssh1_pubkey_str(struct RSAKey *key)
     return buffer;
 }
 
-void ssh1_write_pubkey(FILE *fp, struct RSAKey *key)
+void ssh1_write_pubkey(FILE *fp, RSAKey *key)
 {
     char *buffer = ssh1_pubkey_str(key);
     fprintf(fp, "%s\n", buffer);
@@ -1448,7 +1447,7 @@ static char *ssh2_pubkey_openssh_str_internal(const char *comment,
     return buffer;
 }
 
-char *ssh2_pubkey_openssh_str(struct ssh2_userkey *key)
+char *ssh2_pubkey_openssh_str(ssh2_userkey *key)
 {
     strbuf *blob;
     char *ret;

+ 2 - 2
source/putty/sshrand.c

@@ -140,7 +140,7 @@ static void random_stir(void)
 	     * digest.
 	     */
 
-	    for (k = 0; k < sizeof(digest) / sizeof(*digest); k++)
+	    for (k = 0; k < lenof(digest); k++)
 		digest[k] ^= ((uint32_t *) (pool.pool + j))[k];
 
 	    /*
@@ -153,7 +153,7 @@ static void random_stir(void)
 	     * Stick the result back into the pool.
 	     */
 
-	    for (k = 0; k < sizeof(digest) / sizeof(*digest); k++)
+	    for (k = 0; k < lenof(digest); k++)
 		((uint32_t *) (pool.pool + j))[k] = digest[k];
 	}
 

+ 66 - 59
source/putty/sshrsa.c

@@ -12,7 +12,7 @@
 #include "misc.h"
 
 void BinarySource_get_rsa_ssh1_pub(
-    BinarySource *src, struct RSAKey *rsa, RsaSsh1Order order)
+    BinarySource *src, RSAKey *rsa, RsaSsh1Order order)
 {
     unsigned bits;
     mp_int *e, *m;
@@ -38,12 +38,12 @@ void BinarySource_get_rsa_ssh1_pub(
 }
 
 void BinarySource_get_rsa_ssh1_priv(
-    BinarySource *src, struct RSAKey *rsa)
+    BinarySource *src, RSAKey *rsa)
 {
     rsa->private_exponent = get_mp_ssh1(src);
 }
 
-bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key)
+bool rsa_ssh1_encrypt(unsigned char *data, int length, RSAKey *key)
 {
     mp_int *b1, *b2;
     int i;
@@ -163,18 +163,18 @@ mp_int *crt_modpow(mp_int *base, mp_int *exp, mp_int *mod,
  * Wrapper on crt_modpow that looks up all the right values from an
  * RSAKey.
  */
-static mp_int *rsa_privkey_op(mp_int *input, struct RSAKey *key)
+static mp_int *rsa_privkey_op(mp_int *input, RSAKey *key)
 {
     return crt_modpow(input, key->private_exponent,
                       key->modulus, key->p, key->q, key->iqmp);
 }
 
-mp_int *rsa_ssh1_decrypt(mp_int *input, struct RSAKey *key)
+mp_int *rsa_ssh1_decrypt(mp_int *input, RSAKey *key)
 {
     return rsa_privkey_op(input, key);
 }
 
-bool rsa_ssh1_decrypt_pkcs1(mp_int *input, struct RSAKey *key,
+bool rsa_ssh1_decrypt_pkcs1(mp_int *input, RSAKey *key,
                             strbuf *outbuf)
 {
     strbuf *data = strbuf_new();
@@ -225,7 +225,7 @@ static void append_hex_to_strbuf(strbuf *sb, mp_int *x)
     } // WINSCP
 }
 
-char *rsastr_fmt(struct RSAKey *key)
+char *rsastr_fmt(RSAKey *key)
 {
     strbuf *sb = strbuf_new();
 
@@ -239,16 +239,26 @@ char *rsastr_fmt(struct RSAKey *key)
  * Generate a fingerprint string for the key. Compatible with the
  * OpenSSH fingerprint code.
  */
-char *rsa_ssh1_fingerprint(struct RSAKey *key)
+char *rsa_ssh1_fingerprint(RSAKey *key)
 {
     struct MD5Context md5c;
     unsigned char digest[16];
     strbuf *out;
     int i;
 
+    /*
+     * The hash preimage for SSH-1 key fingerprinting consists of the
+     * modulus and exponent _without_ any preceding length field -
+     * just the minimum number of bytes to represent each integer,
+     * stored big-endian, concatenated with no marker at the division
+     * between them.
+     */
+
     MD5Init(&md5c);
-    put_mp_ssh1(&md5c, key->modulus);
-    put_mp_ssh1(&md5c, key->exponent);
+    for (size_t i = (mp_get_nbits(key->modulus) + 7) / 8; i-- > 0 ;)
+        put_byte(&md5c, mp_get_byte(key->modulus, i));
+    for (size_t i = (mp_get_nbits(key->exponent) + 7) / 8; i-- > 0 ;)
+        put_byte(&md5c, mp_get_byte(key->exponent, i));
     MD5Final(digest, &md5c);
 
     out = strbuf_new();
@@ -265,7 +275,7 @@ char *rsa_ssh1_fingerprint(struct RSAKey *key)
  * data. We also check the private data itself: we ensure that p >
  * q and that iqmp really is the inverse of q mod p.
  */
-bool rsa_verify(struct RSAKey *key)
+bool rsa_verify(RSAKey *key)
 {
     mp_int *n, *ed, *pm1, *qm1;
     unsigned ok = 1;
@@ -312,7 +322,7 @@ bool rsa_verify(struct RSAKey *key)
     return ok;
 }
 
-void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
+void rsa_ssh1_public_blob(BinarySink *bs, RSAKey *key,
                           RsaSsh1Order order)
 {
     put_uint32(bs, mp_get_nbits(key->modulus));
@@ -326,11 +336,11 @@ void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
 }
 
 /* Given an SSH-1 public key blob, determine its length. */
-int rsa_ssh1_public_blob_len(void *data, int maxlen)
+int rsa_ssh1_public_blob_len(ptrlen data)
 {
     BinarySource src[1];
 
-    BinarySource_BARE_INIT(src, data, maxlen);
+    BinarySource_BARE_INIT(src, data.ptr, data.len);
 
     /* Expect a length word, then exponent and modulus. (It doesn't
      * even matter which order.) */
@@ -345,7 +355,7 @@ int rsa_ssh1_public_blob_len(void *data, int maxlen)
     return src->pos;
 }
 
-void freersapriv(struct RSAKey *key)
+void freersapriv(RSAKey *key)
 {
     if (key->private_exponent) {
 	mp_free(key->private_exponent);
@@ -365,7 +375,7 @@ void freersapriv(struct RSAKey *key)
     }
 }
 
-void freersakey(struct RSAKey *key)
+void freersakey(RSAKey *key)
 {
     freersapriv(key);
     if (key->modulus) {
@@ -391,13 +401,13 @@ static void rsa2_freekey(ssh_key *key);   /* forward reference */
 static ssh_key *rsa2_new_pub(const ssh_keyalg *self, ptrlen data)
 {
     BinarySource src[1];
-    struct RSAKey *rsa;
+    RSAKey *rsa;
 
     BinarySource_BARE_INIT(src, data.ptr, data.len);
     if (!ptrlen_eq_string(get_string(src), "ssh-rsa"))
 	return NULL;
 
-    rsa = snew(struct RSAKey);
+    rsa = snew(RSAKey);
     rsa->sshk.vt = &ssh_rsa;
     rsa->exponent = get_mp_ssh2(src);
     rsa->modulus = get_mp_ssh2(src);
@@ -415,20 +425,20 @@ static ssh_key *rsa2_new_pub(const ssh_keyalg *self, ptrlen data)
 
 static void rsa2_freekey(ssh_key *key)
 {
-    struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
+    RSAKey *rsa = container_of(key, RSAKey, sshk);
     freersakey(rsa);
     sfree(rsa);
 }
 
 static char *rsa2_cache_str(ssh_key *key)
 {
-    struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
+    RSAKey *rsa = container_of(key, RSAKey, sshk);
     return rsastr_fmt(rsa);
 }
 
 static void rsa2_public_blob(ssh_key *key, BinarySink *bs)
 {
-    struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
+    RSAKey *rsa = container_of(key, RSAKey, sshk);
 
     put_stringz(bs, "ssh-rsa");
     put_mp_ssh2(bs, rsa->exponent);
@@ -437,7 +447,7 @@ static void rsa2_public_blob(ssh_key *key, BinarySink *bs)
 
 static void rsa2_private_blob(ssh_key *key, BinarySink *bs)
 {
-    struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
+    RSAKey *rsa = container_of(key, RSAKey, sshk);
 
     put_mp_ssh2(bs, rsa->private_exponent);
     put_mp_ssh2(bs, rsa->p);
@@ -450,13 +460,13 @@ static ssh_key *rsa2_new_priv(const ssh_keyalg *self,
 {
     BinarySource src[1];
     ssh_key *sshk;
-    struct RSAKey *rsa;
+    RSAKey *rsa;
 
     sshk = rsa2_new_pub(self, pub);
     if (!sshk)
         return NULL;
 
-    rsa = container_of(sshk, struct RSAKey, sshk);
+    rsa = container_of(sshk, RSAKey, sshk);
     BinarySource_BARE_INIT(src, priv.ptr, priv.len);
     rsa->private_exponent = get_mp_ssh2(src);
     rsa->p = get_mp_ssh2(src);
@@ -474,9 +484,9 @@ static ssh_key *rsa2_new_priv(const ssh_keyalg *self,
 static ssh_key *rsa2_new_priv_openssh(const ssh_keyalg *self,
                                       BinarySource *src)
 {
-    struct RSAKey *rsa;
+    RSAKey *rsa;
 
-    rsa = snew(struct RSAKey);
+    rsa = snew(RSAKey);
     rsa->sshk.vt = &ssh_rsa;
     rsa->comment = NULL;
 
@@ -497,7 +507,7 @@ static ssh_key *rsa2_new_priv_openssh(const ssh_keyalg *self,
 
 static void rsa2_openssh_blob(ssh_key *key, BinarySink *bs)
 {
-    struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
+    RSAKey *rsa = container_of(key, RSAKey, sshk);
 
     put_mp_ssh2(bs, rsa->modulus);
     put_mp_ssh2(bs, rsa->exponent);
@@ -510,14 +520,14 @@ static void rsa2_openssh_blob(ssh_key *key, BinarySink *bs)
 static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
 {
     ssh_key *sshk;
-    struct RSAKey *rsa;
+    RSAKey *rsa;
     int ret;
 
     sshk = rsa2_new_pub(self, pub);
     if (!sshk)
         return -1;
 
-    rsa = container_of(sshk, struct RSAKey, sshk);
+    rsa = container_of(sshk, RSAKey, sshk);
     ret = mp_get_nbits(rsa->modulus);
     rsa2_freekey(&rsa->sshk);
 
@@ -572,7 +582,7 @@ static const unsigned char sha512_asn1_prefix[] = {
 #define SHA1_ASN1_PREFIX_LEN sizeof(sha1_asn1_prefix)
 
 static unsigned char *rsa_pkcs1_signature_string(
-    size_t nbytes, const struct ssh_hashalg *halg, ptrlen data)
+    size_t nbytes, const ssh_hashalg *halg, ptrlen data)
 {
     const unsigned char *asn1_prefix;
     unsigned asn1_prefix_size;
@@ -605,7 +615,7 @@ static unsigned char *rsa_pkcs1_signature_string(
 
     { // WINSCP
     ssh_hash *h = ssh_hash_new(halg);
-    put_data(h, data.ptr, data.len);
+    put_datapl(h, data);
     ssh_hash_final(h, bytes + 2 + padding + asn1_prefix_size);
     } // WINSCP
 
@@ -615,7 +625,7 @@ static unsigned char *rsa_pkcs1_signature_string(
 
 static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
 {
-    struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
+    RSAKey *rsa = container_of(key, RSAKey, sshk);
     BinarySource src[1];
     ptrlen type, in_pl;
     mp_int *in, *out;
@@ -657,14 +667,14 @@ static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
     } // WINSCP
 }
 
-static void rsa2_sign(ssh_key *key, const void *data, int datalen,
+static void rsa2_sign(ssh_key *key, ptrlen data,
                       unsigned flags, BinarySink *bs)
 {
-    struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
+    RSAKey *rsa = container_of(key, RSAKey, sshk);
     unsigned char *bytes;
     size_t nbytes;
     mp_int *in, *out;
-    const struct ssh_hashalg *halg;
+    const ssh_hashalg *halg;
     const char *sign_alg_name;
 
     if (flags & SSH_AGENT_RSA_SHA2_256) {
@@ -680,8 +690,7 @@ static void rsa2_sign(ssh_key *key, const void *data, int datalen,
 
     nbytes = (mp_get_nbits(rsa->modulus) + 7) / 8;
 
-    bytes = rsa_pkcs1_signature_string(
-        nbytes, halg, make_ptrlen(data, datalen));
+    bytes = rsa_pkcs1_signature_string(nbytes, halg, data);
     in = mp_from_bytes_be(make_ptrlen(bytes, nbytes));
     smemclr(bytes, nbytes);
     sfree(bytes);
@@ -723,25 +732,25 @@ const ssh_keyalg ssh_rsa = {
     SSH_AGENT_RSA_SHA2_256 | SSH_AGENT_RSA_SHA2_512,
 };
 
-struct RSAKey *ssh_rsakex_newkey(const void *data, int len)
+RSAKey *ssh_rsakex_newkey(ptrlen data)
 {
-    ssh_key *sshk = rsa2_new_pub(&ssh_rsa, make_ptrlen(data, len));
+    ssh_key *sshk = rsa2_new_pub(&ssh_rsa, data);
     if (!sshk)
         return NULL;
-    return container_of(sshk, struct RSAKey, sshk);
+    return container_of(sshk, RSAKey, sshk);
 }
 
-void ssh_rsakex_freekey(struct RSAKey *key)
+void ssh_rsakex_freekey(RSAKey *key)
 {
     rsa2_freekey(&key->sshk);
 }
 
-int ssh_rsakex_klen(struct RSAKey *rsa)
+int ssh_rsakex_klen(RSAKey *rsa)
 {
     return mp_get_nbits(rsa->modulus);
 }
 
-static void oaep_mask(const struct ssh_hashalg *h, void *seed, int seedlen,
+static void oaep_mask(const ssh_hashalg *h, void *seed, int seedlen,
 		      void *vdata, int datalen)
 {
     unsigned char *data = (unsigned char *)vdata;
@@ -767,9 +776,7 @@ static void oaep_mask(const struct ssh_hashalg *h, void *seed, int seedlen,
     }
 }
 
-void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
-                        unsigned char *in, int inlen,
-                        unsigned char *out, int outlen, struct RSAKey *rsa)
+strbuf *ssh_rsakex_encrypt(RSAKey *rsa, const ssh_hashalg *h, ptrlen in)
 {
     mp_int *b1, *b2;
     int k, i;
@@ -807,10 +814,12 @@ void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
     k = (7 + mp_get_nbits(rsa->modulus)) / 8;
 
     /* The length of the input data must be at most k - 2hLen - 2. */
-    assert(inlen > 0 && inlen <= k - 2*HLEN - 2);
+    assert(in.len > 0 && in.len <= k - 2*HLEN - 2);
 
     /* The length of the output data wants to be precisely k. */
-    assert(outlen == k);
+    strbuf *toret = strbuf_new();
+    int outlen = k;
+    unsigned char *out = strbuf_append(toret, outlen);
 
     /*
      * Now perform EME-OAEP encoding. First set up all the unmasked
@@ -830,8 +839,8 @@ void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
     /* A bunch of zero octets */
     memset(out + 2*HLEN + 1, 0, outlen - (2*HLEN + 1));
     /* A single 1 octet, followed by the input message data. */
-    out[outlen - inlen - 1] = 1;
-    memcpy(out + outlen - inlen, in, inlen);
+    out[outlen - in.len - 1] = 1;
+    memcpy(out + outlen - in.len, in.ptr, in.len);
 
     /*
      * Now use the seed data to mask the block DB.
@@ -859,10 +868,11 @@ void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
     /*
      * And we're done.
      */
+    return toret;
 }
 
-mp_int *ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext,
-                              struct RSAKey *rsa)
+mp_int *ssh_rsakex_decrypt(
+    RSAKey *rsa, const ssh_hashalg *h, ptrlen ciphertext)
 {
     mp_int *b1, *b2;
     int outlen, i;
@@ -935,22 +945,19 @@ mp_int *ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext,
 static const struct ssh_rsa_kex_extra ssh_rsa_kex_extra_sha1 = { 1024 };
 static const struct ssh_rsa_kex_extra ssh_rsa_kex_extra_sha256 = { 2048 };
 
-static const struct ssh_kex ssh_rsa_kex_sha1 = {
+static const ssh_kex ssh_rsa_kex_sha1 = {
     "rsa1024-sha1", NULL, KEXTYPE_RSA,
     &ssh_sha1, &ssh_rsa_kex_extra_sha1,
 };
 
-static const struct ssh_kex ssh_rsa_kex_sha256 = {
+static const ssh_kex ssh_rsa_kex_sha256 = {
     "rsa2048-sha256", NULL, KEXTYPE_RSA,
     &ssh_sha256, &ssh_rsa_kex_extra_sha256,
 };
 
-static const struct ssh_kex *const rsa_kex_list[] = {
+static const ssh_kex *const rsa_kex_list[] = {
     &ssh_rsa_kex_sha256,
     &ssh_rsa_kex_sha1
 };
 
-const struct ssh_kexes ssh_rsa_kex = {
-    sizeof(rsa_kex_list) / sizeof(*rsa_kex_list),
-    rsa_kex_list
-};
+const ssh_kexes ssh_rsa_kex = { lenof(rsa_kex_list), rsa_kex_list };

+ 6 - 56
source/putty/sshsh256.c

@@ -212,7 +212,7 @@ struct sha256_hash {
     ssh_hash hash;
 };
 
-static ssh_hash *sha256_new(const struct ssh_hashalg *alg)
+static ssh_hash *sha256_new(const ssh_hashalg *alg)
 {
     struct sha256_hash *h = snew(struct sha256_hash);
     SHA256_Init(&h->state);
@@ -250,7 +250,7 @@ static void sha256_final(ssh_hash *hash, unsigned char *output)
     sha256_free(hash);
 }
 
-const struct ssh_hashalg ssh_sha256 = {
+const ssh_hashalg ssh_sha256 = {
     sha256_new, sha256_copy, sha256_final, sha256_free, 32, "SHA-256"
 };
 
@@ -265,7 +265,7 @@ struct hmacsha256 {
 };
 
 static ssh2_mac *hmacsha256_new(
-    const struct ssh2_macalg *alg, ssh2_cipher *cipher)
+    const ssh2_macalg *alg, ssh2_cipher *cipher)
 {
     struct hmacsha256 *ctx = snew(struct hmacsha256);
     ctx->mac.vt = alg;
@@ -301,10 +301,10 @@ static void sha256_key_internal(struct hmacsha256 *ctx,
     smemclr(foo, 64);		       /* burn the evidence */
 }
 
-static void hmacsha256_key(ssh2_mac *mac, const void *key)
+static void hmacsha256_key(ssh2_mac *mac, ptrlen key)
 {
     struct hmacsha256 *ctx = container_of(mac, struct hmacsha256, mac);
-    sha256_key_internal(ctx, key, ctx->mac.vt->keylen);
+    sha256_key_internal(ctx, key.ptr, key.len);
 }
 
 static void hmacsha256_start(ssh2_mac *mac)
@@ -330,7 +330,7 @@ static void hmacsha256_genresult(ssh2_mac *mac, unsigned char *hmac)
     SHA256_Final(&s, hmac);
 }
 
-const struct ssh2_macalg ssh_hmac_sha256 = {
+const ssh2_macalg ssh_hmac_sha256 = {
     hmacsha256_new, hmacsha256_free, hmacsha256_key,
     hmacsha256_start, hmacsha256_genresult,
     "hmac-sha2-256", "[email protected]",
@@ -339,56 +339,6 @@ const struct ssh2_macalg ssh_hmac_sha256 = {
 };
 #endif // !WINSCP_VS
 
-#ifdef TEST
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-int main(void) {
-    unsigned char digest[32];
-    int i, j, errors;
-
-    struct {
-	const char *teststring;
-	unsigned char digest[32];
-    } tests[] = {
-	{ "abc", {
-	    0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
-	    0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
-	    0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
-	    0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad,
-	} },
-	{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", {
-	    0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
-	    0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
-	    0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
-	    0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1,
-	} },
-    };
-
-    errors = 0;
-
-    for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
-	SHA256_Simple(tests[i].teststring,
-		      strlen(tests[i].teststring), digest);
-	for (j = 0; j < 32; j++) {
-	    if (digest[j] != tests[i].digest[j]) {
-		fprintf(stderr,
-			"\"%s\" digest byte %d should be 0x%02x, is 0x%02x\n",
-			tests[i].teststring, j, tests[i].digest[j], digest[j]);
-		errors++;
-	    }
-	}
-    }
-
-    printf("%d errors\n", errors);
-
-    return 0;
-}
-
-#endif
-
 #ifdef COMPILER_SUPPORTS_SHA_NI
 
 #if defined _MSC_VER && defined _M_AMD64

+ 4 - 84
source/putty/sshsh512.c

@@ -296,7 +296,7 @@ struct sha512_hash {
     ssh_hash hash;
 };
 
-static ssh_hash *sha512_new(const struct ssh_hashalg *alg)
+static ssh_hash *sha512_new(const ssh_hashalg *alg)
 {
     struct sha512_hash *h = snew(struct sha512_hash);
     SHA512_Init(&h->state);
@@ -334,11 +334,11 @@ static void sha512_final(ssh_hash *hash, unsigned char *output)
     sha512_free(hash);
 }
 
-const struct ssh_hashalg ssh_sha512 = {
+const ssh_hashalg ssh_sha512 = {
     sha512_new, sha512_copy, sha512_final, sha512_free, 64, "SHA-512"
 };
 
-static ssh_hash *sha384_new(const struct ssh_hashalg *alg)
+static ssh_hash *sha384_new(const ssh_hashalg *alg)
 {
     struct sha512_hash *h = snew(struct sha512_hash);
     SHA384_Init(&h->state);
@@ -354,86 +354,6 @@ static void sha384_final(ssh_hash *hash, unsigned char *output)
     sha512_free(hash);
 }
 
-const struct ssh_hashalg ssh_sha384 = {
+const ssh_hashalg ssh_sha384 = {
     sha384_new, sha512_copy, sha384_final, sha512_free, 48, "SHA-384"
 };
-
-#ifdef TEST
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-int main(void) {
-    unsigned char digest[64];
-    int i, j, errors;
-
-    struct {
-	const char *teststring;
-	unsigned char digest512[64];
-    } tests[] = {
-	{ "abc", {
-	    0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba,
-            0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
-            0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
-            0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
-            0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8,
-            0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
-            0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
-            0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f,
-	} },
-	{ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
-	"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", {
-	    0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda,
-            0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f,
-            0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1,
-            0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18,
-            0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4,
-            0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a,
-            0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54,
-            0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09,
-	} },
-	{ NULL, {
-	    0xe7, 0x18, 0x48, 0x3d, 0x0c, 0xe7, 0x69, 0x64,
-	    0x4e, 0x2e, 0x42, 0xc7, 0xbc, 0x15, 0xb4, 0x63,
-	    0x8e, 0x1f, 0x98, 0xb1, 0x3b, 0x20, 0x44, 0x28,
-	    0x56, 0x32, 0xa8, 0x03, 0xaf, 0xa9, 0x73, 0xeb,
-	    0xde, 0x0f, 0xf2, 0x44, 0x87, 0x7e, 0xa6, 0x0a,
-	    0x4c, 0xb0, 0x43, 0x2c, 0xe5, 0x77, 0xc3, 0x1b,
-	    0xeb, 0x00, 0x9c, 0x5c, 0x2c, 0x49, 0xaa, 0x2e,
-	    0x4e, 0xad, 0xb2, 0x17, 0xad, 0x8c, 0xc0, 0x9b, 
-	} },
-    };
-
-    errors = 0;
-
-    for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
-	if (tests[i].teststring) {
-	    SHA512_Simple(tests[i].teststring,
-			  strlen(tests[i].teststring), digest);
-	} else {
-	    SHA512_State s;
-	    int n;
-	    SHA512_Init(&s);
-	    for (n = 0; n < 1000000 / 40; n++)
-		put_data(&s, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 40);
-	    SHA512_Final(&s, digest);
-	}
-	for (j = 0; j < 64; j++) {
-	    if (digest[j] != tests[i].digest512[j]) {
-		fprintf(stderr,
-			"\"%s\" digest512 byte %d should be 0x%02x, is 0x%02x\n",
-			tests[i].teststring, j, tests[i].digest512[j],
-			digest[j]);
-		errors++;
-	    }
-	}
-
-    }
-
-    printf("%d errors\n", errors);
-
-    return 0;
-}
-
-#endif

+ 9 - 12
source/putty/sshsha.c

@@ -236,7 +236,7 @@ struct sha1_hash {
     ssh_hash hash;
 };
 
-static ssh_hash *sha1_new(const struct ssh_hashalg *alg)
+static ssh_hash *sha1_new(const ssh_hashalg *alg)
 {
     struct sha1_hash *h = snew(struct sha1_hash);
     SHA_Init(&h->state);
@@ -274,7 +274,7 @@ static void sha1_final(ssh_hash *hash, unsigned char *output)
     sha1_free(hash);
 }
 
-const struct ssh_hashalg ssh_sha1 = {
+const ssh_hashalg ssh_sha1 = {
     sha1_new, sha1_copy, sha1_final, sha1_free, 20, "SHA-1"
 };
 
@@ -289,7 +289,7 @@ struct hmacsha1 {
 };
 
 static ssh2_mac *hmacsha1_new(
-    const struct ssh2_macalg *alg, ssh2_cipher *cipher)
+    const ssh2_macalg *alg, ssh2_cipher *cipher)
 {
     struct hmacsha1 *ctx = snew(struct hmacsha1);
     ctx->mac.vt = alg;
@@ -325,13 +325,10 @@ static void sha1_key_internal(SHA_State *keys,
     smemclr(foo, 64);		       /* burn the evidence */
 }
 
-static void hmacsha1_key(ssh2_mac *mac, const void *key)
+static void hmacsha1_key(ssh2_mac *mac, ptrlen key)
 {
     struct hmacsha1 *ctx = container_of(mac, struct hmacsha1, mac);
-    /* Reading the key length out of the ssh2_macalg structure means
-     * this same method can be used for the _buggy variants which use
-     * a shorter key */
-    sha1_key_internal(ctx->sha, key, ctx->mac.vt->keylen);
+    sha1_key_internal(ctx->sha, key.ptr, key.len);
 }
 
 static void hmacsha1_start(ssh2_mac *mac)
@@ -373,7 +370,7 @@ void hmac_sha1_simple(const void *key, int keylen,
     SHA_Final(&states[1], output);
 }
 
-const struct ssh2_macalg ssh_hmac_sha1 = {
+const ssh2_macalg ssh_hmac_sha1 = {
     hmacsha1_new, hmacsha1_free, hmacsha1_key,
     hmacsha1_start, hmacsha1_genresult,
     "hmac-sha1", "[email protected]",
@@ -381,7 +378,7 @@ const struct ssh2_macalg ssh_hmac_sha1 = {
     "HMAC-SHA1"
 };
 
-const struct ssh2_macalg ssh_hmac_sha1_96 = {
+const ssh2_macalg ssh_hmac_sha1_96 = {
     hmacsha1_new, hmacsha1_free, hmacsha1_key,
     hmacsha1_start, hmacsha1_genresult,
     "hmac-sha1-96", "[email protected]",
@@ -389,7 +386,7 @@ const struct ssh2_macalg ssh_hmac_sha1_96 = {
     "HMAC-SHA1-96"
 };
 
-const struct ssh2_macalg ssh_hmac_sha1_buggy = {
+const ssh2_macalg ssh_hmac_sha1_buggy = {
     hmacsha1_new, hmacsha1_free, hmacsha1_key,
     hmacsha1_start, hmacsha1_genresult,
     "hmac-sha1", NULL,
@@ -397,7 +394,7 @@ const struct ssh2_macalg ssh_hmac_sha1_buggy = {
     "bug-compatible HMAC-SHA1"
 };
 
-const struct ssh2_macalg ssh_hmac_sha1_96_buggy = {
+const ssh2_macalg ssh_hmac_sha1_96_buggy = {
     hmacsha1_new, hmacsha1_free, hmacsha1_key,
     hmacsha1_start, hmacsha1_genresult,
     "hmac-sha1-96", NULL,

+ 3 - 3
source/putty/sshzlib.c

@@ -510,7 +510,7 @@ static void zlib_match(struct LZ77Context *ectx, int distance, int len)
 	 * transmitting.
 	 */
 	i = -1;
-	j = sizeof(lencodes) / sizeof(*lencodes);
+	j = lenof(lencodes);
 	while (1) {
 	    assert(j - i >= 2);
 	    k = (j + i) / 2;
@@ -546,7 +546,7 @@ static void zlib_match(struct LZ77Context *ectx, int distance, int len)
 	 * transmitting.
 	 */
 	i = -1;
-	j = sizeof(distcodes) / sizeof(*distcodes);
+	j = lenof(distcodes);
 	while (1) {
 	    assert(j - i >= 2);
 	    k = (j + i) / 2;
@@ -1196,7 +1196,7 @@ bool zlib_decompress_block(ssh_decompressor *dc,
     return false;
 }
 
-const struct ssh_compression_alg ssh_zlib = {
+const ssh_compression_alg ssh_zlib = {
     "zlib",
     "[email protected]", /* delayed version */
     zlib_compress_init,

+ 11 - 0
source/putty/utils.c

@@ -940,6 +940,17 @@ bool ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2)
     return (pl1.len == pl2.len && !memcmp(pl1.ptr, pl2.ptr, pl1.len));
 }
 
+int ptrlen_strcmp(ptrlen pl1, ptrlen pl2)
+{
+    size_t minlen = pl1.len < pl2.len ? pl1.len : pl2.len;
+    if (minlen) {  /* tolerate plX.ptr==NULL as long as plX.len==0 */
+        int cmp = memcmp(pl1.ptr, pl2.ptr, minlen);
+        if (cmp)
+            return cmp;
+    }
+    return pl1.len < pl2.len ? -1 : pl1.len > pl2.len ? +1 : 0;
+}
+
 bool ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail)
 {
     if (whole.len >= prefix.len &&

+ 0 - 258
source/putty/windows/winmisc.c

@@ -104,16 +104,6 @@ FILE * mp_wfopen(const char *filename, const char *mode)
 
 #endif
 
-#ifndef NO_SECUREZEROMEMORY
-/*
- * Windows implementation of smemclr (see misc.c) using SecureZeroMemory.
- */
-void smemclr(void *b, size_t n) {
-    if (b && n > 0)
-        SecureZeroMemory(b, n);
-}
-#endif
-
 char *get_username(void)
 {
     DWORD namelen;
@@ -359,254 +349,6 @@ const char *win_strerror(int error)
     return es->text;
 }
 
-#ifdef DEBUG
-static FILE *debug_fp = NULL;
-static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
-static int debug_got_console = 0;
-
-void dputs(const char *buf)
-{
-    DWORD dw;
-
-    if (!debug_got_console) {
-	if (AllocConsole()) {
-	    debug_got_console = 1;
-	    debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
-	}
-    }
-    if (!debug_fp) {
-	debug_fp = fopen("debug.log", "w");
-    }
-
-    if (debug_hdl != INVALID_HANDLE_VALUE) {
-	WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
-    }
-    fputs(buf, debug_fp);
-    fflush(debug_fp);
-}
-#endif
-
-#ifdef MINEFIELD
-/*
- * Minefield - a Windows equivalent for Electric Fence
- */
-
-#define PAGESIZE 4096
-
-/*
- * Design:
- * 
- * We start by reserving as much virtual address space as Windows
- * will sensibly (or not sensibly) let us have. We flag it all as
- * invalid memory.
- * 
- * Any allocation attempt is satisfied by committing one or more
- * pages, with an uncommitted page on either side. The returned
- * memory region is jammed up against the _end_ of the pages.
- * 
- * Freeing anything causes instantaneous decommitment of the pages
- * involved, so stale pointers are caught as soon as possible.
- */
-
-static int minefield_initialised = 0;
-static void *minefield_region = NULL;
-static long minefield_size = 0;
-static long minefield_npages = 0;
-static long minefield_curpos = 0;
-static unsigned short *minefield_admin = NULL;
-static void *minefield_pages = NULL;
-
-static void minefield_admin_hide(int hide)
-{
-    int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;
-    VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);
-}
-
-static void minefield_init(void)
-{
-    int size;
-    int admin_size;
-    int i;
-
-    for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {
-	minefield_region = VirtualAlloc(NULL, size,
-					MEM_RESERVE, PAGE_NOACCESS);
-	if (minefield_region)
-	    break;
-    }
-    minefield_size = size;
-
-    /*
-     * Firstly, allocate a section of that to be the admin block.
-     * We'll need a two-byte field for each page.
-     */
-    minefield_admin = minefield_region;
-    minefield_npages = minefield_size / PAGESIZE;
-    admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);
-    minefield_npages = (minefield_size - admin_size) / PAGESIZE;
-    minefield_pages = (char *) minefield_region + admin_size;
-
-    /*
-     * Commit the admin region.
-     */
-    VirtualAlloc(minefield_admin, minefield_npages * 2,
-		 MEM_COMMIT, PAGE_READWRITE);
-
-    /*
-     * Mark all pages as unused (0xFFFF).
-     */
-    for (i = 0; i < minefield_npages; i++)
-	minefield_admin[i] = 0xFFFF;
-
-    /*
-     * Hide the admin region.
-     */
-    minefield_admin_hide(1);
-
-    minefield_initialised = 1;
-}
-
-static void minefield_bomb(void)
-{
-    div(1, *(int *) minefield_pages);
-}
-
-static void *minefield_alloc(int size)
-{
-    int npages;
-    int pos, lim, region_end, region_start;
-    int start;
-    int i;
-
-    npages = (size + PAGESIZE - 1) / PAGESIZE;
-
-    minefield_admin_hide(0);
-
-    /*
-     * Search from current position until we find a contiguous
-     * bunch of npages+2 unused pages.
-     */
-    pos = minefield_curpos;
-    lim = minefield_npages;
-    while (1) {
-	/* Skip over used pages. */
-	while (pos < lim && minefield_admin[pos] != 0xFFFF)
-	    pos++;
-	/* Count unused pages. */
-	start = pos;
-	while (pos < lim && pos - start < npages + 2 &&
-	       minefield_admin[pos] == 0xFFFF)
-	    pos++;
-	if (pos - start == npages + 2)
-	    break;
-	/* If we've reached the limit, reset the limit or stop. */
-	if (pos >= lim) {
-	    if (lim == minefield_npages) {
-		/* go round and start again at zero */
-		lim = minefield_curpos;
-		pos = 0;
-	    } else {
-		minefield_admin_hide(1);
-		return NULL;
-	    }
-	}
-    }
-
-    minefield_curpos = pos - 1;
-
-    /*
-     * We have npages+2 unused pages starting at start. We leave
-     * the first and last of these alone and use the rest.
-     */
-    region_end = (start + npages + 1) * PAGESIZE;
-    region_start = region_end - size;
-    /* FIXME: could align here if we wanted */
-
-    /*
-     * Update the admin region.
-     */
-    for (i = start + 2; i < start + npages + 1; i++)
-	minefield_admin[i] = 0xFFFE;   /* used but no region starts here */
-    minefield_admin[start + 1] = region_start % PAGESIZE;
-
-    minefield_admin_hide(1);
-
-    VirtualAlloc((char *) minefield_pages + region_start, size,
-		 MEM_COMMIT, PAGE_READWRITE);
-    return (char *) minefield_pages + region_start;
-}
-
-static void minefield_free(void *ptr)
-{
-    int region_start, i, j;
-
-    minefield_admin_hide(0);
-
-    region_start = (char *) ptr - (char *) minefield_pages;
-    i = region_start / PAGESIZE;
-    if (i < 0 || i >= minefield_npages ||
-	minefield_admin[i] != region_start % PAGESIZE)
-	minefield_bomb();
-    for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {
-	minefield_admin[j] = 0xFFFF;
-    }
-
-    VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);
-
-    minefield_admin_hide(1);
-}
-
-static int minefield_get_size(void *ptr)
-{
-    int region_start, i, j;
-
-    minefield_admin_hide(0);
-
-    region_start = (char *) ptr - (char *) minefield_pages;
-    i = region_start / PAGESIZE;
-    if (i < 0 || i >= minefield_npages ||
-	minefield_admin[i] != region_start % PAGESIZE)
-	minefield_bomb();
-    for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);
-
-    minefield_admin_hide(1);
-
-    return j * PAGESIZE - region_start;
-}
-
-void *minefield_c_malloc(size_t size)
-{
-    if (!minefield_initialised)
-	minefield_init();
-    return minefield_alloc(size);
-}
-
-void minefield_c_free(void *p)
-{
-    if (!minefield_initialised)
-	minefield_init();
-    minefield_free(p);
-}
-
-/*
- * realloc _always_ moves the chunk, for rapid detection of code
- * that assumes it won't.
- */
-void *minefield_c_realloc(void *p, size_t size)
-{
-    size_t oldsize;
-    void *q;
-    if (!minefield_initialised)
-	minefield_init();
-    q = minefield_alloc(size);
-    oldsize = minefield_get_size(p);
-    memcpy(q, p, (oldsize < size ? oldsize : size));
-    minefield_free(p);
-    return q;
-}
-
-#endif				/* MINEFIELD */
-
 FontSpec *fontspec_new(const char *name, bool bold, int height, int charset)
 {
     FontSpec *f = snew(FontSpec);

+ 277 - 0
source/putty/windows/winmiscs.c

@@ -0,0 +1,277 @@
+/*
+ * winmiscs.c: Windows-specific standalone functions. Has the same
+ * relationship to winmisc.c that utils.c does to misc.c, but the
+ * corresponding name 'winutils.c' was already taken.
+ */
+
+#include "putty.h"
+
+#ifndef NO_SECUREZEROMEMORY
+/*
+ * Windows implementation of smemclr (see misc.c) using SecureZeroMemory.
+ */
+void smemclr(void *b, size_t n) {
+    if (b && n > 0)
+        SecureZeroMemory(b, n);
+}
+#endif
+
+#ifdef DEBUG
+static FILE *debug_fp = NULL;
+static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
+static int debug_got_console = 0;
+
+void dputs(const char *buf)
+{
+    DWORD dw;
+
+    if (!debug_got_console) {
+	if (AllocConsole()) {
+	    debug_got_console = 1;
+	    debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
+	}
+    }
+    if (!debug_fp) {
+	debug_fp = fopen("debug.log", "w");
+    }
+
+    if (debug_hdl != INVALID_HANDLE_VALUE) {
+	WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
+    }
+    fputs(buf, debug_fp);
+    fflush(debug_fp);
+}
+#endif
+
+#ifdef MINEFIELD
+/*
+ * Minefield - a Windows equivalent for Electric Fence
+ */
+
+#define PAGESIZE 4096
+
+/*
+ * Design:
+ * 
+ * We start by reserving as much virtual address space as Windows
+ * will sensibly (or not sensibly) let us have. We flag it all as
+ * invalid memory.
+ * 
+ * Any allocation attempt is satisfied by committing one or more
+ * pages, with an uncommitted page on either side. The returned
+ * memory region is jammed up against the _end_ of the pages.
+ * 
+ * Freeing anything causes instantaneous decommitment of the pages
+ * involved, so stale pointers are caught as soon as possible.
+ */
+
+static int minefield_initialised = 0;
+static void *minefield_region = NULL;
+static long minefield_size = 0;
+static long minefield_npages = 0;
+static long minefield_curpos = 0;
+static unsigned short *minefield_admin = NULL;
+static void *minefield_pages = NULL;
+
+static void minefield_admin_hide(int hide)
+{
+    int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;
+    VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);
+}
+
+static void minefield_init(void)
+{
+    int size;
+    int admin_size;
+    int i;
+
+    for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {
+	minefield_region = VirtualAlloc(NULL, size,
+					MEM_RESERVE, PAGE_NOACCESS);
+	if (minefield_region)
+	    break;
+    }
+    minefield_size = size;
+
+    /*
+     * Firstly, allocate a section of that to be the admin block.
+     * We'll need a two-byte field for each page.
+     */
+    minefield_admin = minefield_region;
+    minefield_npages = minefield_size / PAGESIZE;
+    admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);
+    minefield_npages = (minefield_size - admin_size) / PAGESIZE;
+    minefield_pages = (char *) minefield_region + admin_size;
+
+    /*
+     * Commit the admin region.
+     */
+    VirtualAlloc(minefield_admin, minefield_npages * 2,
+		 MEM_COMMIT, PAGE_READWRITE);
+
+    /*
+     * Mark all pages as unused (0xFFFF).
+     */
+    for (i = 0; i < minefield_npages; i++)
+	minefield_admin[i] = 0xFFFF;
+
+    /*
+     * Hide the admin region.
+     */
+    minefield_admin_hide(1);
+
+    minefield_initialised = 1;
+}
+
+static void minefield_bomb(void)
+{
+    div(1, *(int *) minefield_pages);
+}
+
+static void *minefield_alloc(int size)
+{
+    int npages;
+    int pos, lim, region_end, region_start;
+    int start;
+    int i;
+
+    npages = (size + PAGESIZE - 1) / PAGESIZE;
+
+    minefield_admin_hide(0);
+
+    /*
+     * Search from current position until we find a contiguous
+     * bunch of npages+2 unused pages.
+     */
+    pos = minefield_curpos;
+    lim = minefield_npages;
+    while (1) {
+	/* Skip over used pages. */
+	while (pos < lim && minefield_admin[pos] != 0xFFFF)
+	    pos++;
+	/* Count unused pages. */
+	start = pos;
+	while (pos < lim && pos - start < npages + 2 &&
+	       minefield_admin[pos] == 0xFFFF)
+	    pos++;
+	if (pos - start == npages + 2)
+	    break;
+	/* If we've reached the limit, reset the limit or stop. */
+	if (pos >= lim) {
+	    if (lim == minefield_npages) {
+		/* go round and start again at zero */
+		lim = minefield_curpos;
+		pos = 0;
+	    } else {
+		minefield_admin_hide(1);
+		return NULL;
+	    }
+	}
+    }
+
+    minefield_curpos = pos - 1;
+
+    /*
+     * We have npages+2 unused pages starting at start. We leave
+     * the first and last of these alone and use the rest.
+     */
+    region_end = (start + npages + 1) * PAGESIZE;
+    region_start = region_end - size;
+    /* FIXME: could align here if we wanted */
+
+    /*
+     * Update the admin region.
+     */
+    for (i = start + 2; i < start + npages + 1; i++)
+	minefield_admin[i] = 0xFFFE;   /* used but no region starts here */
+    minefield_admin[start + 1] = region_start % PAGESIZE;
+
+    minefield_admin_hide(1);
+
+    VirtualAlloc((char *) minefield_pages + region_start, size,
+		 MEM_COMMIT, PAGE_READWRITE);
+    return (char *) minefield_pages + region_start;
+}
+
+static void minefield_free(void *ptr)
+{
+    int region_start, i, j;
+
+    minefield_admin_hide(0);
+
+    region_start = (char *) ptr - (char *) minefield_pages;
+    i = region_start / PAGESIZE;
+    if (i < 0 || i >= minefield_npages ||
+	minefield_admin[i] != region_start % PAGESIZE)
+	minefield_bomb();
+    for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {
+	minefield_admin[j] = 0xFFFF;
+    }
+
+    VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);
+
+    minefield_admin_hide(1);
+}
+
+static int minefield_get_size(void *ptr)
+{
+    int region_start, i, j;
+
+    minefield_admin_hide(0);
+
+    region_start = (char *) ptr - (char *) minefield_pages;
+    i = region_start / PAGESIZE;
+    if (i < 0 || i >= minefield_npages ||
+	minefield_admin[i] != region_start % PAGESIZE)
+	minefield_bomb();
+    for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);
+
+    minefield_admin_hide(1);
+
+    return j * PAGESIZE - region_start;
+}
+
+void *minefield_c_malloc(size_t size)
+{
+    if (!minefield_initialised)
+	minefield_init();
+    return minefield_alloc(size);
+}
+
+void minefield_c_free(void *p)
+{
+    if (!minefield_initialised)
+	minefield_init();
+    minefield_free(p);
+}
+
+/*
+ * realloc _always_ moves the chunk, for rapid detection of code
+ * that assumes it won't.
+ */
+void *minefield_c_realloc(void *p, size_t size)
+{
+    size_t oldsize;
+    void *q;
+    if (!minefield_initialised)
+	minefield_init();
+    q = minefield_alloc(size);
+    oldsize = minefield_get_size(p);
+    memcpy(q, p, (oldsize < size ? oldsize : size));
+    minefield_free(p);
+    return q;
+}
+
+#endif				/* MINEFIELD */
+
+#if defined _MSC_VER && _MSC_VER < 1800
+
+/*
+ * Work around lack of strtoumax in older MSVC libraries
+ */
+uintmax_t strtoumax(const char *nptr, char **endptr, int base)
+{
+    return _strtoui64(nptr, endptr, base);
+}
+
+#endif

+ 0 - 8
source/putty/windows/winstuff.h

@@ -108,14 +108,6 @@ struct FontSpec *fontspec_new(
 #define BOXRESULT (DLGWINDOWEXTRA + sizeof(LONG_PTR))
 #define DF_END 0x0001
 
-#ifdef __WINE__
-#define NO_SECUREZEROMEMORY            /* winelib doesn't have this */
-#endif
-
-#ifndef NO_SECUREZEROMEMORY
-#define PLATFORM_HAS_SMEMCLR /* inhibit cross-platform one in misc.c */
-#endif
-
 #ifndef __WINE__
 #ifdef MPEXT
 /* use them as is in bcb */

+ 1 - 1
source/putty/x11fwd.c

@@ -458,7 +458,7 @@ void BinarySink_put_stringpl_xauth(BinarySink *bs, ptrlen pl)
 {
     assert((pl.len >> 16) == 0);
     put_uint16(bs, pl.len);
-    put_data(bs, pl.ptr, pl.len);
+    put_datapl(bs, pl);
 }
 #define put_stringpl_xauth(bs, ptrlen) \
     BinarySink_put_stringpl_xauth(BinarySink_UPCAST(bs),ptrlen)