Start a file of 'unsafe' mp_int functions.

Unlike the ones in mpint.c proper, these are not intended to respect
the constant-time guarantees. They're going to be the kind of thing
you use in key generation, which is too random to be constant-time in
any case.

I've arranged several precautions to try to make sure these functions
don't accidentally get linked into the main SSH application, only into
key generators:

 - declare them in a separate header with "unsafe" in the name

 - put "unsafe" in the name of every actual function

 - don't even link the mpunsafe.c translation unit into PuTTY proper

 - in fact, define global symbols of the same name in that file and
   the SSH client code, so that there will be a link failure if we
   ever try to do it by accident

The initial contents of the new source file consist of the subroutine
mp_mod_short() that previously lived in sshprime.c (and was not in
mpint.c proper precisely because it was unsafe). While I'm here, I've
turned it into mp_unsafe_mod_integer() and let it take a modulus of up
to 32 bits instead of 16.

Also added some obviously useful functions to shrink an mpint to the
smallest physical size that can hold the contained number (rather like
bn_restore_invariant in the old Bignum system), which I expect to be
using shortly.
This commit is contained in:
Simon Tatham 2020-02-20 18:02:15 +00:00
Родитель 9af72ca1e8
Коммит dec79cf152
7 изменённых файлов: 117 добавлений и 21 удалений

2
Recipe
Просмотреть файл

@ -282,7 +282,7 @@ UXSSH = SSH uxnoise uxagentc uxgss uxshare
SFTP = psftpcommon sftp sftpcommon logging cmdline SFTP = psftpcommon sftp sftpcommon logging cmdline
# Components of the prime-generation system. # Components of the prime-generation system.
SSHPRIME = sshprime smallprimes SSHPRIME = sshprime smallprimes mpunsafe
# Miscellaneous objects appearing in all the utilities, or all the # Miscellaneous objects appearing in all the utilities, or all the
# network ones, or the Unix or Windows subsets of those in turn. # network ones, or the Unix or Windows subsets of those in turn.

Просмотреть файл

