Package: release.debian.org
Severity: normal
Tags: bullseye
X-Debbugs-Cc: pu...@packages.debian.org
Control: affects -1 + src:putty
User: release.debian....@packages.debian.org
Usertags: pu

[ Reason ]
Security fix CVE-2024-31497

[ Impact ]
Vulnerable biased nonce generation is still here.

[ Tests ]
Full crypto test suite testing particularly CVE-2024-31497 is run

[ Risks ]
Low reviewed by maintainer

Approved by Colin

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Changes ]

putty (0.74-1+deb11u2) bullseye; urgency=medium

  * Non-maintainer upload.
  * Cherry-pick from upstream:
    - Refactor the ssh_hash vtable.
    - Add an extra HMAC constructor function.
    - Fix CVE-2024-31497: biased ECDSA nonce generation allows an attacker
    to recover a user's NIST P-521 secret key via a quick attack in
    approximately 60 signatures. In other words, an adversary
    may already have enough signature information to compromise a victim's
    private key, even if there is no further use of vulnerable PuTTY
    versions.


diff -Nru putty-0.74/debian/changelog putty-0.74/debian/changelog
--- putty-0.74/debian/changelog	2023-12-22 17:36:21.000000000 +0000
+++ putty-0.74/debian/changelog	2024-07-16 10:13:59.000000000 +0000
@@ -1,3 +1,18 @@
+putty (0.74-1+deb11u2) bullseye; urgency=medium
+
+  * Non-maintainer upload.
+  * Cherry-pick from upstream:
+    - Refactor the ssh_hash vtable.
+    - Add an extra HMAC constructor function.
+    - Fix CVE-2024-31497: biased ECDSA nonce generation allows an attacker
+    to recover a user's NIST P-521 secret key via a quick attack in
+    approximately 60 signatures. In other words, an adversary
+    may already have enough signature information to compromise a victim's
+    private key, even if there is no further use of vulnerable PuTTY
+    versions.
+
+ -- Bastien Roucari??s <ro...@debian.org>  Tue, 16 Jul 2024 10:13:59 +0000
+
 putty (0.74-1+deb11u1) bullseye-security; urgency=medium
 
   * Cherry-pick from upstream:
diff -Nru putty-0.74/debian/.git-dpm putty-0.74/debian/.git-dpm
--- putty-0.74/debian/.git-dpm	2023-12-21 16:54:36.000000000 +0000
+++ putty-0.74/debian/.git-dpm	2024-07-16 10:13:59.000000000 +0000
@@ -1,6 +1,6 @@
 # see git-dpm(1) from git-dpm package
-a24da4ff8e3a0d9f2b4adf9d092358f41df18432
-a24da4ff8e3a0d9f2b4adf9d092358f41df18432
+3b973f00dd0076ae305a0b5e7ddab9b811a833dd
+3b973f00dd0076ae305a0b5e7ddab9b811a833dd
 4bd8df1aca313a0da36e559bd4a4d0cf0bc2eaa8
 4bd8df1aca313a0da36e559bd4a4d0cf0bc2eaa8
 putty_0.74.orig.tar.gz
diff -Nru putty-0.74/debian/.gitignore putty-0.74/debian/.gitignore
--- putty-0.74/debian/.gitignore	2023-12-21 16:54:36.000000000 +0000
+++ putty-0.74/debian/.gitignore	1970-01-01 00:00:00.000000000 +0000
@@ -1,7 +0,0 @@
-/*.debhelper*
-/*.substvars
-/files
-/pterm
-/putty
-/putty-doc
-/putty-tools
diff -Nru putty-0.74/debian/patches/0006-Refactor-the-ssh_hash-vtable.-NFC.patch putty-0.74/debian/patches/0006-Refactor-the-ssh_hash-vtable.-NFC.patch
--- putty-0.74/debian/patches/0006-Refactor-the-ssh_hash-vtable.-NFC.patch	1970-01-01 00:00:00.000000000 +0000
+++ putty-0.74/debian/patches/0006-Refactor-the-ssh_hash-vtable.-NFC.patch	2024-07-16 10:13:59.000000000 +0000
@@ -0,0 +1,691 @@
+From 9f15a5795bf67d90aad97a394c4b1a93a56d4cba Mon Sep 17 00:00:00 2001
+From: Simon Tatham <ana...@pobox.com>
+Date: Sun, 15 Dec 2019 09:30:10 +0000
+Subject: Refactor the ssh_hash vtable. (NFC)
+
+Refactor the ssh_hash vtable. (NFC)
+
+The idea is to arrange that an ssh_hash object can be reused without
+having to free it and allocate a new one. So the 'final' method has
+been replaced with 'digest', which does everything except the trailing
+free; and there's also a new pair of methods 'reset' and 'copyfrom'
+which overwrite the state of a hash with either the starting state or
+a copy of another state. Meanwhile, the 'new' allocator function has
+stopped performing 'reset' as a side effect; now it _just_ does the
+administrative stuff (allocation, setting up vtables), and returns an
+object which isn't yet ready to receive any actual data, expecting
+that the caller will either reset it or copy another hash state into
+it.
+
+In particular, that means that the SHA-384 / SHA-512 pair no longer
+need separate 'new' methods, because only the 'reset' part has to
+change between them.
+
+This commit makes no change to the user-facing API of wrapper
+functions in ssh.h, except to add new functions which nothing yet
+calls. The user-facing ssh_hash_new() calls the new and reset methods
+in succession, and the copy and final methods still exist to do
+new+copy and digest+free.
+
+origin: backport, https://git.tartarus.org/?p=simon/putty.git;a=commitdiff_plain;h=156762fc0246c4ff587c72eed7010552f9c1e5bb
+---
+ ssh.h      |  26 ++++++++++----
+ sshmd5.c   |  26 +++++++-------
+ sshsh256.c | 100 +++++++++++++++++++++++++++++------------------------
+ sshsh512.c |  35 ++++++++-----------
+ sshsha.c   |  97 +++++++++++++++++++++++++++------------------------
+ 5 files changed, 154 insertions(+), 130 deletions(-)
+
+diff --git a/ssh.h b/ssh.h
+index 2449c6a4..2f8df928 100644
+--- a/ssh.h
++++ b/ssh.h
+@@ -717,8 +717,9 @@ struct ssh_hash {
+ 
+ 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 (*reset)(ssh_hash *);
++    void (*copyfrom)(ssh_hash *dest, ssh_hash *src);
++    void (*digest)(ssh_hash *, unsigned char *);
+     void (*free)(ssh_hash *);
+     int hlen; /* output length in bytes */
+     int blocklen; /* length of the hash's input block, or 0 for N/A */
+@@ -728,16 +729,27 @@ struct ssh_hashalg {
+ };
+ 
+ static inline ssh_hash *ssh_hash_new(const ssh_hashalg *alg)
+-{ return alg->new(alg); }
+-static inline ssh_hash *ssh_hash_copy(ssh_hash *h)
+-{ return h->vt->copy(h); }
+-static inline void ssh_hash_final(ssh_hash *h, unsigned char *out)
+-{ h->vt->final(h, out); }
++{ ssh_hash *h = alg->new(alg); if (h) h->vt->reset(h); return h; }
++static inline ssh_hash *ssh_hash_copy(ssh_hash *orig)
++{ ssh_hash *h = orig->vt->new(orig->vt); h->vt->copyfrom(h, orig); return h; }
++static inline void ssh_hash_digest(ssh_hash *h, unsigned char *out)
++{ h->vt->digest(h, out); }
+ static inline void ssh_hash_free(ssh_hash *h)
+ { h->vt->free(h); }
+ static inline const ssh_hashalg *ssh_hash_alg(ssh_hash *h)
+ { return h->vt; }
+ 
++/* The reset and copyfrom vtable methods return void. But for call-site
++ * convenience, these wrappers return their input pointer. */
++static inline ssh_hash *ssh_hash_reset(ssh_hash *h)
++{ h->vt->reset(h); return h; }
++static inline ssh_hash *ssh_hash_copyfrom(ssh_hash *dest, ssh_hash *src)
++{ dest->vt->copyfrom(dest, src); return dest; }
++
++/* ssh_hash_final emits the digest _and_ frees the ssh_hash */
++static inline void ssh_hash_final(ssh_hash *h, unsigned char *out)
++{ h->vt->digest(h, out); h->vt->free(h); }
++
+ /* Handy macros for defining all those text-name fields at once */
+ #define HASHALG_NAMES_BARE(base) \
+     base, NULL, base
+diff --git a/sshmd5.c b/sshmd5.c
+index 04de6816..dbcba3f7 100644
+--- a/sshmd5.c
++++ b/sshmd5.c
+@@ -235,24 +235,24 @@ struct md5_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)
++static void md5_reset(ssh_hash *hash)
+ {
+-    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);
++    struct md5_hash *h = container_of(hash, struct md5_hash, hash);
++    MD5Init(&h->state);
++}
+ 
+-    hnew->state = hold->state;
+-    BinarySink_COPIED(&hnew->state);
++static void md5_copyfrom(ssh_hash *hcopy, ssh_hash *horig)
++{
++    struct md5_hash *copy = container_of(hcopy, struct md5_hash, hash);
++    struct md5_hash *orig = container_of(horig, struct md5_hash, hash);
+ 
+-    return hashnew;
++    copy->state = orig->state;
++    BinarySink_COPIED(&copy->state);
+ }
+ 
+ static void md5_free(ssh_hash *hash)
+@@ -263,13 +263,13 @@ static void md5_free(ssh_hash *hash)
+     sfree(h);
+ }
+ 
+-static void md5_final(ssh_hash *hash, unsigned char *output)
++static void md5_digest(ssh_hash *hash, unsigned char *output)
+ {
+     struct md5_hash *h = container_of(hash, struct md5_hash, hash);
+     MD5Final(output, &h->state);
+-    md5_free(hash);
+ }
+ 
+ const ssh_hashalg ssh_md5 = {
+-    md5_new, md5_copy, md5_final, md5_free, 16, 64, HASHALG_NAMES_BARE("MD5"),
++    md5_new, md5_reset, md5_copyfrom, md5_digest, md5_free,
++    16, 64, HASHALG_NAMES_BARE("MD5"),
+ };
+diff --git a/sshsh256.c b/sshsh256.c
+index 1e445171..363e50a4 100644
+--- a/sshsh256.c
++++ b/sshsh256.c
+@@ -98,7 +98,7 @@ static ssh_hash *sha256_select(const ssh_hashalg *alg)
+ }
+ 
+ const ssh_hashalg ssh_sha256 = {
+-    sha256_select, NULL, NULL, NULL,
++    sha256_select, NULL, NULL, NULL, NULL,
+     32, 64, HASHALG_NAMES_ANNOTATED("SHA-256", "dummy selector vtable"),
+ };
+ 
+@@ -276,26 +276,28 @@ static ssh_hash *sha256_sw_new(const ssh_hashalg *alg)
+ {
+     sha256_sw *s = snew(sha256_sw);
+ 
+-    memcpy(s->core, sha256_initial_state, sizeof(s->core));
+-
+-    sha256_block_setup(&s->blk);
+-
+     s->hash.vt = alg;
+     BinarySink_INIT(s, sha256_sw_write);
+     BinarySink_DELEGATE_INIT(&s->hash, s);
+     return &s->hash;
+ }
+ 
+-static ssh_hash *sha256_sw_copy(ssh_hash *hash)
++static void sha256_sw_reset(ssh_hash *hash)
+ {
+     sha256_sw *s = container_of(hash, sha256_sw, hash);
+-    sha256_sw *copy = snew(sha256_sw);
+ 
+-    memcpy(copy, s, sizeof(*copy));
++    memcpy(s->core, sha256_initial_state, sizeof(s->core));
++    sha256_block_setup(&s->blk);
++}
++
++static void sha256_sw_copyfrom(ssh_hash *hcopy, ssh_hash *horig)
++{
++    sha256_sw *copy = container_of(hcopy, sha256_sw, hash);
++    sha256_sw *orig = container_of(horig, sha256_sw, hash);
++
++    memcpy(copy, orig, sizeof(*copy));
+     BinarySink_COPIED(copy);
+     BinarySink_DELEGATE_INIT(&copy->hash, copy);
+-
+-    return &copy->hash;
+ }
+ 
+ static void sha256_sw_free(ssh_hash *hash)
+@@ -315,18 +317,18 @@ static void sha256_sw_write(BinarySink *bs, const void *vp, size_t len)
+             sha256_sw_block(s->core, s->blk.block);
+ }
+ 
+-static void sha256_sw_final(ssh_hash *hash, uint8_t *digest)
++static void sha256_sw_digest(ssh_hash *hash, uint8_t *digest)
+ {
+     sha256_sw *s = container_of(hash, sha256_sw, hash);
+ 
+     sha256_block_pad(&s->blk, BinarySink_UPCAST(s));
+     for (size_t i = 0; i < 8; i++)
+         PUT_32BIT_MSB_FIRST(digest + 4*i, s->core[i]);
+-    sha256_sw_free(hash);
+ }
+ 
+ const ssh_hashalg ssh_sha256_sw = {
+-    sha256_sw_new, sha256_sw_copy, sha256_sw_final, sha256_sw_free,
++    sha256_sw_new, sha256_sw_reset, sha256_sw_copyfrom, sha256_sw_digest,
++    sha256_sw_free,
+     32, 64, HASHALG_NAMES_ANNOTATED("SHA-256", "unaccelerated"),
+ };
+ 
+@@ -602,13 +604,24 @@ static sha256_ni *sha256_ni_alloc(void)
+     return s;
+ }
+ 
+-FUNC_ISA static ssh_hash *sha256_ni_new(const ssh_hashalg *alg)
++static ssh_hash *sha256_ni_new(const ssh_hashalg *alg)
+ {
+     if (!sha256_hw_available_cached())
+         return NULL;
+ 
+     sha256_ni *s = sha256_ni_alloc();
+ 
++    s->hash.vt = alg;
++    BinarySink_INIT(s, sha256_ni_write);
++    BinarySink_DELEGATE_INIT(&s->hash, s);
++
++    return &s->hash;
++}
++
++FUNC_ISA static void sha256_ni_reset(ssh_hash *hash)
++{
++    sha256_ni *s = container_of(hash, sha256_ni, hash);
++
+     /* Initialise the core vectors in their storage order */
+     s->core[0] = _mm_set_epi64x(
+         0x6a09e667bb67ae85ULL, 0x510e527f9b05688cULL);
+@@ -616,26 +629,19 @@ FUNC_ISA static ssh_hash *sha256_ni_new(const ssh_hashalg *alg)
+         0x3c6ef372a54ff53aULL, 0x1f83d9ab5be0cd19ULL);
+ 
+     sha256_block_setup(&s->blk);
+-
+-    s->hash.vt = alg;
+-    BinarySink_INIT(s, sha256_ni_write);
+-    BinarySink_DELEGATE_INIT(&s->hash, s);
+-    return &s->hash;
+ }
+ 
+-static ssh_hash *sha256_ni_copy(ssh_hash *hash)
++static void sha256_ni_copyfrom(ssh_hash *hcopy, ssh_hash *horig)
+ {
+-    sha256_ni *s = container_of(hash, sha256_ni, hash);
+-    sha256_ni *copy = sha256_ni_alloc();
++    sha256_ni *copy = container_of(hcopy, sha256_ni, hash);
++    sha256_ni *orig = container_of(horig, sha256_ni, hash);
+ 
+     void *ptf_save = copy->pointer_to_free;
+-    *copy = *s; /* structure copy */
++    *copy = *orig; /* structure copy */
+     copy->pointer_to_free = ptf_save;
+ 
+     BinarySink_COPIED(copy);
+     BinarySink_DELEGATE_INIT(&copy->hash, copy);
+-
+-    return &copy->hash;
+ }
+ 
+ static void sha256_ni_free(ssh_hash *hash)
+@@ -656,7 +662,7 @@ static void sha256_ni_write(BinarySink *bs, const void *vp, size_t len)
+             sha256_ni_block(s->core, s->blk.block);
+ }
+ 
+-FUNC_ISA static void sha256_ni_final(ssh_hash *hash, uint8_t *digest)
++FUNC_ISA static void sha256_ni_digest(ssh_hash *hash, uint8_t *digest)
+ {
+     sha256_ni *s = container_of(hash, sha256_ni, hash);
+ 
+@@ -677,12 +683,11 @@ FUNC_ISA static void sha256_ni_final(ssh_hash *hash, uint8_t *digest)
+     __m128i *output = (__m128i *)digest;
+     _mm_storeu_si128(output, dcba);
+     _mm_storeu_si128(output+1, hgfe);
+-
+-    sha256_ni_free(hash);
+ }
+ 
+ const ssh_hashalg ssh_sha256_hw = {
+-    sha256_ni_new, sha256_ni_copy, sha256_ni_final, sha256_ni_free,
++    sha256_ni_new, sha256_ni_reset, sha256_ni_copyfrom, sha256_ni_digest,
++    sha256_ni_free,
+     32, 64, HASHALG_NAMES_ANNOTATED("SHA-256", "SHA-NI accelerated"),
+ };
+ 
+@@ -818,28 +823,31 @@ static ssh_hash *sha256_neon_new(const ssh_hashalg *alg)
+ 
+     sha256_neon *s = snew(sha256_neon);
+ 
+-    s->core.abcd = vld1q_u32(sha256_initial_state);
+-    s->core.efgh = vld1q_u32(sha256_initial_state + 4);
+-
+-    sha256_block_setup(&s->blk);
+-
+     s->hash.vt = alg;
+     BinarySink_INIT(s, sha256_neon_write);
+     BinarySink_DELEGATE_INIT(&s->hash, s);
+     return &s->hash;
+ }
+ 
+-static ssh_hash *sha256_neon_copy(ssh_hash *hash)
++static void sha256_neon_reset(ssh_hash *hash)
+ {
+     sha256_neon *s = container_of(hash, sha256_neon, hash);
+-    sha256_neon *copy = snew(sha256_neon);
+ 
+-    *copy = *s; /* structure copy */
++    s->core.abcd = vld1q_u32(sha256_initial_state);
++    s->core.efgh = vld1q_u32(sha256_initial_state + 4);
++
++    sha256_block_setup(&s->blk);
++}
++
++static void sha256_neon_copyfrom(ssh_hash *hcopy, ssh_hash *horig)
++{
++    sha256_neon *copy = container_of(hcopy, sha256_neon, hash);
++    sha256_neon *orig = container_of(horig, sha256_neon, hash);
++
++    *copy = *orig; /* structure copy */
+ 
+     BinarySink_COPIED(copy);
+     BinarySink_DELEGATE_INIT(&copy->hash, copy);
+-
+-    return &copy->hash;
+ }
+ 
+ static void sha256_neon_free(ssh_hash *hash)
+@@ -858,18 +866,18 @@ static void sha256_neon_write(BinarySink *bs, const void *vp, size_t len)
+             sha256_neon_block(&s->core, s->blk.block);
+ }
+ 
+-static void sha256_neon_final(ssh_hash *hash, uint8_t *digest)
++static void sha256_neon_digest(ssh_hash *hash, uint8_t *digest)
+ {
+     sha256_neon *s = container_of(hash, sha256_neon, hash);
+ 
+     sha256_block_pad(&s->blk, BinarySink_UPCAST(s));
+     vst1q_u8(digest,      vrev32q_u8(vreinterpretq_u8_u32(s->core.abcd)));
+     vst1q_u8(digest + 16, vrev32q_u8(vreinterpretq_u8_u32(s->core.efgh)));
+-    sha256_neon_free(hash);
+ }
+ 
+ const ssh_hashalg ssh_sha256_hw = {
+-    sha256_neon_new, sha256_neon_copy, sha256_neon_final, sha256_neon_free,
++    sha256_neon_new, sha256_neon_reset, sha256_neon_copyfrom,
++    sha256_neon_digest, sha256_neon_free,
+     32, 64, HASHALG_NAMES_ANNOTATED("SHA-256", "NEON accelerated"),
+ };
+ 
+@@ -895,12 +903,14 @@ static ssh_hash *sha256_stub_new(const ssh_hashalg *alg)
+ 
+ #define STUB_BODY { unreachable("Should never be called"); }
+ 
+-static ssh_hash *sha256_stub_copy(ssh_hash *hash) STUB_BODY
++static void sha256_stub_reset(ssh_hash *hash) STUB_BODY
++static void sha256_stub_copyfrom(ssh_hash *hash, ssh_hash *orig) STUB_BODY
+ static void sha256_stub_free(ssh_hash *hash) STUB_BODY
+-static void sha256_stub_final(ssh_hash *hash, uint8_t *digest) STUB_BODY
++static void sha256_stub_digest(ssh_hash *hash, uint8_t *digest) STUB_BODY
+ 
+ const ssh_hashalg ssh_sha256_hw = {
+-    sha256_stub_new, sha256_stub_copy, sha256_stub_final, sha256_stub_free,
++    sha256_stub_new, sha256_stub_reset, sha256_stub_copyfrom,
++    sha256_stub_digest, sha256_stub_free,
+     32, 64, HASHALG_NAMES_ANNOTATED(
+         "SHA-256", "!NONEXISTENT ACCELERATED VERSION!"),
+ };
+diff --git a/sshsh512.c b/sshsh512.c
+index 6712047c..03201d74 100644
+--- a/sshsh512.c
++++ b/sshsh512.c
+@@ -307,24 +307,24 @@ struct sha512_hash {
+ static ssh_hash *sha512_new(const ssh_hashalg *alg)
+ {
+     struct sha512_hash *h = snew(struct sha512_hash);
+-    SHA512_Init(&h->state);
+     h->hash.vt = alg;
+     BinarySink_DELEGATE_INIT(&h->hash, &h->state);
+-    return &h->hash;
++    return ssh_hash_reset(&h->hash);
+ }
+ 
+-static ssh_hash *sha512_copy(ssh_hash *hashold)
++static void sha512_reset(ssh_hash *hash)
+ {
+-    struct sha512_hash *hold, *hnew;
+-    ssh_hash *hashnew = sha512_new(hashold->vt);
++    struct sha512_hash *h = container_of(hash, struct sha512_hash, hash);
++    SHA512_Init(&h->state);
++}
+ 
+-    hold = container_of(hashold, struct sha512_hash, hash);
+-    hnew = container_of(hashnew, struct sha512_hash, hash);
++static void sha512_copyfrom(ssh_hash *hashnew, ssh_hash *hashold)
++{
++    struct sha512_hash *hold = container_of(hashold, struct sha512_hash, hash);
++    struct sha512_hash *hnew = container_of(hashnew, struct sha512_hash, hash);
+ 
+     hnew->state = hold->state;
+     BinarySink_COPIED(&hnew->state);
+-
+-    return hashnew;
+ }
+ 
+ static void sha512_free(ssh_hash *hash)
+@@ -335,35 +335,30 @@ static void sha512_free(ssh_hash *hash)
+     sfree(h);
+ }
+ 
+-static void sha512_final(ssh_hash *hash, unsigned char *output)
++static void sha512_digest(ssh_hash *hash, unsigned char *output)
+ {
+     struct sha512_hash *h = container_of(hash, struct sha512_hash, hash);
+     SHA512_Final(&h->state, output);
+-    sha512_free(hash);
+ }
+ 
+ const ssh_hashalg ssh_sha512 = {
+-    sha512_new, sha512_copy, sha512_final, sha512_free,
++    sha512_new, sha512_reset, sha512_copyfrom, sha512_digest, sha512_free,
+     64, BLKSIZE, HASHALG_NAMES_BARE("SHA-512"),
+ };
+ 
+-static ssh_hash *sha384_new(const ssh_hashalg *alg)
++static void sha384_reset(ssh_hash *hash)
+ {
+-    struct sha512_hash *h = snew(struct sha512_hash);
++    struct sha512_hash *h = container_of(hash, struct sha512_hash, hash);
+     SHA384_Init(&h->state);
+-    h->hash.vt = alg;
+-    BinarySink_DELEGATE_INIT(&h->hash, &h->state);
+-    return &h->hash;
+ }
+ 
+-static void sha384_final(ssh_hash *hash, unsigned char *output)
++static void sha384_digest(ssh_hash *hash, unsigned char *output)
+ {
+     struct sha512_hash *h = container_of(hash, struct sha512_hash, hash);
+     SHA384_Final(&h->state, output);
+-    sha512_free(hash);
+ }
+ 
+ const ssh_hashalg ssh_sha384 = {
+-    sha384_new, sha512_copy, sha384_final, sha512_free,
++    sha512_new, sha384_reset, sha512_copyfrom, sha384_digest, sha512_free,
+     48, BLKSIZE, HASHALG_NAMES_BARE("SHA-384"),
+ };
+diff --git a/sshsha.c b/sshsha.c
+index 0b8b58f5..dac393aa 100644
+--- a/sshsha.c
++++ b/sshsha.c
+@@ -98,7 +98,7 @@ static ssh_hash *sha1_select(const ssh_hashalg *alg)
+ }
+ 
+ const ssh_hashalg ssh_sha1 = {
+-    sha1_select, NULL, NULL, NULL,
++    sha1_select, NULL, NULL, NULL, NULL,
+     20, 64, HASHALG_NAMES_ANNOTATED("SHA-1", "dummy selector vtable"),
+ };
+ 
+@@ -259,26 +259,28 @@ static ssh_hash *sha1_sw_new(const ssh_hashalg *alg)
+ {
+     sha1_sw *s = snew(sha1_sw);
+ 
+-    memcpy(s->core, sha1_initial_state, sizeof(s->core));
+-
+-    sha1_block_setup(&s->blk);
+-
+     s->hash.vt = alg;
+     BinarySink_INIT(s, sha1_sw_write);
+     BinarySink_DELEGATE_INIT(&s->hash, s);
+     return &s->hash;
+ }
+ 
+-static ssh_hash *sha1_sw_copy(ssh_hash *hash)
++static void sha1_sw_reset(ssh_hash *hash)
+ {
+     sha1_sw *s = container_of(hash, sha1_sw, hash);
+-    sha1_sw *copy = snew(sha1_sw);
+ 
+-    memcpy(copy, s, sizeof(*copy));
++    memcpy(s->core, sha1_initial_state, sizeof(s->core));
++    sha1_block_setup(&s->blk);
++}
++
++static void sha1_sw_copyfrom(ssh_hash *hcopy, ssh_hash *horig)
++{
++    sha1_sw *copy = container_of(hcopy, sha1_sw, hash);
++    sha1_sw *orig = container_of(horig, sha1_sw, hash);
++
++    memcpy(copy, orig, sizeof(*copy));
+     BinarySink_COPIED(copy);
+     BinarySink_DELEGATE_INIT(&copy->hash, copy);
+-
+-    return &copy->hash;
+ }
+ 
+ static void sha1_sw_free(ssh_hash *hash)
+@@ -298,18 +300,17 @@ static void sha1_sw_write(BinarySink *bs, const void *vp, size_t len)
+             sha1_sw_block(s->core, s->blk.block);
+ }
+ 
+-static void sha1_sw_final(ssh_hash *hash, uint8_t *digest)
++static void sha1_sw_digest(ssh_hash *hash, uint8_t *digest)
+ {
+     sha1_sw *s = container_of(hash, sha1_sw, hash);
+ 
+     sha1_block_pad(&s->blk, BinarySink_UPCAST(s));
+     for (size_t i = 0; i < 5; i++)
+         PUT_32BIT_MSB_FIRST(digest + 4*i, s->core[i]);
+-    sha1_sw_free(hash);
+ }
+ 
+ const ssh_hashalg ssh_sha1_sw = {
+-    sha1_sw_new, sha1_sw_copy, sha1_sw_final, sha1_sw_free,
++    sha1_sw_new, sha1_sw_reset, sha1_sw_copyfrom, sha1_sw_digest, sha1_sw_free,
+     20, 64, HASHALG_NAMES_ANNOTATED("SHA-1", "unaccelerated"),
+ };
+ 
+@@ -573,39 +574,42 @@ static sha1_ni *sha1_ni_alloc(void)
+     return s;
+ }
+ 
+-FUNC_ISA static ssh_hash *sha1_ni_new(const ssh_hashalg *alg)
++static ssh_hash *sha1_ni_new(const ssh_hashalg *alg)
+ {
+     if (!sha1_hw_available_cached())
+         return NULL;
+ 
+     sha1_ni *s = sha1_ni_alloc();
+ 
++    s->hash.vt = alg;
++    BinarySink_INIT(s, sha1_ni_write);
++    BinarySink_DELEGATE_INIT(&s->hash, s);
++    return &s->hash;
++}
++
++FUNC_ISA static void sha1_ni_reset(ssh_hash *hash)
++{
++    sha1_ni *s = container_of(hash, sha1_ni, hash);
++
+     /* Initialise the core vectors in their storage order */
+     s->core[0] = _mm_set_epi64x(
+         0x67452301efcdab89ULL, 0x98badcfe10325476ULL);
+     s->core[1] = _mm_set_epi32(0xc3d2e1f0, 0, 0, 0);
+ 
+     sha1_block_setup(&s->blk);
+-
+-    s->hash.vt = alg;
+-    BinarySink_INIT(s, sha1_ni_write);
+-    BinarySink_DELEGATE_INIT(&s->hash, s);
+-    return &s->hash;
+ }
+ 
+-static ssh_hash *sha1_ni_copy(ssh_hash *hash)
++static void sha1_ni_copyfrom(ssh_hash *hcopy, ssh_hash *horig)
+ {
+-    sha1_ni *s = container_of(hash, sha1_ni, hash);
+-    sha1_ni *copy = sha1_ni_alloc();
++    sha1_ni *copy = container_of(hcopy, sha1_ni, hash);
++    sha1_ni *orig = container_of(horig, sha1_ni, hash);
+ 
+     void *ptf_save = copy->pointer_to_free;
+-    *copy = *s; /* structure copy */
++    *copy = *orig; /* structure copy */
+     copy->pointer_to_free = ptf_save;
+ 
+     BinarySink_COPIED(copy);
+     BinarySink_DELEGATE_INIT(&copy->hash, copy);
+-
+-    return &copy->hash;
+ }
+ 
+ static void sha1_ni_free(ssh_hash *hash)
+@@ -626,7 +630,7 @@ static void sha1_ni_write(BinarySink *bs, const void *vp, size_t len)
+             sha1_ni_block(s->core, s->blk.block);
+ }
+ 
+-FUNC_ISA static void sha1_ni_final(ssh_hash *hash, uint8_t *digest)
++FUNC_ISA static void sha1_ni_digest(ssh_hash *hash, uint8_t *digest)
+ {
+     sha1_ni *s = container_of(hash, sha1_ni, hash);
+ 
+@@ -645,12 +649,10 @@ FUNC_ISA static void sha1_ni_final(ssh_hash *hash, uint8_t *digest)
+     /* Finally, store the leftover word */
+     uint32_t e = _mm_extract_epi32(s->core[1], 3);
+     PUT_32BIT_MSB_FIRST(digest + 16, e);
+-
+-    sha1_ni_free(hash);
+ }
+ 
+ const ssh_hashalg ssh_sha1_hw = {
+-    sha1_ni_new, sha1_ni_copy, sha1_ni_final, sha1_ni_free,
++    sha1_ni_new, sha1_ni_reset, sha1_ni_copyfrom, sha1_ni_digest, sha1_ni_free,
+     20, 64, HASHALG_NAMES_ANNOTATED("SHA-1", "SHA-NI accelerated"),
+ };
+ 
+@@ -813,28 +815,31 @@ static ssh_hash *sha1_neon_new(const ssh_hashalg *alg)
+ 
+     sha1_neon *s = snew(sha1_neon);
+ 
+-    s->core.abcd = vld1q_u32(sha1_initial_state);
+-    s->core.e = sha1_initial_state[4];
+-
+-    sha1_block_setup(&s->blk);
+-
+     s->hash.vt = alg;
+     BinarySink_INIT(s, sha1_neon_write);
+     BinarySink_DELEGATE_INIT(&s->hash, s);
+     return &s->hash;
+ }
+ 
+-static ssh_hash *sha1_neon_copy(ssh_hash *hash)
++static void sha1_neon_reset(ssh_hash *hash)
+ {
+     sha1_neon *s = container_of(hash, sha1_neon, hash);
+-    sha1_neon *copy = snew(sha1_neon);
+ 
+-    *copy = *s; /* structure copy */
++    s->core.abcd = vld1q_u32(sha1_initial_state);
++    s->core.e = sha1_initial_state[4];
++
++    sha1_block_setup(&s->blk);
++}
++
++static void sha1_neon_copyfrom(ssh_hash *hcopy, ssh_hash *horig)
++{
++    sha1_neon *copy = container_of(hcopy, sha1_neon, hash);
++    sha1_neon *orig = container_of(horig, sha1_neon, hash);
++
++    *copy = *orig; /* structure copy */
+ 
+     BinarySink_COPIED(copy);
+     BinarySink_DELEGATE_INIT(&copy->hash, copy);
+-
+-    return &copy->hash;
+ }
+ 
+ static void sha1_neon_free(ssh_hash *hash)
+@@ -853,18 +858,18 @@ static void sha1_neon_write(BinarySink *bs, const void *vp, size_t len)
+             sha1_neon_block(&s->core, s->blk.block);
+ }
+ 
+-static void sha1_neon_final(ssh_hash *hash, uint8_t *digest)
++static void sha1_neon_digest(ssh_hash *hash, uint8_t *digest)
+ {
+     sha1_neon *s = container_of(hash, sha1_neon, hash);
+ 
+     sha1_block_pad(&s->blk, BinarySink_UPCAST(s));
+     vst1q_u8(digest, vrev32q_u8(vreinterpretq_u8_u32(s->core.abcd)));
+     PUT_32BIT_MSB_FIRST(digest + 16, s->core.e);
+-    sha1_neon_free(hash);
+ }
+ 
+ const ssh_hashalg ssh_sha1_hw = {
+-    sha1_neon_new, sha1_neon_copy, sha1_neon_final, sha1_neon_free,
++    sha1_neon_new, sha1_neon_reset, sha1_neon_copyfrom, sha1_neon_digest,
++    sha1_neon_free,
+     20, 64, HASHALG_NAMES_ANNOTATED("SHA-1", "NEON accelerated"),
+ };
+ 
+@@ -890,12 +895,14 @@ static ssh_hash *sha1_stub_new(const ssh_hashalg *alg)
+ 
+ #define STUB_BODY { unreachable("Should never be called"); }
+ 
+-static ssh_hash *sha1_stub_copy(ssh_hash *hash) STUB_BODY
++static void sha1_stub_reset(ssh_hash *hash) STUB_BODY
++static void sha1_stub_copyfrom(ssh_hash *hash, ssh_hash *orig) STUB_BODY
+ static void sha1_stub_free(ssh_hash *hash) STUB_BODY
+-static void sha1_stub_final(ssh_hash *hash, uint8_t *digest) STUB_BODY
++static void sha1_stub_digest(ssh_hash *hash, uint8_t *digest) STUB_BODY
+ 
+ const ssh_hashalg ssh_sha1_hw = {
+-    sha1_stub_new, sha1_stub_copy, sha1_stub_final, sha1_stub_free,
++    sha1_stub_new, sha1_stub_reset, sha1_stub_copyfrom, sha1_stub_digest,
++    sha1_stub_free,
+     20, 64, HASHALG_NAMES_ANNOTATED(
+         "SHA-1", "!NONEXISTENT ACCELERATED VERSION!"),
+ };
diff -Nru putty-0.74/debian/patches/0007-Add-an-extra-HMAC-constructor-function.patch putty-0.74/debian/patches/0007-Add-an-extra-HMAC-constructor-function.patch
--- putty-0.74/debian/patches/0007-Add-an-extra-HMAC-constructor-function.patch	1970-01-01 00:00:00.000000000 +0000
+++ putty-0.74/debian/patches/0007-Add-an-extra-HMAC-constructor-function.patch	2024-07-16 10:13:59.000000000 +0000
@@ -0,0 +1,121 @@
+From dd4a85ecaadb2cfa038754efd3862072eb62b20f Mon Sep 17 00:00:00 2001
+From: Simon Tatham <ana...@pobox.com>
+Date: Mon, 29 Apr 2024 18:50:46 +0000
+Subject: Add an extra HMAC constructor function.
+
+This takes a plain ssh_hashalg, and constructs the most natural kind
+of HMAC wrapper around it, taking its key length and output length
+to be the hash's output length. In other words, it converts SHA-foo
+into exactly the thing usually called HMAC-SHA-foo.
+
+It does it by constructing a new ssh2_macalg vtable, and including it
+in the same memory allocation as the actual hash object. That's the
+first time in PuTTY I've done it this way.
+
+Nothing yet uses this, but a new piece of code is about to.
+
+[backport]
+- Drop nullmac_next_message uses that is not used in this bullseye version
+
+origin: backport, https://git.tartarus.org/?p=simon/putty.git;a=commitdiff_plain;h=dea3ddca0537299ebfe907dd4c883fe65bfb4035
+---
+ ssh.h     |  5 +++++
+ sshhmac.c | 48 +++++++++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 50 insertions(+), 3 deletions(-)
+
+diff --git a/ssh.h b/ssh.h
+index 2f8df928..aa375ab7 100644
+--- a/ssh.h
++++ b/ssh.h
+@@ -710,6 +710,11 @@ bool ssh2_mac_verify(ssh2_mac *, const void *, int, unsigned long seq);
+  * string with a given key in the most obvious way. */
+ void mac_simple(const ssh2_macalg *alg, ptrlen key, ptrlen data, void *output);
+ 
++/* Constructor that makes an HMAC object given just a MAC. This object
++ * will have empty 'name' and 'etm_name' fields, so it's not suitable
++ * for use in SSH. It's used as a subroutine in RFC 6979. */
++ssh2_mac *hmac_new_from_hash(const ssh_hashalg *hash);
++
+ struct ssh_hash {
+     const ssh_hashalg *vt;
+     BinarySink_DELEGATE_IMPLEMENTATION;
+diff --git a/sshhmac.c b/sshhmac.c
+index 2f870f36..ff536b73 100644
+--- a/sshhmac.c
++++ b/sshhmac.c
+@@ -19,9 +19,10 @@ struct hmac_extra {
+     const char *suffix, *annotation;
+ };
+ 
+-static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher)
+-{
+-    struct hmac *ctx = snew(struct hmac);
++/* Most of hmac_new(). Takes the actual 'struct hmac' as a parameter,
++ * because sometimes it will have been allocated in a special way. */
++static ssh2_mac *hmac_new_inner(struct hmac *ctx, const ssh2_macalg *alg)
++ {
+     const struct hmac_extra *extra = (const struct hmac_extra *)alg->extra;
+ 
+     ctx->h_outer = ssh_hash_new(extra->hashalg_base);
+@@ -66,6 +67,11 @@ static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher)
+     return &ctx->mac;
+ }
+ 
++static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher)
++{
++    return hmac_new_inner(snew(struct hmac), alg); /* cipher isn't needed */
++}
++
+ static void hmac_free(ssh2_mac *mac)
+ {
+     struct hmac *ctx = container_of(mac, struct hmac, mac);
+@@ -81,6 +87,8 @@ static void hmac_free(ssh2_mac *mac)
+     sfree(ctx);
+ }
+ 
++
++
+ #define PAD_OUTER 0x5C
+ #define PAD_INNER 0x36
+ 
+@@ -187,6 +195,40 @@ static const char *hmac_text_name(ssh2_mac *mac)
+     return ctx->text_name->s;
+ }
+ 
++ssh2_mac *hmac_new_from_hash(const ssh_hashalg *hash)
++{
++    /*
++     * Construct a custom ssh2_macalg, derived directly from the
++     * provided hash vtable. It's included in the same memory
++     * allocation as the struct hmac, so that it all gets freed
++     * together.
++     */
++
++    struct alloc {
++        struct hmac hmac;
++        ssh2_macalg alg;
++        struct hmac_extra extra;
++    };
++
++    struct alloc *alloc = snew(struct alloc);
++    alloc->alg.new = hmac_new;
++    alloc->alg.free = hmac_free;
++    alloc->alg.setkey = hmac_key;
++    alloc->alg.start = hmac_start;
++    alloc->alg.genresult = hmac_genresult;
++    alloc->alg.text_name = hmac_text_name;
++    alloc->alg.name = NULL;
++    alloc->alg.etm_name = NULL;
++    alloc->alg.len = hash->hlen;
++    alloc->alg.keylen = hash->hlen;
++    alloc->alg.extra = &alloc->extra;
++    alloc->extra.hashalg_base = hash;
++    alloc->extra.suffix = "";
++    alloc->extra.annotation = NULL;
++
++    return hmac_new_inner(&alloc->hmac, &alloc->alg);
++}
++
+ const struct hmac_extra ssh_hmac_sha256_extra = { &ssh_sha256, "" };
+ const ssh2_macalg ssh_hmac_sha256 = {
+     hmac_new, hmac_free, hmac_key,
diff -Nru putty-0.74/debian/patches/0008-Switch-to-RFC-6979-for-DSA-nonce-generation.patch putty-0.74/debian/patches/0008-Switch-to-RFC-6979-for-DSA-nonce-generation.patch
--- putty-0.74/debian/patches/0008-Switch-to-RFC-6979-for-DSA-nonce-generation.patch	1970-01-01 00:00:00.000000000 +0000
+++ putty-0.74/debian/patches/0008-Switch-to-RFC-6979-for-DSA-nonce-generation.patch	2024-07-16 10:13:59.000000000 +0000
@@ -0,0 +1,1206 @@
+From 3b973f00dd0076ae305a0b5e7ddab9b811a833dd Mon Sep 17 00:00:00 2001
+From: Simon Tatham <ana...@pobox.com>
+Date: Mon, 29 Apr 2024 15:46:17 +0000
+Subject: Switch to RFC 6979 for DSA nonce generation.
+
+Switch to RFC 6979 for DSA nonce generation.
+
+This fixes a vulnerability that compromises NIST P521 ECDSA keys when
+they are used with PuTTY's existing DSA nonce generation code. The
+vulnerability has been assigned the identifier CVE-2024-31497.
+
+PuTTY has been doing its DSA signing deterministically for literally
+as long as it's been doing it at all, because I didn't trust Windows's
+entropy generation. Deterministic nonce generation was introduced in
+commit d345ebc2a5a0b59, as part of the initial version of our DSA
+signing routine. At the time, there was no standard for how to do it,
+so we had to think up the details of our system ourselves, with some
+help from the Cambridge University computer security group.
+
+More than ten years later, RFC 6979 was published, recommending a
+similar system for general use, naturally with all the details
+different. We didn't switch over to doing it that way, because we had
+a scheme in place already, and as far as I could see, the differences
+were not security-critical - just the normal sort of variation you
+expect when any two people design a protocol component of this kind
+independently.
+
+As far as I know, the _structure_ of our scheme is still perfectly
+fine, in terms of what data gets hashed, how many times, and how the
+hash output is converted into a nonce. But the weak spot is the choice
+of hash function: inside our dsa_gen_k() function, we generate 512
+bits of random data using SHA-512, and then reduce that to the output
+range by modular reduction, regardless of what signature algorithm
+we're generating a nonce for.
+
+In the original use case, this introduced a theoretical bias (the
+output size is an odd prime, which doesn't evenly divide the space of
+2^512 possible inputs to the reduction), but the theory was that since
+integer DSA uses a modulus prime only 160 bits long (being based on
+SHA-1, at least in the form that SSH uses it), the bias would be too
+small to be detectable, let alone exploitable.
+
+Then we reused the same function for NIST-style ECDSA, when it
+arrived. This is fine for the P256 curve, and even P384. But in P521,
+the order of the base point is _greater_ than 2^512, so when we
+generate a 512-bit number and reduce it, the reduction never makes any
+difference, and our output nonces are all in the first 2^512 elements
+of the range of about 2^521. So this _does_ introduce a significant
+bias in the nonces, compared to the ideal of uniformly random
+distribution over the whole range. And it's been recently discovered
+that a bias of this kind is sufficient to expose private keys, given a
+manageably small number of signatures to work from.
+
+(Incidentally, none of this affects Ed25519. The spec for that system
+includes its own idea of how you should do deterministic nonce
+generation - completely different again, naturally - and we did it
+that way rather than our way, so that we could use the existing test
+vectors.)
+
+The simplest fix would be to patch our existing nonce generator to use
+a longer hash, or concatenate a couple of SHA-512 hashes, or something
+similar. But I think a more robust approach is to switch it out
+completely for what is now the standard system. The main reason why I
+prefer that is that the standard system comes with test vectors, which
+adds a lot of confidence that I haven't made some other mistake in
+following my own design.
+
+So here's a commit that adds an implementation of RFC 6979, and
+removes the old dsa_gen_k() function. Tests are added based on the
+RFC's appendix of test vectors (as many as are compatible with the
+more limited API of PuTTY's crypto code, e.g. we lack support for the
+NIST P192 curve, or for doing integer DSA with many different hash
+functions). One existing test changes its expected outputs, namely the
+one that has a sample key pair and signature for every key algorithm
+we support.
+
+origin: backport, https://git.tartarus.org/?p=simon/putty.git;a=commitdiff_plain;h=c193fe9848f50a88a4089aac647fecc31ae96d27
+bug: https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/vuln-p521-bias.html
+bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2024-31497
+---
+ Makefile.am        |  24 +--
+ Recipe             |   9 +-
+ defs.h             |   2 +
+ rfc6979.c          | 359 +++++++++++++++++++++++++++++++++++++++++++++
+ ssh.h              |  16 +-
+ sshdss.c           | 116 +--------------
+ sshecc.c           |  14 +-
+ test/cryptsuite.py | 253 +++++++++++++++++++++++++++++++-
+ testcrypt.h        |   5 +
+ testsc.c           |  60 ++++++++
+ 10 files changed, 713 insertions(+), 145 deletions(-)
+ create mode 100644 rfc6979.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 3360c6b2..4ff7f76e 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -70,7 +70,7 @@ allsources = agentf.c aqsync.c be_all_s.c be_misc.c be_none.c be_nos_s.c \
+ 		windows/winsecur.c windows/winsecur.h windows/winser.c \
+ 		windows/winsftp.c windows/winshare.c windows/winstore.c \
+ 		windows/winstuff.h windows/wintime.c windows/winucs.c \
+-		windows/winutils.c windows/winx11.c x11fwd.c
++		windows/winutils.c windows/winx11.c x11fwd.c rfc6979.c
+ 
+ if HAVE_GTK
+ bin_PROGRAMS = plink pscp psftp puttygen pageant pterm putty puttytel
+@@ -104,7 +104,7 @@ cgtest_SOURCES = cgtest.c conf.c ecc.c import.c marshal.c memory.c misc.c \
+ 		sshrsa.c sshrsag.c sshsh256.c sshsh512.c sshsha.c \
+ 		stripctrl.c time.c tree234.c unix/uxcons.c unix/uxgen.c \
+ 		unix/uxmisc.c unix/uxnogtk.c unix/uxnoise.c unix/uxpoll.c \
+-		unix/uxstore.c unix/uxutils.c utils.c wcwidth.c
++		unix/uxstore.c unix/uxutils.c utils.c wcwidth.c rfc6979.c
+ cgtest_LDADD = libversion.a
+ 
+ fuzzterm_SOURCES = be_none.c callback.c charset/fromucs.c charset/localenc.c \
+@@ -131,7 +131,7 @@ pageant_SOURCES = aqsync.c be_misc.c be_none.c callback.c conf.c ecc.c \
+ 		unix/uxmisc.c unix/uxnet.c unix/uxnoise.c unix/uxpeer.c \
+ 		unix/uxpgnt.c unix/uxpoll.c unix/uxproxy.c unix/uxsel.c \
+ 		unix/uxsignal.c unix/uxstore.c unix/uxutils.c utils.c \
+-		wcwidth.c x11fwd.c
++		wcwidth.c x11fwd.c rfc6979.c
+ pageant_LDADD = libversion.a $(GTK_LIBS)
+ endif
+ 
+@@ -154,7 +154,7 @@ plink_SOURCES = agentf.c aqsync.c be_all_s.c be_misc.c callback.c cmdline.c \
+ 		unix/uxnet.c unix/uxnogtk.c unix/uxnoise.c unix/uxpeer.c \
+ 		unix/uxplink.c unix/uxpoll.c unix/uxproxy.c unix/uxsel.c \
+ 		unix/uxser.c unix/uxshare.c unix/uxsignal.c unix/uxstore.c \
+-		unix/uxutils.c utils.c wcwidth.c wildcard.c x11fwd.c
++		unix/uxutils.c utils.c wcwidth.c wildcard.c x11fwd.c rfc6979.c
+ plink_LDADD = libversion.a
+ 
+ pscp_SOURCES = agentf.c aqsync.c be_misc.c be_ssh.c callback.c cmdline.c \
+@@ -175,7 +175,7 @@ pscp_SOURCES = agentf.c aqsync.c be_misc.c be_ssh.c callback.c cmdline.c \
+ 		unix/uxgss.c unix/uxmisc.c unix/uxnet.c unix/uxnogtk.c \
+ 		unix/uxnoise.c unix/uxpeer.c unix/uxpoll.c unix/uxproxy.c \
+ 		unix/uxsel.c unix/uxsftp.c unix/uxshare.c unix/uxstore.c \
+-		unix/uxutils.c utils.c wcwidth.c wildcard.c x11fwd.c
++		unix/uxutils.c utils.c wcwidth.c wildcard.c x11fwd.c rfc6979.c
+ pscp_LDADD = libversion.a
+ 
+ psftp_SOURCES = agentf.c aqsync.c be_misc.c be_ssh.c callback.c cmdline.c \
+@@ -196,7 +196,7 @@ psftp_SOURCES = agentf.c aqsync.c be_misc.c be_ssh.c callback.c cmdline.c \
+ 		unix/uxgss.c unix/uxmisc.c unix/uxnet.c unix/uxnogtk.c \
+ 		unix/uxnoise.c unix/uxpeer.c unix/uxpoll.c unix/uxproxy.c \
+ 		unix/uxsel.c unix/uxsftp.c unix/uxshare.c unix/uxstore.c \
+-		unix/uxutils.c utils.c wcwidth.c wildcard.c x11fwd.c
++		unix/uxutils.c utils.c wcwidth.c wildcard.c x11fwd.c rfc6979.c
+ psftp_LDADD = libversion.a
+ 
+ if HAVE_GTK
+@@ -261,7 +261,7 @@ putty_SOURCES = agentf.c aqsync.c be_all_s.c be_misc.c callback.c \
+ 		unix/uxser.c unix/uxshare.c unix/uxsignal.c unix/uxstore.c \
+ 		unix/uxucs.c unix/uxutils.c unix/x11misc.c unix/xkeysym.c \
+ 		unix/xpmpucfg.c unix/xpmputty.c utils.c wcwidth.c wildcard.c \
+-		x11fwd.c
++		x11fwd.c rfc6979.c
+ putty_LDADD = libversion.a $(GTK_LIBS)
+ endif
+ 
+@@ -293,7 +293,7 @@ puttyapp_SOURCES = agentf.c aqsync.c be_all_s.c be_misc.c callback.c \
+ 		unix/uxser.c unix/uxshare.c unix/uxsignal.c unix/uxstore.c \
+ 		unix/uxucs.c unix/uxutils.c unix/x11misc.c unix/xkeysym.c \
+ 		unix/xpmpucfg.c unix/xpmputty.c utils.c wcwidth.c wildcard.c \
+-		x11fwd.c
++		x11fwd.c rfc6979.c
+ puttyapp_LDADD = libversion.a $(GTK_LIBS)
+ endif
+ 
+@@ -304,7 +304,7 @@ puttygen_SOURCES = cmdgen.c conf.c ecc.c import.c marshal.c memory.c misc.c \
+ 		sshrsa.c sshrsag.c sshsh256.c sshsh512.c sshsha.c \
+ 		stripctrl.c time.c tree234.c unix/uxcons.c unix/uxgen.c \
+ 		unix/uxmisc.c unix/uxnogtk.c unix/uxnoise.c unix/uxpoll.c \
+-		unix/uxstore.c unix/uxutils.c utils.c wcwidth.c
++		unix/uxstore.c unix/uxutils.c utils.c wcwidth.c rfc6979.c
+ puttygen_LDADD = libversion.a
+ 
+ if HAVE_GTK
+@@ -331,13 +331,13 @@ testcrypt_SOURCES = ecc.c marshal.c memory.c mpint.c sshaes.c ssharcf.c \
+ 		sshauxcrypt.c sshblowf.c sshccp.c sshcrc.c sshcrcda.c \
+ 		sshdes.c sshdh.c sshdss.c sshecc.c sshhmac.c sshmd5.c \
+ 		sshprime.c sshprng.c sshrsa.c sshsh256.c sshsh512.c sshsha.c \
+-		testcrypt.c tree234.c unix/uxutils.c utils.c
++		testcrypt.c tree234.c unix/uxutils.c utils.c rfc6979.c
+ 
+ testsc_SOURCES = ecc.c marshal.c memory.c mpint.c sshaes.c ssharcf.c \
+ 		sshauxcrypt.c sshblowf.c sshccp.c sshcrc.c sshcrcda.c \
+ 		sshdes.c sshdh.c sshdss.c sshecc.c sshhmac.c sshmac.c \
+ 		sshmd5.c sshrsa.c sshsh256.c sshsh512.c sshsha.c testsc.c \
+-		tree234.c unix/uxutils.c utils.c wildcard.c
++		tree234.c unix/uxutils.c utils.c wildcard.c rfc6979.c
+ 
+ testzlib_SOURCES = marshal.c memory.c sshzlib.c testzlib.c utils.c
+ 
+@@ -360,7 +360,7 @@ uppity_SOURCES = be_misc.c be_none.c callback.c conf.c cproxy.c ecc.c \
+ 		unix/uxnoise.c unix/uxpeer.c unix/uxpoll.c unix/uxproxy.c \
+ 		unix/uxpty.c unix/uxsel.c unix/uxserver.c \
+ 		unix/uxsftpserver.c unix/uxsignal.c unix/uxstore.c \
+-		unix/uxutils.c utils.c wcwidth.c wildcard.c x11fwd.c
++		unix/uxutils.c utils.c wcwidth.c wildcard.c x11fwd.c rfc6979.c
+ uppity_LDADD = libversion.a
+ 
+ if AUTO_GIT_COMMIT
+diff --git a/Recipe b/Recipe
+index 4bad3f33..15d656b3 100644
+--- a/Recipe
++++ b/Recipe
+@@ -262,6 +262,7 @@ SSHCRYPTO = ARITH sshmd5 sshsha sshsh256 sshsh512
+          + sshdes sshblowf sshaes sshccp ssharcf
+          + sshdh sshcrc sshcrcda sshauxcrypt
+          + sshhmac
++         + rfc6979
+ SSHCOMMON = sshcommon sshprng sshrand SSHCRYPTO
+          + sshverstring
+          + sshpubk sshzlib
+@@ -338,7 +339,7 @@ psftp    : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
+          + psftp.res winnojmp winnohlp LIBS
+ 
+ pageant  : [G] winpgnt pageant sshrsa sshpubk sshdes ARITH sshmd5 version
+-	 + tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
++	 + tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256 rfc6979
+ 	 + sshsh512 winutils sshecc winmisc winmiscs winhelp conf pageant.res
+ 	 + sshauxcrypt sshhmac LIBS
+ 
+@@ -346,7 +347,7 @@ puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes ARITH sshmd5 version
+          + sshrand winnoise sshsha winstore MISC winctrls sshrsa sshdss winmisc
+          + sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res
+          + tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc sshprng
+-         + sshecdsag sshauxcrypt sshhmac winsecur winmiscs
++         + sshecdsag sshauxcrypt sshhmac winsecur winmiscs rfc6979
+ 
+ pterm    : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
+          + uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg
+@@ -366,6 +367,7 @@ PUTTYGEN_UNIX = sshrsag sshdssg sshprime sshdes ARITH sshmd5 version sshprng
+          + sshpubk sshaes sshsh256 sshsh512 IMPORT puttygen.res time tree234
+          + uxgen notiming CONF sshecc sshecdsag uxnogtk sshauxcrypt sshhmac
+          + uxpoll uxutils
++         + rfc6979
+ puttygen : [U] cmdgen PUTTYGEN_UNIX
+ cgtest   : [UT] cgtest PUTTYGEN_UNIX
+ 
+@@ -377,6 +379,7 @@ pageant  : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes ARITH
+ 	 + sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons
+          + gtkask gtkmisc nullplug logging UXMISC uxagentsock utils memory
+ 	 + sshauxcrypt sshhmac sshprng uxnoise
++	 + rfc6979
+ 
+ ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
+          + uxsignal CHARSET uxpterm version time xpmpterm xpmptcfg
+@@ -390,10 +393,12 @@ fuzzterm : [UT] UXTERM CHARSET MISC version uxmisc uxucs fuzzterm time settings
+ 	 + uxstore be_none uxnogtk memory
+ testcrypt : [UT] testcrypt SSHCRYPTO sshprng sshprime marshal utils
+           + memory tree234 uxutils
++          + rfc6979
+ testcrypt : [C] testcrypt SSHCRYPTO sshprng sshprime marshal utils
+           + memory tree234 winmiscs
+ testsc    : [UT] testsc SSHCRYPTO marshal utils memory tree234 wildcard
+           + sshmac uxutils
++          + rfc6979
+ testzlib : [UT] testzlib sshzlib utils marshal memory
+ 
+ uppity   : [UT] uxserver SSHSERVER UXMISC uxsignal uxnoise uxgss uxnogtk
+diff --git a/defs.h b/defs.h
+index b9577036..4a4bf72e 100644
+--- a/defs.h
++++ b/defs.h
+@@ -141,6 +141,8 @@ typedef struct ssh_cipher ssh_cipher;
+ typedef struct ssh2_ciphers ssh2_ciphers;
+ typedef struct dh_ctx dh_ctx;
+ typedef struct ecdh_key ecdh_key;
++typedef struct RFC6979 RFC6979;
++typedef struct RFC6979Result RFC6979Result;
+ 
+ typedef struct dlgparam dlgparam;
+ 
+diff --git a/rfc6979.c b/rfc6979.c
+new file mode 100644
+index 00000000..73e5c924
+--- /dev/null
++++ b/rfc6979.c
+@@ -0,0 +1,359 @@
++/*
++ * Code to generate 'nonce' values for DSA signature algorithms, in a
++ * deterministic way.
++ */
++
++#include "ssh.h"
++#include "mpint.h"
++#include "misc.h"
++
++/*
++ * All DSA-type signature systems depend on a nonce - a random number
++ * generated during the signing operation.
++ *
++ * This nonce is a weak point of DSA and needs careful protection,
++ * for multiple reasons:
++ *
++ *  1. If an attacker in possession of your public key and a single
++ *     signature can find out or guess the nonce you used in that
++ *     signature, they can immediately recover your _private key_.
++ *
++ *  2. If you reuse the same nonce in two different signatures, this
++ *     will be instantly obvious to the attacker (one of the two
++ *     values making up the signature will match), and again, they can
++ *     immediately recover the private key as soon as they notice this.
++ *
++ *  3. In at least one system, information about your private key is
++ *     leaked merely by generating nonces with a significant bias.
++ *
++ * Attacks #1 and #2 work across all of integer DSA, NIST-style ECDSA,
++ * and EdDSA. The details vary, but the headline effects are the same.
++ *
++ * So we must be very careful with our nonces. They must be generated
++ * with uniform distribution, but also, they must avoid depending on
++ * any random number generator that has the slightest doubt about its
++ * reliability.
++ *
++ * In particular, PuTTY's policy is that for this purpose we don't
++ * _even_ trust the PRNG we use for other cryptography. This is mostly
++ * a concern because of Windows, where system entropy sources are
++ * limited and we have doubts about their trustworthiness
++ * - even CryptGenRandom. PuTTY compensates as best it can with its
++ * own ongoing entropy collection, and we trust that for session keys,
++ * but revealing the private key that goes with a long-term public key
++ * is a far worse outcome than revealing one SSH session key, and for
++ * keeping your private key safe, we don't think the available Windows
++ * entropy gives us enough confidence.
++ *
++ * A common strategy these days (although <hipster>PuTTY was doing it
++ * before it was cool</hipster>) is to avoid using a PRNG based on
++ * system entropy at all. Instead, you use a deterministic PRNG that
++ * starts from a fixed input seed, and in that input seed you include
++ * the message to be signed and the _private key_.
++ *
++ * Including the private key in the seed is counterintuitive, but does
++ * actually make sense. A deterministic nonce generation strategy must
++ * use _some_ piece of input that the attacker doesn't have, or else
++ * they'd be able to repeat the entire computation and construct the
++ * same nonce you did. And the one thing they don't know is the
++ * private key! So we include that in the seed data (under enough
++ * layers of overcautious hashing to protect it against exposure), and
++ * then they _can't_ repeat the same construction. Moreover, if they
++ * _could_, they'd already know the private key, so they wouldn't need
++ * to perform an attack of this kind at all!
++ *
++ * (This trick doesn't, _per se_, protect against reuse of nonces.
++ * That is left to chance, which is enough, because the space of
++ * nonces is large enough to make it adequately unlikely. But it
++ * avoids escalating the reuse risk due to inadequate entropy.)
++ *
++ * For integer DSA and ECDSA, the system we use for deterministic
++ * generation of k is exactly the one specified in RFC 6979. We
++ * switched to this from the old system that PuTTY used to use before
++ * that RFC came out. The old system had a critical bug: it did not
++ * always generate _enough_ data to get uniform distribution, because
++ * its output was a single SHA-512 hash. We could have fixed that
++ * minimally, by concatenating multiple hashes, but it seemed more
++ * sensible to switch to a system that comes with test vectors.
++ *
++ * One downside of RFC 6979 is that it's based on rejection sampling
++ * (that is, you generate a random number and keep retrying until it's
++ * in range). This makes it play badly with our side-channel test
++ * system, which wants every execution trace of a supposedly
++ * constant-time operation to be the same. To work around this
++ * awkwardness, we break up the algorithm further, into a setup phase
++ * and an 'attempt to generate an output' phase, each of which is
++ * individually constant-time.
++ */
++
++struct RFC6979 {
++    /*
++     * Size of the cyclic group over which we're doing DSA.
++     * Equivalently, the multiplicative order of g (for integer DSA)
++     * or the curve's base point (for ECDSA). For integer DSA this is
++     * also the same thing as the small prime q from the key
++     * parameters.
++     *
++     * This pointer is not owned. Freeing this structure will not free
++     * it, and freeing the pointed-to integer before freeing this
++     * structure will make this structure dangerous to use.
++     */
++    mp_int *q;
++
++    /*
++     * The private key integer, which is always the discrete log of
++     * the public key with respect to the group generator.
++     *
++     * This pointer is not owned. Freeing this structure will not free
++     * it, and freeing the pointed-to integer before freeing this
++     * structure will make this structure dangerous to use.
++     */
++    mp_int *x;
++
++    /*
++     * Cached values derived from q: its length in bits, and in bytes.
++     */
++    size_t qbits, qbytes;
++
++    /*
++     * Reusable hash and MAC objects.
++     */
++    ssh_hash *hash;
++    ssh2_mac *mac;
++
++    /*
++     * Cached value: the output length of the hash.
++     */
++    size_t hlen;
++
++    /*
++     * The byte string V used in the algorithm.
++     */
++    unsigned char V[MAX_HASH_LEN];
++
++    /*
++     * The string T to use during each attempt, and how many
++     * hash-sized blocks to fill it with.
++     */
++    size_t T_nblocks;
++    unsigned char *T;
++};
++
++static mp_int *bits2int(ptrlen b, RFC6979 *s)
++{
++    if (b.len > s->qbytes)
++        b.len = s->qbytes;
++    mp_int *x = mp_from_bytes_be(b);
++
++    /*
++     * Rationale for using mp_rshift_fixed_into and not
++     * mp_rshift_safe_into: the shift count is derived from the
++     * difference between the length of the modulus q, and the length
++     * of the input bit string, i.e. between the _sizes_ of things
++     * involved in the protocol. But the sizes aren't secret. Only the
++     * actual values of integers and bit strings of those sizes are
++     * secret. So it's OK for the shift count to be known to an
++     * attacker - they'd know it anyway just from which DSA algorithm
++     * we were using.
++     */
++    if (b.len * 8 > s->qbits)
++        mp_rshift_fixed_into(x, x, b.len * 8 - s->qbits);
++
++    return x;
++}
++
++static void BinarySink_put_int2octets(BinarySink *bs, mp_int *x, RFC6979 *s)
++{
++    mp_int *x_mod_q = mp_mod(x, s->q);
++    for (size_t i = s->qbytes; i-- > 0 ;)
++        put_byte(bs, mp_get_byte(x_mod_q, i));
++    mp_free(x_mod_q);
++}
++
++static void BinarySink_put_bits2octets(BinarySink *bs, ptrlen b, RFC6979 *s)
++{
++    mp_int *x = bits2int(b, s);
++    BinarySink_put_int2octets(bs, x, s);
++    mp_free(x);
++}
++
++#define put_int2octets(bs, x, s) \
++    BinarySink_put_int2octets(BinarySink_UPCAST(bs), x, s)
++#define put_bits2octets(bs, b, s) \
++    BinarySink_put_bits2octets(BinarySink_UPCAST(bs), b, s)
++
++RFC6979 *rfc6979_new(const ssh_hashalg *hashalg, mp_int *q, mp_int *x)
++{
++    /* Make the state structure. */
++    RFC6979 *s = snew(RFC6979);
++    s->q = q;
++    s->x = x;
++    s->qbits = mp_get_nbits(q);
++    s->qbytes = (s->qbits + 7) >> 3;
++    s->hash = ssh_hash_new(hashalg);
++    s->mac = hmac_new_from_hash(hashalg);
++    s->hlen = hashalg->hlen;
++
++    /* In each attempt, we concatenate enough hash blocks to be
++     * greater than qbits in size. */
++    size_t hbits = 8 * s->hlen;
++    s->T_nblocks = (s->qbits + hbits - 1) / hbits;
++    s->T = snewn(s->T_nblocks * s->hlen, unsigned char);
++
++    return s;
++}
++
++void rfc6979_setup(RFC6979 *s, ptrlen message)
++{
++    unsigned char h1[MAX_HASH_LEN];
++    unsigned char K[MAX_HASH_LEN];
++
++    /* 3.2 (a): hash the message to get h1. */
++    ssh_hash_reset(s->hash);
++    put_datapl(s->hash, message);
++    ssh_hash_digest(s->hash, h1);
++
++    /* 3.2 (b): set V to a sequence of 0x01 bytes the same size as the
++     * hash function's output. */
++    memset(s->V, 1, s->hlen);
++
++    /* 3.2 (c): set the initial HMAC key K to all zeroes, again the
++     * same size as the hash function's output. */
++    memset(K, 0, s->hlen);
++    ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));
++
++    /* 3.2 (d): compute the MAC of V, the private key, and h1, with
++     * key K, making a new key to replace K. */
++    ssh2_mac_start(s->mac);
++    put_data(s->mac, s->V, s->hlen);
++    put_byte(s->mac, 0);
++    put_int2octets(s->mac, s->x, s);
++    put_bits2octets(s->mac, make_ptrlen(h1, s->hlen), s);
++    ssh2_mac_genresult(s->mac, K);
++    ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));
++
++    /* 3.2 (e): replace V with its HMAC using the new K. */
++    ssh2_mac_start(s->mac);
++    put_data(s->mac, s->V, s->hlen);
++    ssh2_mac_genresult(s->mac, s->V);
++
++    /* 3.2 (f): repeat step (d), only using the new K in place of the
++     * initial all-zeroes one, and with the extra byte in the middle
++     * of the MAC preimage being 1 rather than 0. */
++    ssh2_mac_start(s->mac);
++    put_data(s->mac, s->V, s->hlen);
++    put_byte(s->mac, 1);
++    put_int2octets(s->mac, s->x, s);
++    put_bits2octets(s->mac, make_ptrlen(h1, s->hlen), s);
++    ssh2_mac_genresult(s->mac, K);
++    ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));
++
++    /* 3.2 (g): repeat step (e), using the again-replaced K. */
++    ssh2_mac_start(s->mac);
++    put_data(s->mac, s->V, s->hlen);
++    ssh2_mac_genresult(s->mac, s->V);
++
++    smemclr(h1, sizeof(h1));
++    smemclr(K, sizeof(K));
++}
++
++RFC6979Result rfc6979_attempt(RFC6979 *s)
++{
++    RFC6979Result result;
++
++    /* 3.2 (h) 1: set T to the empty string */
++    /* 3.2 (h) 2: make lots of output by concatenating MACs of V */
++    for (size_t i = 0; i < s->T_nblocks; i++) {
++        ssh2_mac_start(s->mac);
++        put_data(s->mac, s->V, s->hlen);
++        ssh2_mac_genresult(s->mac, s->V);
++        memcpy(s->T + i * s->hlen, s->V, s->hlen);
++    }
++
++    /* 3.2 (h) 3: if we have a number in [1, q-1], return it ... */
++    result.k = bits2int(make_ptrlen(s->T, s->T_nblocks * s->hlen), s);
++    result.ok = mp_hs_integer(result.k, 1) & ~mp_cmp_hs(result.k, s->q);
++
++    /*
++     * Perturb K and regenerate V ready for the next attempt.
++     *
++     * We do this unconditionally, whether or not the k we just
++     * generated is acceptable. The time cost isn't large compared to
++     * the public-key operation we're going to do next (not to mention
++     * the larger number of these same operations we've already done),
++     * and it makes side-channel testing easier if this function is
++     * constant-time from beginning to end.
++     *
++     * In other rejection-sampling situations, particularly prime
++     * generation, we're not this careful: it's enough to ensure that
++     * _successful_ attempts run in constant time, Failures can do
++     * whatever they like, on the theory that the only information
++     * they _have_ to potentially expose via side channels is
++     * information that was subsequently thrown away without being
++     * used for anything important. (Hence, for example, it's fine to
++     * have multiple different early-exit paths for failures you
++     * detect at different times.)
++     *
++     * But here, the situation is different. Prime generation attempts
++     * are independent of each other. These are not. All our
++     * iterations round this loop use the _same_ secret data set up by
++     * rfc6979_new(), and also, the perturbation step we're about to
++     * compute will be used by the next iteration if there is one. So
++     * it's absolutely _not_ true that a failed iteration deals
++     * exclusively with data that won't contribute to the eventual
++     * output. Hence, we have to be careful about the failures as well
++     * as the successes.
++     *
++     * (Even so, it would be OK to make successes and failures take
++     * different amounts of time, as long as each of those amounts was
++     * consistent. But it's easier for testing to make them the same.)
++     */
++    ssh2_mac_start(s->mac);
++    put_data(s->mac, s->V, s->hlen);
++    put_byte(s->mac, 0);
++    unsigned char K[MAX_HASH_LEN];
++    ssh2_mac_genresult(s->mac, K);
++    ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));
++    smemclr(K, sizeof(K));
++
++    ssh2_mac_start(s->mac);
++    put_data(s->mac, s->V, s->hlen);
++    ssh2_mac_genresult(s->mac, s->V);
++
++    return result;
++}
++
++void rfc6979_free(RFC6979 *s)
++{
++    /* We don't free s->q or s->x: our caller still owns those. */
++
++    ssh_hash_free(s->hash);
++    ssh2_mac_free(s->mac);
++    smemclr(s->T, s->T_nblocks * s->hlen);
++    sfree(s->T);
++
++    /* Clear the whole structure before freeing. Most fields aren't
++     * sensitive (pointers or well-known length values), but V is, and
++     * it's easier to clear the whole lot than fiddle about
++     * identifying the sensitive fields. */
++    smemclr(s, sizeof(*s));
++
++    sfree(s);
++}
++
++mp_int *rfc6979(
++    const ssh_hashalg *hashalg, mp_int *q, mp_int *x, ptrlen message)
++{
++    RFC6979 *s = rfc6979_new(hashalg, q, x);
++    rfc6979_setup(s, message);
++    RFC6979Result result;
++    while (true) {
++        result = rfc6979_attempt(s);
++        if (result.ok)
++            break;
++        else
++            mp_free(result.k);
++    }
++    rfc6979_free(s);
++    return result.k;
++}
+diff --git a/ssh.h b/ssh.h
+index aa375ab7..4c1cad41 100644
+--- a/ssh.h
++++ b/ssh.h
+@@ -589,11 +589,18 @@ void ssh_ecdhkex_getpublic(ecdh_key *key, BinarySink *bs);
+ mp_int *ssh_ecdhkex_getkey(ecdh_key *key, ptrlen remoteKey);
+ 
+ /*
+- * Helper function for k generation in DSA, reused in ECDSA
++ * System for generating k in DSA and ECDSA.
+  */
+-mp_int *dss_gen_k(const char *id_string,
+-                     mp_int *modulus, mp_int *private_key,
+-                     unsigned char *digest, int digest_len);
++struct RFC6979Result {
++    mp_int *k;
++    unsigned ok;
++};
++RFC6979 *rfc6979_new(const ssh_hashalg *hashalg, mp_int *q, mp_int *x);
++void rfc6979_setup(RFC6979 *s, ptrlen message);
++RFC6979Result rfc6979_attempt(RFC6979 *s);
++void rfc6979_free(RFC6979 *s);
++mp_int *rfc6979(const ssh_hashalg *hashalg, mp_int *modulus,
++                mp_int *private_key, ptrlen message);
+ 
+ struct ssh_cipher {
+     const ssh_cipheralg *vt;
+@@ -971,6 +978,7 @@ extern const ssh2_macalg ssh_hmac_sha1_buggy;
+ extern const ssh2_macalg ssh_hmac_sha1_96;
+ extern const ssh2_macalg ssh_hmac_sha1_96_buggy;
+ extern const ssh2_macalg ssh_hmac_sha256;
++extern const ssh2_macalg ssh_hmac_sha384;
+ extern const ssh2_macalg ssh2_poly1305;
+ extern const ssh_compression_alg ssh_zlib;
+ 
+diff --git a/sshdss.c b/sshdss.c
+index 90dc075a..059d2b6d 100644
+--- a/sshdss.c
++++ b/sshdss.c
+@@ -317,117 +317,6 @@ static int dss_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
+     return ret;
+ }
+ 
+-mp_int *dss_gen_k(const char *id_string, mp_int *modulus,
+-                     mp_int *private_key,
+-                     unsigned char *digest, int digest_len)
+-{
+-    /*
+-     * The basic DSS signing algorithm is:
+-     *
+-     *  - invent a random k between 1 and q-1 (exclusive).
+-     *  - Compute r = (g^k mod p) mod q.
+-     *  - Compute s = k^-1 * (hash + x*r) mod q.
+-     *
+-     * This has the dangerous properties that:
+-     *
+-     *  - if an attacker in possession of the public key _and_ the
+-     *    signature (for example, the host you just authenticated
+-     *    to) can guess your k, he can reverse the computation of s
+-     *    and work out x = r^-1 * (s*k - hash) mod q. That is, he
+-     *    can deduce the private half of your key, and masquerade
+-     *    as you for as long as the key is still valid.
+-     *
+-     *  - since r is a function purely of k and the public key, if
+-     *    the attacker only has a _range of possibilities_ for k
+-     *    it's easy for him to work through them all and check each
+-     *    one against r; he'll never be unsure of whether he's got
+-     *    the right one.
+-     *
+-     *  - if you ever sign two different hashes with the same k, it
+-     *    will be immediately obvious because the two signatures
+-     *    will have the same r, and moreover an attacker in
+-     *    possession of both signatures (and the public key of
+-     *    course) can compute k = (hash1-hash2) * (s1-s2)^-1 mod q,
+-     *    and from there deduce x as before.
+-     *
+-     *  - the Bleichenbacher attack on DSA makes use of methods of
+-     *    generating k which are significantly non-uniformly
+-     *    distributed; in particular, generating a 160-bit random
+-     *    number and reducing it mod q is right out.
+-     *
+-     * For this reason we must be pretty careful about how we
+-     * generate our k. Since this code runs on Windows, with no
+-     * particularly good system entropy sources, we can't trust our
+-     * RNG itself to produce properly unpredictable data. Hence, we
+-     * use a totally different scheme instead.
+-     *
+-     * What we do is to take a SHA-512 (_big_) hash of the private
+-     * key x, and then feed this into another SHA-512 hash that
+-     * also includes the message hash being signed. That is:
+-     *
+-     *   proto_k = SHA512 ( SHA512(x) || SHA160(message) )
+-     *
+-     * This number is 512 bits long, so reducing it mod q won't be
+-     * noticeably non-uniform. So
+-     *
+-     *   k = proto_k mod q
+-     *
+-     * This has the interesting property that it's _deterministic_:
+-     * signing the same hash twice with the same key yields the
+-     * same signature.
+-     *
+-     * Despite this determinism, it's still not predictable to an
+-     * attacker, because in order to repeat the SHA-512
+-     * construction that created it, the attacker would have to
+-     * know the private key value x - and by assumption he doesn't,
+-     * because if he knew that he wouldn't be attacking k!
+-     *
+-     * (This trick doesn't, _per se_, protect against reuse of k.
+-     * Reuse of k is left to chance; all it does is prevent
+-     * _excessively high_ chances of reuse of k due to entropy
+-     * problems.)
+-     *
+-     * Thanks to Colin Plumb for the general idea of using x to
+-     * ensure k is hard to guess, and to the Cambridge University
+-     * Computer Security Group for helping to argue out all the
+-     * fine details.
+-     */
+-    ssh_hash *h;
+-    unsigned char digest512[64];
+-
+-    /*
+-     * Hash some identifying text plus x.
+-     */
+-    h = ssh_hash_new(&ssh_sha512);
+-    put_asciz(h, id_string);
+-    put_mp_ssh2(h, private_key);
+-    ssh_hash_final(h, digest512);
+-
+-    /*
+-     * Now hash that digest plus the message hash.
+-     */
+-    h = ssh_hash_new(&ssh_sha512);
+-    put_data(h, digest512, sizeof(digest512));
+-    put_data(h, digest, digest_len);
+-    ssh_hash_final(h, digest512);
+-
+-    /*
+-     * Now convert the result into a bignum, and coerce it to the
+-     * range [2,q), which we do by reducing it mod q-2 and adding 2.
+-     */
+-    mp_int *modminus2 = mp_copy(modulus);
+-    mp_sub_integer_into(modminus2, modminus2, 2);
+-    mp_int *proto_k = mp_from_bytes_be(make_ptrlen(digest512, 64));
+-    mp_int *k = mp_mod(proto_k, modminus2);
+-    mp_free(proto_k);
+-    mp_free(modminus2);
+-    mp_add_integer_into(k, k, 2);
+-
+-    smemclr(digest512, sizeof(digest512));
+-
+-    return k;
+-}
+-
+ static void dss_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs)
+ {
+     struct dss_key *dss = container_of(key, struct dss_key, sshk);
+@@ -436,8 +325,9 @@ static void dss_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs)
+ 
+     hash_simple(&ssh_sha1, data, digest);
+ 
+-    mp_int *k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x,
+-                          digest, sizeof(digest));
++    /* Generate any valid exponent k, using the RFC 6979 deterministic
++     * procedure. */
++    mp_int *k = rfc6979(&ssh_sha1, dss->q, dss->x, data);
+     mp_int *kinv = mp_invert(k, dss->q);       /* k^-1 mod q */
+ 
+     /*
+diff --git a/sshecc.c b/sshecc.c
+index 3005e288..eec4ec21 100644
+--- a/sshecc.c
++++ b/sshecc.c
+@@ -997,16 +997,10 @@ static void ecdsa_sign(ssh_key *key, ptrlen data,
+ 
+     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];
+-        hash_simple(&ssh_sha1, data, digest);
+-        k = dss_gen_k(
+-            "ECDSA deterministic k generator", ek->curve->w.G_order,
+-            ek->privateKey, digest, sizeof(digest));
+-    }
++    /* Generate any valid exponent k, using the RFC 6979 deterministic
++     * procedure. */
++    mp_int *k = rfc6979(
++        extra->hash, ek->curve->w.G_order, ek->privateKey, data);
+ 
+     WeierstrassPoint *kG = ecc_weierstrass_multiply(ek->curve->w.G, k);
+     mp_int *x;
+diff --git a/test/cryptsuite.py b/test/cryptsuite.py
+index 5564c11f..5e40f048 100755
+--- a/test/cryptsuite.py
++++ b/test/cryptsuite.py
+@@ -86,6 +86,13 @@ def last(iterable):
+         pass
+     return toret
+ 
++def le_integer(x, nbits):
++    assert nbits % 8 == 0
++    return bytes([0xFF & (x >> (8*n)) for n in range(nbits//8)])
++
++def be_integer(x, nbits):
++    return bytes(reversed(le_integer(x, nbits)))
++
+ @contextlib.contextmanager
+ def queued_random_data(nbytes, seed):
+     hashsize = 512 // 8
+@@ -1324,6 +1331,244 @@ culpa qui officia deserunt mollit anim id est laborum.
+         self.assertFalse(ssh_key_verify(pubkey, badsig0, "hello, again"))
+         self.assertFalse(ssh_key_verify(pubkey, badsigq, "hello, again"))
+ 
++    def testRFC6979(self):
++        # The test case described in detail in RFC 6979 section A.1.
++        # We can't actually do the _signature_ for this, because it's
++        # based on ECDSA over a finite field of characteristic 2, and
++        # we only support prime-order fields. But we don't need to do
++        # full ECDSA, only generate the same deterministic nonce that
++        # the test case expects.
++        k = rfc6979('sha256',
++                    0x4000000000000000000020108A2E0CC0D99F8A5EF,
++                    0x09A4D6792295A7F730FC3F2B49CBC0F62E862272F, "sample")
++        self.assertEqual(int(k), 0x23AF4074C90A02B3FE61D286D5C87F425E6BDD81B)
++
++        # Selected test cases from the rest of Appendix A.
++        #
++        # We can only use test cases for which we have the appropriate
++        # hash function, so I've left out the test cases based on
++        # SHA-224. (We could easily implement that, but I don't think
++        # it's worth it just for adding further tests of this one
++        # function.) Similarly, I've omitted test cases relating to
++        # ECDSA curves we don't implement: P192, P224, and all the
++        # curves over power-of-2 finite fields.
++        #
++        # Where possible, we also test the actual signature algorithm,
++        # to make sure it delivers the same entire signature as the
++        # test case. This demonstrates that the rfc6979() function is
++        # being called in the right way and the results are being used
++        # as they should be. Here I've had to cut down the test cases
++        # even further, because the RFC specifies test cases with a
++        # cross product of DSA group and hash function, whereas we
++        # have a fixed hash (specified by SSH) for each signature
++        # algorithm. And the RFC is clear that you use the same hash
++        # for nonce generation and actual signing.
++
++        # A.2.1: 1024-bit DSA
++        q = 0x996F967F6C8E388D9E28D01E205FBA957A5698B1
++        x = 0x411602CB19A6CCC34494D79D98EF1E7ED5AF25F7
++        k = rfc6979('sha1', q, x, "sample")
++        self.assertEqual(int(k), 0x7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B)
++        k = rfc6979('sha256', q, x, "sample")
++        self.assertEqual(int(k), 0x519BA0546D0C39202A7D34D7DFA5E760B318BCFB)
++        k = rfc6979('sha384', q, x, "sample")
++        self.assertEqual(int(k), 0x95897CD7BBB944AA932DBC579C1C09EB6FCFC595)
++        k = rfc6979('sha512', q, x, "sample")
++        self.assertEqual(int(k), 0x09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B)
++        k = rfc6979('sha1', q, x, "test")
++        self.assertEqual(int(k), 0x5C842DF4F9E344EE09F056838B42C7A17F4A6433)
++        k = rfc6979('sha256', q, x, "test")
++        self.assertEqual(int(k), 0x5A67592E8128E03A417B0484410FB72C0B630E1A)
++        k = rfc6979('sha384', q, x, "test")
++        self.assertEqual(int(k), 0x220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89)
++        k = rfc6979('sha512', q, x, "test")
++        self.assertEqual(int(k), 0x65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C)
++        # The rest of the public key, for signature testing
++        p = 0x86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED8873ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779
++        g = 0x07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA417BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD
++        y = 0x5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F65392195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E682F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B
++        pubblob = ssh_string(b"ssh-dss") + b"".join(map(ssh2_mpint, [p,q,g,y]))
++        privblob = ssh2_mpint(x)
++        pubkey = ssh_key_new_pub('dsa', pubblob)
++        privkey = ssh_key_new_priv('dsa', pubblob, privblob)
++        sig = ssh_key_sign(privkey, b"sample", 0)
++        # Expected output using SHA-1 as the hash in nonce
++        # construction.
++        r = 0x2E1A0C2562B2912CAAF89186FB0F42001585DA55
++        s = 0x29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
++        ref_sig = ssh_string(b"ssh-dss") + ssh_string(
++            be_integer(r, 160) + be_integer(s, 160))
++        self.assertEqual(sig, ref_sig)
++        # And the other test string.
++        sig = ssh_key_sign(privkey, b"test", 0)
++        r = 0x42AB2052FD43E123F0607F115052A67DCD9C5C77
++        s = 0x183916B0230D45B9931491D4C6B0BD2FB4AAF088
++        ref_sig = ssh_string(b"ssh-dss") + ssh_string(
++            be_integer(r, 160) + be_integer(s, 160))
++        self.assertEqual(sig, ref_sig)
++
++        # A.2.2: 2048-bit DSA
++        q = 0xF2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F
++        x = 0x69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC
++        k = rfc6979('sha1', q, x, "sample")
++        self.assertEqual(int(k), 0x888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E)
++        k = rfc6979('sha256', q, x, "sample")
++        self.assertEqual(int(k), 0x8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52)
++        k = rfc6979('sha384', q, x, "sample")
++        self.assertEqual(int(k), 0xC345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920)
++        k = rfc6979('sha512', q, x, "sample")
++        self.assertEqual(int(k), 0x5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC)
++        k = rfc6979('sha1', q, x, "test")
++        self.assertEqual(int(k), 0x6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F)
++        k = rfc6979('sha256', q, x, "test")
++        self.assertEqual(int(k), 0x1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7)
++        k = rfc6979('sha384', q, x, "test")
++        self.assertEqual(int(k), 0x206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C)
++        k = rfc6979('sha512', q, x, "test")
++        self.assertEqual(int(k), 0xAFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA)
++        # The rest of the public key, for signature testing
++        p = 0x9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B
++        g = 0x5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7
++        y = 0x667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD949F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA611728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADECB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D123AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF
++        pubblob = ssh_string(b"ssh-dss") + b"".join(map(ssh2_mpint, [p,q,g,y]))
++        privblob = ssh2_mpint(x)
++        pubkey = ssh_key_new_pub('dsa', pubblob)
++        privkey = ssh_key_new_priv('dsa', pubblob, privblob)
++        sig = ssh_key_sign(privkey, b"sample", 0)
++        # Expected output using SHA-1 as the hash in nonce
++        # construction, which is how SSH does things. RFC6979 lists
++        # the following 256-bit values for r and s, but we end up only
++        # using the low 160 bits of each.
++        r = 0x3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
++        s = 0xD26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
++        ref_sig = ssh_string(b"ssh-dss") + ssh_string(
++            be_integer(r, 160) + be_integer(s, 160))
++        self.assertEqual(sig, ref_sig)
++        # And the other test string.
++        sig = ssh_key_sign(privkey, b"test", 0)
++        r = 0xC18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
++        s = 0x414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
++        ref_sig = ssh_string(b"ssh-dss") + ssh_string(
++            be_integer(r, 160) + be_integer(s, 160))
++        self.assertEqual(sig, ref_sig)
++
++        # A.2.5: ECDSA with NIST P256
++        q = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
++        x = 0xC9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721
++        k = rfc6979('sha1', q, x, "sample")
++        self.assertEqual(int(k), 0x882905F1227FD620FBF2ABF21244F0BA83D0DC3A9103DBBEE43A1FB858109DB4)
++        k = rfc6979('sha256', q, x, "sample")
++        self.assertEqual(int(k), 0xA6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60)
++        k = rfc6979('sha384', q, x, "sample")
++        self.assertEqual(int(k), 0x09F634B188CEFD98E7EC88B1AA9852D734D0BC272F7D2A47DECC6EBEB375AAD4)
++        k = rfc6979('sha512', q, x, "sample")
++        self.assertEqual(int(k), 0x5FA81C63109BADB88C1F367B47DA606DA28CAD69AA22C4FE6AD7DF73A7173AA5)
++        k = rfc6979('sha1', q, x, "test")
++        self.assertEqual(int(k), 0x8C9520267C55D6B980DF741E56B4ADEE114D84FBFA2E62137954164028632A2E)
++        k = rfc6979('sha256', q, x, "test")
++        self.assertEqual(int(k), 0xD16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0)
++        k = rfc6979('sha384', q, x, "test")
++        self.assertEqual(int(k), 0x16AEFFA357260B04B1DD199693960740066C1A8F3E8EDD79070AA914D361B3B8)
++        k = rfc6979('sha512', q, x, "test")
++        self.assertEqual(int(k), 0x6915D11632ACA3C40D5D51C08DAF9C555933819548784480E93499000D9F0B7F)
++        # The public key, for signature testing
++        Ux = 0x60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6
++        Uy = 0x7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299
++        pubblob = ssh_string(b"ecdsa-sha2-nistp256") + ssh_string(b"nistp256") + ssh_string(b'\x04' + be_integer(Ux, 256) + be_integer(Uy, 256))
++        privblob = ssh2_mpint(x)
++        pubkey = ssh_key_new_pub('p256', pubblob)
++        privkey = ssh_key_new_priv('p256', pubblob, privblob)
++        sig = ssh_key_sign(privkey, b"sample", 0)
++        # Expected output using SHA-256
++        r = 0xEFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716
++        s = 0xF7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8
++        ref_sig = ssh_string(b"ecdsa-sha2-nistp256") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
++        self.assertEqual(sig, ref_sig)
++        # And the other test string
++        sig = ssh_key_sign(privkey, b"test", 0)
++        r = 0xF1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367
++        s = 0x019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083
++        ref_sig = ssh_string(b"ecdsa-sha2-nistp256") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
++        self.assertEqual(sig, ref_sig)
++
++        # A.2.5: ECDSA with NIST P384
++        q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973
++        x = 0x6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5
++        k = rfc6979('sha1', q, x, "sample")
++        self.assertEqual(int(k), 0x4471EF7518BB2C7C20F62EAE1C387AD0C5E8E470995DB4ACF694466E6AB096630F29E5938D25106C3C340045A2DB01A7)
++        k = rfc6979('sha256', q, x, "sample")
++        self.assertEqual(int(k), 0x180AE9F9AEC5438A44BC159A1FCB277C7BE54FA20E7CF404B490650A8ACC414E375572342863C899F9F2EDF9747A9B60)
++        k = rfc6979('sha384', q, x, "sample")
++        self.assertEqual(int(k), 0x94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA2907E3E83BA95368623B8C4686915CF9)
++        k = rfc6979('sha512', q, x, "sample")
++        self.assertEqual(int(k), 0x92FC3C7183A883E24216D1141F1A8976C5B0DD797DFA597E3D7B32198BD35331A4E966532593A52980D0E3AAA5E10EC3)
++        k = rfc6979('sha1', q, x, "test")
++        self.assertEqual(int(k), 0x66CC2C8F4D303FC962E5FF6A27BD79F84EC812DDAE58CF5243B64A4AD8094D47EC3727F3A3C186C15054492E30698497)
++        k = rfc6979('sha256', q, x, "test")
++        self.assertEqual(int(k), 0x0CFAC37587532347DC3389FDC98286BBA8C73807285B184C83E62E26C401C0FAA48DD070BA79921A3457ABFF2D630AD7)
++        k = rfc6979('sha384', q, x, "test")
++        self.assertEqual(int(k), 0x015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092ADA71F4A459BC0DA98ADB95837DB8312EA)
++        k = rfc6979('sha512', q, x, "test")
++        self.assertEqual(int(k), 0x3780C4F67CB15518B6ACAE34C9F83568D2E12E47DEAB6C50A4E4EE5319D1E8CE0E2CC8A136036DC4B9C00E6888F66B6C)
++        # The public key, for signature testing
++        Ux = 0xEC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13
++        Uy = 0x8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720
++        pubblob = ssh_string(b"ecdsa-sha2-nistp384") + ssh_string(b"nistp384") + ssh_string(b'\x04' + be_integer(Ux, 384) + be_integer(Uy, 384))
++        privblob = ssh2_mpint(x)
++        pubkey = ssh_key_new_pub('p384', pubblob)
++        privkey = ssh_key_new_priv('p384', pubblob, privblob)
++        sig = ssh_key_sign(privkey, b"sample", 0)
++        # Expected output using SHA-384
++        r = 0x94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE46
++        s = 0x99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8
++        ref_sig = ssh_string(b"ecdsa-sha2-nistp384") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
++        self.assertEqual(sig, ref_sig)
++        # And the other test string
++        sig = ssh_key_sign(privkey, b"test", 0)
++        r = 0x8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DB
++        s = 0xDDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5
++        ref_sig = ssh_string(b"ecdsa-sha2-nistp384") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
++        self.assertEqual(sig, ref_sig)
++
++        # A.2.6: ECDSA with NIST P521
++        q = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409
++        x = 0x0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538
++        k = rfc6979('sha1', q, x, "sample")
++        self.assertEqual(int(k), 0x089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9)
++        k = rfc6979('sha256', q, x, "sample")
++        self.assertEqual(int(k), 0x0EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0)
++        k = rfc6979('sha384', q, x, "sample")
++        self.assertEqual(int(k), 0x1546A108BC23A15D6F21872F7DED661FA8431DDBD922D0DCDB77CC878C8553FFAD064C95A920A750AC9137E527390D2D92F153E66196966EA554D9ADFCB109C4211)
++        k = rfc6979('sha512', q, x, "sample")
++        self.assertEqual(int(k), 0x1DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F10198B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBFFD3)
++        k = rfc6979('sha1', q, x, "test")
++        self.assertEqual(int(k), 0x0BB9F2BF4FE1038CCF4DABD7139A56F6FD8BB1386561BD3C6A4FC818B20DF5DDBA80795A947107A1AB9D12DAA615B1ADE4F7A9DC05E8E6311150F47F5C57CE8B222)
++        k = rfc6979('sha256', q, x, "test")
++        self.assertEqual(int(k), 0x01DE74955EFAABC4C4F17F8E84D881D1310B5392D7700275F82F145C61E843841AF09035BF7A6210F5A431A6A9E81C9323354A9E69135D44EBD2FCAA7731B909258)
++        k = rfc6979('sha384', q, x, "test")
++        self.assertEqual(int(k), 0x1F1FC4A349A7DA9A9E116BFDD055DC08E78252FF8E23AC276AC88B1770AE0B5DCEB1ED14A4916B769A523CE1E90BA22846AF11DF8B300C38818F713DADD85DE0C88)
++        k = rfc6979('sha512', q, x, "test")
++        self.assertEqual(int(k), 0x16200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D)
++        # The public key, for signature testing
++        Ux = 0x1894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A4
++        Uy = 0x0493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5
++        pubblob = ssh_string(b"ecdsa-sha2-nistp521") + ssh_string(b"nistp521") + ssh_string(b'\x04' + be_integer(Ux, 528) + be_integer(Uy, 528))
++        privblob = ssh2_mpint(x)
++        pubkey = ssh_key_new_pub('p521', pubblob)
++        privkey = ssh_key_new_priv('p521', pubblob, privblob)
++        sig = ssh_key_sign(privkey, b"sample", 0)
++        # Expected output using SHA-512
++        r = 0x0C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA
++        s = 0x0617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A
++        ref_sig = ssh_string(b"ecdsa-sha2-nistp521") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
++        self.assertEqual(sig, ref_sig)
++        # And the other test string
++        sig = ssh_key_sign(privkey, b"test", 0)
++        r = 0x13E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D
++        s = 0x1FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3
++        ref_sig = ssh_string(b"ecdsa-sha2-nistp521") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
++        self.assertEqual(sig, ref_sig)
++
+     def testRSAVerify(self):
+         def blobs(n, e, d, p, q, iqmp):
+             pubblob = ssh_string(b"ssh-rsa") + ssh2_mpint(e) + ssh2_mpint(n)
+@@ -1393,10 +1638,10 @@ culpa qui officia deserunt mollit anim id est laborum.
+ 
+         test_keys = [
+             ('ed25519', 'AAAAC3NzaC1lZDI1NTE5AAAAIM7jupzef6CD0ps2JYxJp9IlwY49oorOseV5z5JFDFKn', 'AAAAIAf4/WRtypofgdNF2vbZOUFE1h4hvjw4tkGJZyOzI7c3', 255, b'0xf4d6e7f6f4479c23f0764ef43cea1711dbfe02aa2b5a32ff925c7c1fbf0f0db,0x27520c4592cf79e5b1ce8aa23d8ec125d2a7498c25369bd283a07fde9cbae3ce', [(0, 'AAAAC3NzaC1lZDI1NTE5AAAAQN73EqfyA4WneqDhgZ98TlRj9V5Wg8zCrMxTLJN1UtyfAnPUJDtfG/U0vOsP8PrnQxd41DDDnxrAXuqJz8rOagc=')]),
+-            ('p256', 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHkYQ0sQoq5LbJI1VMWhw3bV43TSYi3WVpqIgKcBKK91TcFFlAMZgceOHQ0xAFYcSczIttLvFu+xkcLXrRd4N7Q=', 'AAAAIQCV/1VqiCsHZm/n+bq7lHEHlyy7KFgZBEbzqYaWtbx48Q==', 256, b'nistp256,0x7918434b10a2ae4b6c923554c5a1c376d5e374d2622dd6569a8880a70128af75,0x4dc14594031981c78e1d0d3100561c49ccc8b6d2ef16efb191c2d7ad177837b4', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABIAAAAIAryzHDGi/TcCnbdxZkIYR5EGR6SNYXr/HlQRF8le+/IAAAAIERfzn6eHuBbqWIop2qL8S7DWRB3lenN1iyL10xYQPKw')]),
+-            ('p384', 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBMYK8PUtfAlJwKaBTIGEuCzH0vqOMa4UbcjrBbTbkGVSUnfo+nuC80NCdj9JJMs1jvfF8GzKLc5z8H3nZyM741/BUFjV7rEHsQFDek4KyWvKkEgKiTlZid19VukNo1q2Hg==', 'AAAAMGsfTmdB4zHdbiQ2euTSdzM6UKEOnrVjMAWwHEYvmG5qUOcBnn62fJDRJy67L+QGdg==', 384, b'nistp384,0xc60af0f52d7c0949c0a6814c8184b82cc7d2fa8e31ae146dc8eb05b4db9065525277e8fa7b82f34342763f4924cb358e,0xf7c5f06cca2dce73f07de767233be35fc15058d5eeb107b101437a4e0ac96bca90480a89395989dd7d56e90da35ab61e', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAABpAAAAMDmHrtXCADzLvkkWG/duBAHlf6B1mVvdt6F0uzXfsf8Yub8WXNUNVnYq6ovrWPzLggAAADEA9izzwoUuFcXYRJeKcRLZEGMmSDDPzUZb7oZR0UgD1jsMQXs8UfpO31Qur/FDSCRK')]),
+-            ('p521', 'AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAFrGthlKM152vu2Ghk+R7iO9/M6e+hTehNZ6+FBwof4HPkPB2/HHXj5+w5ynWyUrWiX5TI2riuJEIrJErcRH5LglADnJDX2w4yrKZ+wDHSz9lwh9p2F+B5R952es6gX3RJRkGA+qhKpKup8gKx78RMbleX8wgRtIu+4YMUnKb1edREiRg==', 'AAAAQgFh7VNJFUljWhhyAEiL0z+UPs/QggcMTd3Vv2aKDeBdCRl5di8r+BMm39L7bRzxRMEtW5NSKlDtE8MFEGdIE9khsw==', 521, b'nistp521,0x16b1ad86528cd79dafbb61a193e47b88ef7f33a7be8537a1359ebe141c287f81cf90f076fc71d78f9fb0e729d6c94ad6897e53236ae2b89108ac912b7111f92e094,0xe72435f6c38cab299fb00c74b3f65c21f69d85f81e51f79d9eb3a817dd125190603eaa12a92aea7c80ac7bf1131b95e5fcc2046d22efb860c52729bd5e75112246', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAACMAAAAQgCLgvftvwM3CUaigrW0yzmCHoYjC6GLtO+6S91itqpgMEtWPNlaTZH6QQqkgscijWdXx98dDkQao/gcAKVmOZKPXgAAAEIB1PIrsDF1y6poJ/czqujB7NSUWt31v+c2t6UA8m2gTA1ARuVJ9XBGLMdceOTB00Hi9psC2RYFLpaWREOGCeDa6ow=')]),
+-            ('dsa', 'AAAAB3NzaC1kc3MAAABhAJyWZzjVddGdyc5JPu/WPrC07vKRAmlqO6TUi49ah96iRcM7/D1aRMVAdYBepQ2mf1fsQTmvoC9KgQa79nN3kHhz0voQBKOuKI1ZAodfVOgpP4xmcXgjaA73Vjz22n4newAAABUA6l7/vIveaiA33YYv+SKcKLQaA8cAAABgbErc8QLw/WDz7mhVRZrU+9x3Tfs68j3eW+B/d7Rz1ZCqMYDk7r/F8dlBdQlYhpQvhuSBgzoFa0+qPvSSxPmutgb94wNqhHlVIUb9ZOJNloNr2lXiPP//Wu51TxXAEvAAAAAAYQCcQ9mufXtZa5RyfwT4NuLivdsidP4HRoLXdlnppfFAbNdbhxE0Us8WZt+a/443bwKnYxgif8dgxv5UROnWTngWu0jbJHpaDcTc9lRyTeSUiZZK312s/Sl7qDk3/Du7RUI=', 'AAAAFGx3ft7G8AQzFsjhle7PWardUXh3', 768, b'0x9c966738d575d19dc9ce493eefd63eb0b4eef29102696a3ba4d48b8f5a87dea245c33bfc3d5a44c54075805ea50da67f57ec4139afa02f4a8106bbf67377907873d2fa1004a3ae288d5902875f54e8293f8c66717823680ef7563cf6da7e277b,0xea5effbc8bde6a2037dd862ff9229c28b41a03c7,0x6c4adcf102f0fd60f3ee6855459ad4fbdc774dfb3af23dde5be07f77b473d590aa3180e4eebfc5f1d94175095886942f86e481833a056b4faa3ef492c4f9aeb606fde3036a8479552146fd64e24d96836bda55e23cffff5aee754f15c012f000,0x9c43d9ae7d7b596b94727f04f836e2e2bddb2274fe074682d77659e9a5f1406cd75b87113452cf1666df9aff8e376f02a76318227fc760c6fe5444e9d64e7816bb48db247a5a0dc4dcf654724de49489964adf5dacfd297ba83937fc3bbb4542', [(0, 'AAAAB3NzaC1kc3MAAAAo0T2t6dr8Qr5DK2B0ETwUa3BhxMLPjLY0ZtlOACmP/kUt3JgByLv+3g==')]),
++            ('p256', 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHkYQ0sQoq5LbJI1VMWhw3bV43TSYi3WVpqIgKcBKK91TcFFlAMZgceOHQ0xAFYcSczIttLvFu+xkcLXrRd4N7Q=', 'AAAAIQCV/1VqiCsHZm/n+bq7lHEHlyy7KFgZBEbzqYaWtbx48Q==', 256, b'nistp256,0x7918434b10a2ae4b6c923554c5a1c376d5e374d2622dd6569a8880a70128af75,0x4dc14594031981c78e1d0d3100561c49ccc8b6d2ef16efb191c2d7ad177837b4', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABIAAAAIFrd1bjr4GHfWsM9RNJ+y4Z0eVwpRRv3IvNE2moaA1x3AAAAIFWcwwCE69kS4oybMFEUP4r7qFAY8tSb1o8ItSFcSe2+')]),
++            ('p384', 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBMYK8PUtfAlJwKaBTIGEuCzH0vqOMa4UbcjrBbTbkGVSUnfo+nuC80NCdj9JJMs1jvfF8GzKLc5z8H3nZyM741/BUFjV7rEHsQFDek4KyWvKkEgKiTlZid19VukNo1q2Hg==', 'AAAAMGsfTmdB4zHdbiQ2euTSdzM6UKEOnrVjMAWwHEYvmG5qUOcBnn62fJDRJy67L+QGdg==', 384, b'nistp384,0xc60af0f52d7c0949c0a6814c8184b82cc7d2fa8e31ae146dc8eb05b4db9065525277e8fa7b82f34342763f4924cb358e,0xf7c5f06cca2dce73f07de767233be35fc15058d5eeb107b101437a4e0ac96bca90480a89395989dd7d56e90da35ab61e', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAABoAAAAMFqCJ+gBP4GGc7yCy9F5e4EjkDlvYBYsYWMYFg3Md/ml7Md8pIrN7I0+8bFb99rZjQAAADAsM2kI+QOcgK+oVDaP0qkLRRbWDO1dSU5I2YfETyHVLYFNdRmgdWo6002XTO9jAsk=')]),
++            ('p521', 'AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAFrGthlKM152vu2Ghk+R7iO9/M6e+hTehNZ6+FBwof4HPkPB2/HHXj5+w5ynWyUrWiX5TI2riuJEIrJErcRH5LglADnJDX2w4yrKZ+wDHSz9lwh9p2F+B5R952es6gX3RJRkGA+qhKpKup8gKx78RMbleX8wgRtIu+4YMUnKb1edREiRg==', 'AAAAQgFh7VNJFUljWhhyAEiL0z+UPs/QggcMTd3Vv2aKDeBdCRl5di8r+BMm39L7bRzxRMEtW5NSKlDtE8MFEGdIE9khsw==', 521, b'nistp521,0x16b1ad86528cd79dafbb61a193e47b88ef7f33a7be8537a1359ebe141c287f81cf90f076fc71d78f9fb0e729d6c94ad6897e53236ae2b89108ac912b7111f92e094,0xe72435f6c38cab299fb00c74b3f65c21f69d85f81e51f79d9eb3a817dd125190603eaa12a92aea7c80ac7bf1131b95e5fcc2046d22efb860c52729bd5e75112246', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAACLAAAAQVBkbaCKivgvc+68CULCdPayjzRUYZdj1G2pLyiPWTdmJKVKF/W1oDAtjMZlP53tqCpGxDdrLoJH2A39k6g5MgNjAAAAQgGrNcesPBw/HMopBQ1JqOG1cSlAzjiFT34FvM68ZhdIjbQ0eHFuYs97RekQ8dpxmkuM88e63ATbZy4yDX06pKgmuQ==')]),
++            ('dsa', 'AAAAB3NzaC1kc3MAAABhAJyWZzjVddGdyc5JPu/WPrC07vKRAmlqO6TUi49ah96iRcM7/D1aRMVAdYBepQ2mf1fsQTmvoC9KgQa79nN3kHhz0voQBKOuKI1ZAodfVOgpP4xmcXgjaA73Vjz22n4newAAABUA6l7/vIveaiA33YYv+SKcKLQaA8cAAABgbErc8QLw/WDz7mhVRZrU+9x3Tfs68j3eW+B/d7Rz1ZCqMYDk7r/F8dlBdQlYhpQvhuSBgzoFa0+qPvSSxPmutgb94wNqhHlVIUb9ZOJNloNr2lXiPP//Wu51TxXAEvAAAAAAYQCcQ9mufXtZa5RyfwT4NuLivdsidP4HRoLXdlnppfFAbNdbhxE0Us8WZt+a/443bwKnYxgif8dgxv5UROnWTngWu0jbJHpaDcTc9lRyTeSUiZZK312s/Sl7qDk3/Du7RUI=', 'AAAAFGx3ft7G8AQzFsjhle7PWardUXh3', 768, b'0x9c966738d575d19dc9ce493eefd63eb0b4eef29102696a3ba4d48b8f5a87dea245c33bfc3d5a44c54075805ea50da67f57ec4139afa02f4a8106bbf67377907873d2fa1004a3ae288d5902875f54e8293f8c66717823680ef7563cf6da7e277b,0xea5effbc8bde6a2037dd862ff9229c28b41a03c7,0x6c4adcf102f0fd60f3ee6855459ad4fbdc774dfb3af23dde5be07f77b473d590aa3180e4eebfc5f1d94175095886942f86e481833a056b4faa3ef492c4f9aeb606fde3036a8479552146fd64e24d96836bda55e23cffff5aee754f15c012f000,0x9c43d9ae7d7b596b94727f04f836e2e2bddb2274fe074682d77659e9a5f1406cd75b87113452cf1666df9aff8e376f02a76318227fc760c6fe5444e9d64e7816bb48db247a5a0dc4dcf654724de49489964adf5dacfd297ba83937fc3bbb4542', [(0, 'AAAAB3NzaC1kc3MAAAAoyCVHLG2QqdMx7NiCWaThx6tDA5mf7UGl+8By0IzmSldBujsGKNs20g==')]),
+             ('rsa', 'AAAAB3NzaC1yc2EAAAABJQAAAGEA2ChX9+mQD/NULFkBrxLDI8d1PHgrInC2u11U4Grqu4oVzKvnFROo6DZeCu6sKhFJE5CnIL7evAthQ9hkXVHDhQ7xGVauzqyHGdIU4/pHRScAYWBv/PZOlNMrSoP/PP91', 'AAAAYCMNdgyGvWpez2EjMLSbQj0nQ3GW8jzvru3zdYwtA3hblNUU9QpWNxDmOMOApkwCzUgsdIPsBxctIeWT2h+v8sVOH+d66LCaNmNR0lp+dQ+iXM67hcGNuxJwRdMupD9ZbQAAADEA7XMrMAb4WuHaFafoTfGrf6Jhdy9Ozjqi1fStuld7Nj9JkoZluiL2dCwIrxqOjwU5AAAAMQDpC1gYiGVSPeDRILr2oxREtXWOsW+/ZZTfZNX7lvoufnp+qvwZPqvZnXQFHyZ8qB0AAAAwQE0wx8TPgcvRVEVv8Wt+o1NFlkJZayWD5hqpe/8AqUMZbqfg/aiso5mvecDLFgfV', 768, b'0x25,0xd82857f7e9900ff3542c5901af12c323c7753c782b2270b6bb5d54e06aeabb8a15ccabe71513a8e8365e0aeeac2a11491390a720bedebc0b6143d8645d51c3850ef11956aeceac8719d214e3fa4745270061606ffcf64e94d32b4a83ff3cff75', [(0, 'AAAAB3NzaC1yc2EAAABgrLSC4635RCsH1b3en58NqLsrH7PKRZyb3YmRasOyr8xIZMSlKZyxNg+kkn9OgBzbH9vChafzarfHyVwtJE2IMt3uwxTIWjwgwH19tc16k8YmNfDzujmB6OFOArmzKJgJ'), (2, 'AAAADHJzYS1zaGEyLTI1NgAAAGAJszr04BZlVBEdRLGOv1rTJwPiid/0I6/MycSH+noahvUH2wjrRhqDuv51F4nKYF5J9vBsEotTSrSF/cnLsliCdvVkEfmvhdcn/jx2LWF2OfjqETiYSc69Dde9UFmAPds='), (4, 'AAAADHJzYS1zaGEyLTUxMgAAAGBxfZ2m+WjvZ5YV5RFm0+w84CgHQ95EPndoAha0PCMc93AUHBmoHnezsJvEGuLovUm35w/0POmUNHI7HzM9PECwXrV0rO6N/HL/oFxJuDYmeqCpjMVmN8QXka+yxs2GEtA=')]),
+         ]
+ 
+diff --git a/testcrypt.h b/testcrypt.h
+index 690bfa2b..2cd6ddfb 100644
+--- a/testcrypt.h
++++ b/testcrypt.h
+@@ -157,6 +157,11 @@ FUNC2(void, ssh_key_openssh_blob, val_key, out_val_string_binarysink)
+ FUNC1(val_string_asciz, ssh_key_cache_str, val_key)
+ FUNC2(uint, ssh_key_public_bits, keyalg, val_string_ptrlen)
+ 
++/*
++ * DSA nonce generation.
++ */
++FUNC4(opt_val_mpint, rfc6979, hashalg, val_mpint, val_mpint, val_string_ptrlen)
++
+ /*
+  * The ssh_cipher abstraction. The in-place encrypt and decrypt
+  * functions are wrapped to replace them with versions that take one
+diff --git a/testsc.c b/testsc.c
+index 7127032e..04bd430a 100644
+--- a/testsc.c
++++ b/testsc.c
+@@ -312,6 +312,8 @@ VOLATILE_WRAPPED_DEFN(static, size_t, looplimit, (size_t x))
+     X(ecc_edwards_eq)                           \
+     X(ecc_edwards_get_affine)                   \
+     X(ecc_edwards_decompress)                   \
++    X(rfc6979_setup)                            \
++    X(rfc6979_attempt)                          \
+     CIPHERS(CIPHER_TESTLIST, X)                 \
+     MACS(MAC_TESTLIST, X)                       \
+     HASHES(HASH_TESTLIST, X)                    \
+@@ -1377,6 +1379,64 @@ static void test_hash(const ssh_hashalg *halg)
+     ssh_hash_free(h);
+ }
+ 
++static void test_rfc6979_setup(void)
++{
++    mp_int *q = mp_new(512);
++    mp_int *x = mp_new(512);
++
++    strbuf *message = strbuf_new();
++    strbuf_append(message, 123);
++
++    RFC6979 *s = rfc6979_new(&ssh_sha256, q, x);
++
++    for (size_t i = 0; i < looplimit(20); i++) {
++        random_read(message->u, message->len);
++        mp_random_fill(q);
++        mp_random_fill(x);
++
++        log_start();
++        rfc6979_setup(s, ptrlen_from_strbuf(message));
++        log_end();
++    }
++
++    rfc6979_free(s);
++    mp_free(q);
++    mp_free(x);
++    strbuf_free(message);
++}
++
++static void test_rfc6979_attempt(void)
++{
++    mp_int *q = mp_new(512);
++    mp_int *x = mp_new(512);
++
++    strbuf *message = strbuf_new();
++    strbuf_append(message, 123);
++
++    RFC6979 *s = rfc6979_new(&ssh_sha256, q, x);
++
++    for (size_t i = 0; i < looplimit(5); i++) {
++        random_read(message->u, message->len);
++        mp_random_fill(q);
++        mp_random_fill(x);
++
++        rfc6979_setup(s, ptrlen_from_strbuf(message));
++
++        for (size_t j = 0; j < looplimit(10); j++) {
++            log_start();
++            RFC6979Result result = rfc6979_attempt(s);
++            mp_free(result.k);
++            log_end();
++        }
++    }
++
++    rfc6979_free(s);
++    mp_free(q);
++    mp_free(x);
++    strbuf_free(message);
++}
++
++
+ #define HASH_TESTFN(Y_unused, hash)                             \
+     static void test_hash_##hash(void) { test_hash(&hash); }
+ HASHES(HASH_TESTFN, Y_unused)
diff -Nru putty-0.74/debian/patches/series putty-0.74/debian/patches/series
--- putty-0.74/debian/patches/series	2023-12-21 16:54:36.000000000 +0000
+++ putty-0.74/debian/patches/series	2024-07-16 10:13:59.000000000 +0000
@@ -3,3 +3,6 @@
 PTRLEN_DECL_LITERAL.patch
 add_to_commasep_pl.patch
 strict-kex.patch
+0006-Refactor-the-ssh_hash-vtable.-NFC.patch
+0007-Add-an-extra-HMAC-constructor-function.patch
+0008-Switch-to-RFC-6979-for-DSA-nonce-generation.patch
diff -Nru putty-0.74/debian/putty.NEWS putty-0.74/debian/putty.NEWS
--- putty-0.74/debian/putty.NEWS	1970-01-01 00:00:00.000000000 +0000
+++ putty-0.74/debian/putty.NEWS	2024-07-16 09:42:13.000000000 +0000
@@ -0,0 +1,29 @@
+putty (0.74-1+deb11u2) bullseye; urgency=high
+
+   Previous putty versions were affected by CVE-2024-31497,
+   a critical vulnerability that generates signatures
+   from ECDSA private keys that use the NIST P521 curve.
+   The effect of the vulnerability is to compromise the private key.
+
+   An attacker in possession of a few dozen signed messages and the public
+   key has enough information to deduce the private key, and then forge
+   signatures as if they were made by the victim. This allows the attacker
+   to (for instance) log in to any servers the victim uses that key for.
+   To obtain these signatures, an attacker need only briefly compromise
+   any server the victim uses the key to authenticate to.
+
+   Therefore, if you have any NIST-P521 ECDSA key, we strongly recommend
+   you to replace it with a freshly new created with a fixed version of
+   putty. Then, to revoke the old public key and remove it from any
+   machine where you use it to login into, so that a signature
+   from the compromised key has no value any more.
+
+   The only affected key type is 521-bit ECDSA. That is, a key that appears
+   in Windows PuTTYgen with ecdsa-sha2-nistp521 at the start of the
+   'Key fingerprint' box, or is described as 'NIST p521', or has an id
+   starting ecdsa-sha2-nistp521 in the SSH protocol or the key file.
+   Other sizes of ECDSA, and other key algorithms, are unaffected.
+   In particular, Ed25519 is not affected. 
+   
+ -- Bastien Roucari??s <ro...@debian.org>  Mon, 29 Apr 2024 16:55:15 +0000
+
diff -Nru putty-0.74/debian/putty-tools.NEWS putty-0.74/debian/putty-tools.NEWS
--- putty-0.74/debian/putty-tools.NEWS	1970-01-01 00:00:00.000000000 +0000
+++ putty-0.74/debian/putty-tools.NEWS	2024-07-16 09:42:13.000000000 +0000
@@ -0,0 +1,29 @@
+putty (0.74-1+deb11u2) bullseye; urgency=high
+
+   Previous putty versions were affected by CVE-2024-31497,
+   a critical vulnerability that generates signatures
+   from ECDSA private keys that use the NIST P521 curve.
+   The effect of the vulnerability is to compromise the private key.
+
+   An attacker in possession of a few dozen signed messages and the public
+   key has enough information to deduce the private key, and then forge
+   signatures as if they were made by the victim. This allows the attacker
+   to (for instance) log in to any servers the victim uses that key for.
+   To obtain these signatures, an attacker need only briefly compromise
+   any server the victim uses the key to authenticate to.
+
+   Therefore, if you have any NIST-P521 ECDSA key, we strongly recommend
+   you to replace it with a freshly new created with a fixed version of
+   putty. Then, to revoke the old public key and remove it from any
+   machine where you use it to login into, so that a signature
+   from the compromised key has no value any more.
+
+   The only affected key type is 521-bit ECDSA. That is, a key that appears
+   in Windows PuTTYgen with ecdsa-sha2-nistp521 at the start of the
+   'Key fingerprint' box, or is described as 'NIST p521', or has an id
+   starting ecdsa-sha2-nistp521 in the SSH protocol or the key file.
+   Other sizes of ECDSA, and other key algorithms, are unaffected.
+   In particular, Ed25519 is not affected. 
+   
+ -- Bastien Roucari??s <ro...@debian.org>  Mon, 29 Apr 2024 16:55:15 +0000
+

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to