@ -33,7 +33,7 @@ static inline BignumInt mp_word(mp_int *x, size_t i)
return i < x->nw ? x->w[i] : 0; return i < x->nw ? x->w[i] : 0;
} }
static mp_int *mp_make_sized(size_t nw) mp_int *mp_make_sized(size_t nw)
{ {
mp_int *x = snew_plus(mp_int, nw * sizeof(BignumInt)); mp_int *x = snew_plus(mp_int, nw * sizeof(BignumInt));
assert(nw); /* we outlaw the zero-word mp_int */ assert(nw); /* we outlaw the zero-word mp_int */

Просмотреть файл

@ -319,3 +319,6 @@ struct MontyContext {
*/ */
mp_int *scratch; mp_int *scratch;
}; };
/* Functions shared between mpint.c and mpunsafe.c */
mp_int *mp_make_sized(size_t nw);

57
mpunsafe.c Normal file
Просмотреть файл

@ -0,0 +1,57 @@
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include "defs.h"
#include "misc.h"
#include "puttymem.h"
#include "mpint.h"
#include "mpint_i.h"
/*
* This global symbol is also defined in ssh2kex-client.c, to ensure
* that these unsafe non-constant-time mp_int functions can't end up
* accidentally linked in to any PuTTY tool that actually makes an SSH
* client connection.
*
* (Only _client_ connections, however. Uppity, being a test server
* only, is exempt.)
*/
const int deliberate_symbol_clash = 12345;
static size_t mp_unsafe_words_needed(mp_int *x)
{
size_t words = x->nw;
while (words > 1 && !x->w[words-1])
words--;
return words;
}
mp_int *mp_unsafe_shrink(mp_int *x)
{
x->nw = mp_unsafe_words_needed(x);
/* This potentially leaves some allocated words between the new
* and old values of x->nw, which won't be wiped by mp_free now
* that x->nw doesn't mention that they exist. But we've just
* checked they're all zero, so we don't need to wipe them now
* either. */
return x;
}
mp_int *mp_unsafe_copy(mp_int *x)
{
mp_int *copy = mp_make_sized(mp_unsafe_words_needed(x));
mp_copy_into(copy, x);
return copy;
}
uint32_t mp_unsafe_mod_integer(mp_int *x, uint32_t modulus)
{
uint64_t accumulator = 0;
for (size_t i = mp_max_bytes(x); i-- > 0 ;) {
accumulator = 0x100 * accumulator + mp_get_byte(x, i);
accumulator %= modulus;
}
return accumulator;
}

46
mpunsafe.h Normal file
Просмотреть файл

@ -0,0 +1,46 @@
/*
* mpunsafe.h: functions that deal with mp_ints in ways that are *not*
* expected to be constant-time. Used during key generation, in which
* constant run time is a lost cause anyway.
*
* These functions are in a separate header, so that you can easily
* check that you're not calling them in the wrong context. They're
* also defined in a separate source file, which is only linked in to
* the key generation tools. Furthermore, that source file also
* defines a global symbol that intentionally conflicts with one
* defined in the SSH client code, so that any attempt to put these
* functions into the same binary as the live SSH client
* implementation will cause a link-time failure. They should only be
* linked into PuTTYgen and auxiliary test programs.
*
* Also, just in case those precautions aren't enough, all the unsafe
* functions have 'unsafe' in the name.
*/
#ifndef PUTTY_MPINT_UNSAFE_H
#define PUTTY_MPINT_UNSAFE_H
/*
* The most obvious unsafe thing you want to do with an mp_int is to
* get rid of leading zero words in its representation, so that its
* nominal size is as close as possible to its true size, and you
* don't waste any time processing it.
*
* mp_unsafe_shrink performs this operation in place, mutating the
* size field of the mp_int it's given. It returns the same pointer it
* was given.
*
* mp_unsafe_copy leaves the original mp_int alone and makes a new one
* with the minimal size.
*/
mp_int *mp_unsafe_shrink(mp_int *m);
mp_int *mp_unsafe_copy(mp_int *m);
/*
* Compute the residue of x mod m. This is implemented in the most
* obvious way using the C % operator, which won't be constant-time on
* many C implementations.
*/
uint32_t mp_unsafe_mod_integer(mp_int *x, uint32_t m);
#endif /* PUTTY_MPINT_UNSAFE_H */

Просмотреть файл

@ -13,6 +13,12 @@
#include "ssh2transport.h" #include "ssh2transport.h"
#include "mpint.h" #include "mpint.h"
/*
* Another copy of the symbol defined in mpunsafe.c. See the comment
* there.
*/
const int deliberate_symbol_clash = 12345;
void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted) void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
{ {
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */ PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */

Просмотреть файл

@ -5,6 +5,7 @@
#include <assert.h> #include <assert.h>
#include "ssh.h" #include "ssh.h"
#include "mpint.h" #include "mpint.h"
#include "mpunsafe.h"
#include "sshkeygen.h" #include "sshkeygen.h"
/* /*
@ -108,23 +109,6 @@
* but 1s.) * but 1s.)
*/ */
static unsigned short mp_mod_short(mp_int *x, unsigned short modulus)
{
/*
* This function lives here rather than in mpint.c partly because
* this is the only place it's needed, but mostly because it
* doesn't pay careful attention to constant running time, since
* as far as I can tell that's a lost cause for key generation
* anyway.
*/
unsigned accumulator = 0;
for (size_t i = mp_max_bytes(x); i-- > 0 ;) {
accumulator = 0x100 * accumulator + mp_get_byte(x, i);
accumulator %= modulus;
}
return accumulator;
}
/* /*
* Generate a prime. We can deal with various extra properties of * Generate a prime. We can deal with various extra properties of
* the prime: * the prime:
@ -204,9 +188,9 @@ mp_int *primegen(
* we're incrementing by multiples of factor). */ * we're incrementing by multiples of factor). */
unsigned long residues[NSMALLPRIMES + 1], multipliers[NSMALLPRIMES + 1]; unsigned long residues[NSMALLPRIMES + 1], multipliers[NSMALLPRIMES + 1];
for (size_t i = 0; i < lenof(moduli); i++) { for (size_t i = 0; i < lenof(moduli); i++) {
residues[i] = mp_mod_short(p, moduli[i]); residues[i] = mp_unsafe_mod_integer(p, moduli[i]);
if (factor) if (factor)
multipliers[i] = mp_mod_short(factor, moduli[i]); multipliers[i] = mp_unsafe_mod_integer(factor, moduli[i]);
else else
multipliers[i] = 1; multipliers[i] = 1;
} }