2004-01-22 19:15:32 +00:00
|
|
|
/*
|
|
|
|
* cmdgen.c - command-line form of PuTTYgen
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <time.h>
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
2004-01-22 19:15:32 +00:00
|
|
|
|
|
|
|
#include "putty.h"
|
|
|
|
#include "ssh.h"
|
2020-02-23 15:29:40 +00:00
|
|
|
#include "sshkeygen.h"
|
cmdgen: add a --dump option.
Also spelled '-O text', this takes a public or private key as input,
and produces on standard output a dump of all the actual numbers
involved in the key: the exponent and modulus for RSA, the p,q,g,y
parameters for DSA, the affine x and y coordinates of the public
elliptic curve point for ECC keys, and all the extra bits and pieces
in the private keys too.
Partly I expect this to be useful to me for debugging: I've had to
paste key files a few too many times through base64 decoders and hex
dump tools, then manually decode SSH marshalling and paste the result
into the Python REPL to get an integer object. Now I should be able to
get _straight_ to text I can paste into Python.
But also, it's a way that other applications can use the key
generator: if you need to generate, say, an RSA key in some format I
don't support (I've recently heard of an XML-based one, for example),
then you can run 'puttygen -t rsa --dump' and have it print the
elements of a freshly generated keypair on standard output, and then
all you have to do is understand the output format.
2020-02-17 19:53:19 +00:00
|
|
|
#include "mpint.h"
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2020-02-29 17:11:01 +00:00
|
|
|
static FILE *progress_fp = NULL;
|
|
|
|
static bool linear_progress_phase;
|
|
|
|
static unsigned last_progress_col;
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2020-02-29 17:11:01 +00:00
|
|
|
static ProgressPhase cmdgen_progress_add_linear(
|
|
|
|
ProgressReceiver *prog, double c)
|
|
|
|
{
|
|
|
|
ProgressPhase ph = { .n = 0 };
|
|
|
|
return ph;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ProgressPhase cmdgen_progress_add_probabilistic(
|
|
|
|
ProgressReceiver *prog, double c, double p)
|
|
|
|
{
|
|
|
|
ProgressPhase ph = { .n = 1 };
|
|
|
|
return ph;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cmdgen_progress_start_phase(ProgressReceiver *prog,
|
|
|
|
ProgressPhase p)
|
|
|
|
{
|
|
|
|
linear_progress_phase = (p.n == 0);
|
|
|
|
last_progress_col = 0;
|
|
|
|
}
|
|
|
|
static void cmdgen_progress_report(ProgressReceiver *prog, double p)
|
|
|
|
{
|
|
|
|
unsigned new_col = p * 64 + 0.5;
|
|
|
|
for (; last_progress_col < new_col; last_progress_col++)
|
|
|
|
fputc('+', progress_fp);
|
|
|
|
}
|
2020-02-23 15:29:40 +00:00
|
|
|
static void cmdgen_progress_report_attempt(ProgressReceiver *prog)
|
2004-01-22 19:15:32 +00:00
|
|
|
{
|
2020-02-23 15:29:40 +00:00
|
|
|
if (progress_fp) {
|
|
|
|
fputc('+', progress_fp);
|
|
|
|
fflush(progress_fp);
|
2020-02-23 15:29:40 +00:00
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
2020-02-23 15:29:40 +00:00
|
|
|
static void cmdgen_progress_report_phase_complete(ProgressReceiver *prog)
|
2020-02-29 16:32:16 +00:00
|
|
|
{
|
2020-02-29 17:11:01 +00:00
|
|
|
if (linear_progress_phase)
|
|
|
|
cmdgen_progress_report(prog, 1.0);
|
2020-02-23 15:29:40 +00:00
|
|
|
if (progress_fp) {
|
|
|
|
fputc('\n', progress_fp);
|
|
|
|
fflush(progress_fp);
|
|
|
|
}
|
2020-02-29 16:32:16 +00:00
|
|
|
}
|
2020-02-23 15:29:40 +00:00
|
|
|
|
2020-02-23 15:29:40 +00:00
|
|
|
static const ProgressReceiverVtable cmdgen_progress_vt = {
|
Change vtable defs to use C99 designated initialisers.
This is a sweeping change applied across the whole code base by a spot
of Emacs Lisp. Now, everywhere I declare a vtable filled with function
pointers (and the occasional const data member), all the members of
the vtable structure are initialised by name using the '.fieldname =
value' syntax introduced in C99.
We were already using this syntax for a handful of things in the new
key-generation progress report system, so it's not new to the code
base as a whole.
The advantage is that now, when a vtable only declares a subset of the
available fields, I can initialise the rest to NULL or zero just by
leaving them out. This is most dramatic in a couple of the outlying
vtables in things like psocks (which has a ConnectionLayerVtable
containing only one non-NULL method), but less dramatically, it means
that the new 'flags' field in BackendVtable can be completely left out
of every backend definition except for the SUPDUP one which defines it
to a nonzero value. Similarly, the test_for_upstream method only used
by SSH doesn't have to be mentioned in the rest of the backends;
network Plugs for listening sockets don't have to explicitly null out
'receive' and 'sent', and vice versa for 'accepting', and so on.
While I'm at it, I've normalised the declarations so they don't use
the unnecessarily verbose 'struct' keyword. Also a handful of them
weren't const; now they are.
2020-03-10 21:06:29 +00:00
|
|
|
.add_linear = cmdgen_progress_add_linear,
|
|
|
|
.add_probabilistic = cmdgen_progress_add_probabilistic,
|
|
|
|
.ready = null_progress_ready,
|
|
|
|
.start_phase = cmdgen_progress_start_phase,
|
|
|
|
.report = cmdgen_progress_report,
|
|
|
|
.report_attempt = cmdgen_progress_report_attempt,
|
|
|
|
.report_phase_complete = cmdgen_progress_report_phase_complete,
|
2020-02-23 15:29:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static ProgressReceiver cmdgen_progress = { .vt = &cmdgen_progress_vt };
|
|
|
|
|
2004-01-22 19:15:32 +00:00
|
|
|
/*
|
|
|
|
* Stubs to let everything else link sensibly.
|
|
|
|
*/
|
|
|
|
char *x_get_default(const char *key)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
void sk_cleanup(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void showversion(void)
|
|
|
|
{
|
2017-01-21 14:55:53 +00:00
|
|
|
char *buildinfo_text = buildinfo("\n");
|
2017-02-11 20:12:55 +00:00
|
|
|
printf("puttygen: %s\n%s\n", ver, buildinfo_text);
|
2017-01-21 14:55:53 +00:00
|
|
|
sfree(buildinfo_text);
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
void usage(bool standalone)
|
2004-01-22 19:15:32 +00:00
|
|
|
{
|
2017-02-11 20:12:55 +00:00
|
|
|
fprintf(standalone ? stderr : stdout,
|
2019-09-08 19:29:00 +00:00
|
|
|
"Usage: puttygen ( keyfile | -t type [ -b bits ] )\n"
|
|
|
|
" [ -C comment ] [ -P ] [ -q ]\n"
|
|
|
|
" [ -o output-keyfile ] [ -O type | -l | -L"
|
|
|
|
" | -p ]\n");
|
2006-06-17 13:01:04 +00:00
|
|
|
if (standalone)
|
2019-09-08 19:29:00 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"Use \"puttygen --help\" for more detail.\n");
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void help(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Help message is an extended version of the usage message. So
|
|
|
|
* start with that, plus a version heading.
|
|
|
|
*/
|
2017-02-11 20:12:55 +00:00
|
|
|
printf("PuTTYgen: key generator and converter for the PuTTY tools\n"
|
2019-09-08 19:29:00 +00:00
|
|
|
"%s\n", ver);
|
2018-10-29 19:50:29 +00:00
|
|
|
usage(false);
|
2020-03-02 07:05:19 +00:00
|
|
|
printf(" -t specify key type when generating:\n"
|
|
|
|
" eddsa, ecdsa, rsa, dsa, rsa1 use with -b\n"
|
2020-03-02 07:09:08 +00:00
|
|
|
" ed25519, ed448 special cases of eddsa\n"
|
2019-09-08 19:29:00 +00:00
|
|
|
" -b specify number of bits when generating key\n"
|
|
|
|
" -C change or specify key comment\n"
|
|
|
|
" -P change key passphrase\n"
|
|
|
|
" -q quiet: do not display progress bar\n"
|
|
|
|
" -O specify output type:\n"
|
|
|
|
" private output PuTTY private key format\n"
|
|
|
|
" private-openssh export OpenSSH private key\n"
|
|
|
|
" private-openssh-new export OpenSSH private key "
|
2017-02-11 20:12:55 +00:00
|
|
|
"(force new format)\n"
|
2019-09-08 19:29:00 +00:00
|
|
|
" private-sshcom export ssh.com private key\n"
|
|
|
|
" public RFC 4716 / ssh.com public key\n"
|
|
|
|
" public-openssh OpenSSH public key\n"
|
|
|
|
" fingerprint output the key fingerprint\n"
|
cmdgen: add a --dump option.
Also spelled '-O text', this takes a public or private key as input,
and produces on standard output a dump of all the actual numbers
involved in the key: the exponent and modulus for RSA, the p,q,g,y
parameters for DSA, the affine x and y coordinates of the public
elliptic curve point for ECC keys, and all the extra bits and pieces
in the private keys too.
Partly I expect this to be useful to me for debugging: I've had to
paste key files a few too many times through base64 decoders and hex
dump tools, then manually decode SSH marshalling and paste the result
into the Python REPL to get an integer object. Now I should be able to
get _straight_ to text I can paste into Python.
But also, it's a way that other applications can use the key
generator: if you need to generate, say, an RSA key in some format I
don't support (I've recently heard of an XML-based one, for example),
then you can run 'puttygen -t rsa --dump' and have it print the
elements of a freshly generated keypair on standard output, and then
all you have to do is understand the output format.
2020-02-17 19:53:19 +00:00
|
|
|
" text output the key components as "
|
|
|
|
"'name=0x####'\n"
|
2019-09-08 19:29:00 +00:00
|
|
|
" -o specify output file\n"
|
|
|
|
" -l equivalent to `-O fingerprint'\n"
|
|
|
|
" -L equivalent to `-O public-openssh'\n"
|
|
|
|
" -p equivalent to `-O public'\n"
|
2020-02-23 12:02:19 +00:00
|
|
|
" --dump equivalent to `-O text'\n"
|
2021-02-22 17:56:02 +00:00
|
|
|
" --reencrypt load a key and save it with fresh "
|
|
|
|
"encryption\n"
|
2019-09-08 19:29:00 +00:00
|
|
|
" --old-passphrase file\n"
|
|
|
|
" specify file containing old key passphrase\n"
|
|
|
|
" --new-passphrase file\n"
|
|
|
|
" specify file containing new key passphrase\n"
|
|
|
|
" --random-device device\n"
|
|
|
|
" specify device to read entropy from (e.g. /dev/urandom)\n"
|
2020-03-01 20:37:09 +00:00
|
|
|
" --primes <type> select prime-generation method:\n"
|
|
|
|
" probable conventional probabilistic prime finding\n"
|
|
|
|
" proven numbers that have been proven to be prime\n"
|
|
|
|
" proven-even also try harder for an even distribution\n"
|
RSA generation: option to generate strong primes.
A 'strong' prime, as defined by the Handbook of Applied Cryptography,
is a prime p such that each of p-1 and p+1 has a large prime factor,
and that the large factor q of p-1 is such that q-1 in turn _also_ has
a large prime factor.
HoAC says that making your RSA key using primes of this form defeats
some factoring algorithms - but there are other faster algorithms to
which it makes no difference. So this is probably not a useful
precaution in practice. However, it has been recommended in the past
by some official standards, and it's easy to implement given the new
general facility in PrimeCandidateSource that lets you ask for your
prime to satisfy an arbitrary modular congruence. (And HoAC also says
there's no particular reason _not_ to use strong primes.) So I provide
it as an option, just in case anyone wants to select it.
The change to the key generation algorithm is entirely in sshrsag.c,
and is neatly independent of the prime-generation system in use. If
you're using Maurer provable prime generation, then the known factor q
of p-1 can be used to help certify p, and the one for q-1 to help with
q in turn; if you switch to probabilistic prime generation then you
still get an RSA key with the right structure, except that every time
the definition says 'prime factor' you just append '(probably)'.
(The probabilistic version of this procedure is described as 'Gordon's
algorithm' in HoAC section 4.4.2.)
2020-03-02 06:52:09 +00:00
|
|
|
" --strong-rsa use \"strong\" primes as RSA key factors\n"
|
2021-02-22 18:13:12 +00:00
|
|
|
" --ppk-param <key>=<value>[,<key>=<value>,...]\n"
|
|
|
|
" specify parameters when writing PuTTY private key file "
|
|
|
|
"format:\n"
|
|
|
|
" version PPK format version (min 2, max 3, "
|
|
|
|
"default 3)\n"
|
2021-02-23 18:26:50 +00:00
|
|
|
" kdf key derivation function (argon2id, "
|
|
|
|
"argon2i, argon2d)\n"
|
2021-04-19 16:55:50 +00:00
|
|
|
" memory Kbyte of memory to use in passphrase "
|
|
|
|
"hash\n"
|
|
|
|
" (default 8192)\n"
|
2021-02-22 18:13:12 +00:00
|
|
|
" time approx milliseconds to hash for "
|
|
|
|
"(default 100)\n"
|
2021-02-23 18:26:50 +00:00
|
|
|
" passes number of hash passes to run "
|
2021-02-22 18:13:12 +00:00
|
|
|
"(alternative to 'time')\n"
|
|
|
|
" parallelism number of parallelisable threads in the "
|
|
|
|
"hash function\n"
|
|
|
|
" (default 1)\n"
|
2019-09-08 19:29:00 +00:00
|
|
|
);
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
static bool move(char *from, char *to)
|
2004-01-22 19:15:32 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = rename(from, to);
|
|
|
|
if (ret) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* This OS may require us to remove the original file first.
|
|
|
|
*/
|
|
|
|
remove(to);
|
|
|
|
ret = rename(from, to);
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
if (ret) {
|
2019-09-08 19:29:00 +00:00
|
|
|
perror("puttygen: cannot move new file on to old one");
|
|
|
|
return false;
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
2018-10-29 19:50:29 +00:00
|
|
|
return true;
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
static char *readpassphrase(const char *filename)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char *line;
|
|
|
|
|
|
|
|
fp = fopen(filename, "r");
|
|
|
|
if (!fp) {
|
2019-09-08 19:29:00 +00:00
|
|
|
fprintf(stderr, "puttygen: cannot open %s: %s\n",
|
|
|
|
filename, strerror(errno));
|
|
|
|
return NULL;
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
}
|
|
|
|
line = fgetline(fp);
|
|
|
|
if (line)
|
2019-09-08 19:29:00 +00:00
|
|
|
line[strcspn(line, "\r\n")] = '\0';
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
else if (ferror(fp))
|
2019-09-08 19:29:00 +00:00
|
|
|
fprintf(stderr, "puttygen: error reading from %s: %s\n",
|
|
|
|
filename, strerror(errno));
|
|
|
|
else /* empty file */
|
|
|
|
line = dupstr("");
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
fclose(fp);
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
2016-04-02 07:00:37 +00:00
|
|
|
#define DEFAULT_RSADSA_BITS 2048
|
|
|
|
|
2017-02-22 22:10:05 +00:00
|
|
|
/* For Unix in particular, but harmless if this main() is reused elsewhere */
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
const bool buildinfo_gtk_relevant = false;
|
2017-02-22 22:10:05 +00:00
|
|
|
|
2004-01-22 19:15:32 +00:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
char *infile = NULL;
|
2012-03-05 18:32:27 +00:00
|
|
|
Filename *infilename = NULL, *outfilename = NULL;
|
2020-02-02 11:41:06 +00:00
|
|
|
LoadedFile *infile_lf = NULL;
|
|
|
|
BinarySource *infile_bs = NULL;
|
2020-03-02 07:05:19 +00:00
|
|
|
enum { NOKEYGEN, RSA1, RSA2, DSA, ECDSA, EDDSA } keytype = NOKEYGEN;
|
2004-01-22 19:15:32 +00:00
|
|
|
char *outfile = NULL, *outfiletmp = NULL;
|
2015-05-10 06:42:48 +00:00
|
|
|
enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH_AUTO,
|
cmdgen: add a --dump option.
Also spelled '-O text', this takes a public or private key as input,
and produces on standard output a dump of all the actual numbers
involved in the key: the exponent and modulus for RSA, the p,q,g,y
parameters for DSA, the affine x and y coordinates of the public
elliptic curve point for ECC keys, and all the extra bits and pieces
in the private keys too.
Partly I expect this to be useful to me for debugging: I've had to
paste key files a few too many times through base64 decoders and hex
dump tools, then manually decode SSH marshalling and paste the result
into the Python REPL to get an integer object. Now I should be able to
get _straight_ to text I can paste into Python.
But also, it's a way that other applications can use the key
generator: if you need to generate, say, an RSA key in some format I
don't support (I've recently heard of an XML-based one, for example),
then you can run 'puttygen -t rsa --dump' and have it print the
elements of a freshly generated keypair on standard output, and then
all you have to do is understand the output format.
2020-02-17 19:53:19 +00:00
|
|
|
OPENSSH_NEW, SSHCOM, TEXT } outtype = PRIVATE;
|
2015-05-09 14:02:47 +00:00
|
|
|
int bits = -1;
|
2019-07-06 16:54:56 +00:00
|
|
|
const char *comment = NULL;
|
|
|
|
char *origcomment = NULL;
|
2021-02-22 17:56:02 +00:00
|
|
|
bool change_passphrase = false, reencrypt = false;
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool errs = false, nogo = false;
|
2004-01-22 19:15:32 +00:00
|
|
|
int intype = SSH_KEYTYPE_UNOPENABLE;
|
|
|
|
int sshver = 0;
|
2019-01-04 06:51:44 +00:00
|
|
|
ssh2_userkey *ssh2key = NULL;
|
|
|
|
RSAKey *ssh1key = NULL;
|
2018-05-24 09:59:39 +00:00
|
|
|
strbuf *ssh2blob = NULL;
|
2006-12-30 23:00:14 +00:00
|
|
|
char *ssh2alg = NULL;
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
char *old_passphrase = NULL, *new_passphrase = NULL;
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool load_encrypted;
|
2016-03-30 07:17:03 +00:00
|
|
|
const char *random_device = NULL;
|
2020-01-13 22:14:02 +00:00
|
|
|
int exit_status = 0;
|
2020-02-29 06:43:28 +00:00
|
|
|
const PrimeGenerationPolicy *primegen = &primegen_probabilistic;
|
RSA generation: option to generate strong primes.
A 'strong' prime, as defined by the Handbook of Applied Cryptography,
is a prime p such that each of p-1 and p+1 has a large prime factor,
and that the large factor q of p-1 is such that q-1 in turn _also_ has
a large prime factor.
HoAC says that making your RSA key using primes of this form defeats
some factoring algorithms - but there are other faster algorithms to
which it makes no difference. So this is probably not a useful
precaution in practice. However, it has been recommended in the past
by some official standards, and it's easy to implement given the new
general facility in PrimeCandidateSource that lets you ask for your
prime to satisfy an arbitrary modular congruence. (And HoAC also says
there's no particular reason _not_ to use strong primes.) So I provide
it as an option, just in case anyone wants to select it.
The change to the key generation algorithm is entirely in sshrsag.c,
and is neatly independent of the prime-generation system in use. If
you're using Maurer provable prime generation, then the known factor q
of p-1 can be used to help certify p, and the one for q-1 to help with
q in turn; if you switch to probabilistic prime generation then you
still get an RSA key with the right structure, except that every time
the definition says 'prime factor' you just append '(probably)'.
(The probabilistic version of this procedure is described as 'Gordon's
algorithm' in HoAC section 4.4.2.)
2020-03-02 06:52:09 +00:00
|
|
|
bool strong_rsa = false;
|
2021-02-22 18:13:12 +00:00
|
|
|
ppk_save_parameters params = ppk_save_default_parameters;
|
2021-03-13 09:57:02 +00:00
|
|
|
FingerprintType fptype = SSH_FPTYPE_DEFAULT;
|
2020-01-13 22:14:02 +00:00
|
|
|
|
2020-02-23 15:29:40 +00:00
|
|
|
if (is_interactive())
|
|
|
|
progress_fp = stderr;
|
|
|
|
|
2020-01-13 22:14:02 +00:00
|
|
|
#define RETURN(status) do { exit_status = (status); goto out; } while (0)
|
2004-01-22 19:15:32 +00:00
|
|
|
|
|
|
|
/* ------------------------------------------------------------------
|
|
|
|
* Parse the command line to figure out what we've been asked to do.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If run with no arguments at all, print the usage message and
|
|
|
|
* return success.
|
|
|
|
*/
|
|
|
|
if (argc <= 1) {
|
2019-09-08 19:29:00 +00:00
|
|
|
usage(true);
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(0);
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse command line arguments.
|
|
|
|
*/
|
|
|
|
while (--argc) {
|
2019-09-08 19:29:00 +00:00
|
|
|
char *p = *++argv;
|
2020-02-02 11:41:06 +00:00
|
|
|
if (p[0] == '-' && p[1]) {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* An option.
|
|
|
|
*/
|
|
|
|
while (p && *++p) {
|
|
|
|
char c = *p;
|
|
|
|
switch (c) {
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
case '-': {
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* Long option.
|
|
|
|
*/
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
char *opt, *val;
|
|
|
|
opt = p++; /* opt will have _one_ leading - */
|
|
|
|
while (*p && *p != '=')
|
|
|
|
p++; /* find end of option */
|
|
|
|
if (*p == '=') {
|
|
|
|
*p++ = '\0';
|
|
|
|
val = p;
|
|
|
|
} else
|
|
|
|
val = NULL;
|
|
|
|
|
|
|
|
if (!strcmp(opt, "-help")) {
|
|
|
|
if (val) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: option `-%s'"
|
|
|
|
" expects no argument\n", opt);
|
|
|
|
} else {
|
|
|
|
help();
|
|
|
|
nogo = true;
|
|
|
|
}
|
|
|
|
} else if (!strcmp(opt, "-version")) {
|
|
|
|
if (val) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: option `-%s'"
|
|
|
|
" expects no argument\n", opt);
|
|
|
|
} else {
|
|
|
|
showversion();
|
|
|
|
nogo = true;
|
|
|
|
}
|
|
|
|
} else if (!strcmp(opt, "-pgpfp")) {
|
|
|
|
if (val) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: option `-%s'"
|
|
|
|
" expects no argument\n", opt);
|
|
|
|
} else {
|
|
|
|
/* support --pgpfp for consistency */
|
|
|
|
pgp_fingerprints();
|
|
|
|
nogo = true;
|
|
|
|
}
|
|
|
|
} else if (!strcmp(opt, "-old-passphrase")) {
|
|
|
|
if (!val && argc > 1)
|
|
|
|
--argc, val = *++argv;
|
|
|
|
if (!val) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: option `-%s'"
|
|
|
|
" expects an argument\n", opt);
|
|
|
|
} else {
|
|
|
|
old_passphrase = readpassphrase(val);
|
|
|
|
if (!old_passphrase)
|
2019-09-08 19:29:00 +00:00
|
|
|
errs = true;
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
}
|
|
|
|
} else if (!strcmp(opt, "-new-passphrase")) {
|
|
|
|
if (!val && argc > 1)
|
|
|
|
--argc, val = *++argv;
|
|
|
|
if (!val) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: option `-%s'"
|
|
|
|
" expects an argument\n", opt);
|
|
|
|
} else {
|
|
|
|
new_passphrase = readpassphrase(val);
|
|
|
|
if (!new_passphrase)
|
|
|
|
errs = true;
|
|
|
|
}
|
|
|
|
} else if (!strcmp(opt, "-random-device")) {
|
|
|
|
if (!val && argc > 1)
|
|
|
|
--argc, val = *++argv;
|
|
|
|
if (!val) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: option `-%s'"
|
|
|
|
" expects an argument\n", opt);
|
|
|
|
} else {
|
|
|
|
random_device = val;
|
|
|
|
}
|
cmdgen: add a --dump option.
Also spelled '-O text', this takes a public or private key as input,
and produces on standard output a dump of all the actual numbers
involved in the key: the exponent and modulus for RSA, the p,q,g,y
parameters for DSA, the affine x and y coordinates of the public
elliptic curve point for ECC keys, and all the extra bits and pieces
in the private keys too.
Partly I expect this to be useful to me for debugging: I've had to
paste key files a few too many times through base64 decoders and hex
dump tools, then manually decode SSH marshalling and paste the result
into the Python REPL to get an integer object. Now I should be able to
get _straight_ to text I can paste into Python.
But also, it's a way that other applications can use the key
generator: if you need to generate, say, an RSA key in some format I
don't support (I've recently heard of an XML-based one, for example),
then you can run 'puttygen -t rsa --dump' and have it print the
elements of a freshly generated keypair on standard output, and then
all you have to do is understand the output format.
2020-02-17 19:53:19 +00:00
|
|
|
} else if (!strcmp(opt, "-dump")) {
|
|
|
|
outtype = TEXT;
|
2020-02-29 06:43:28 +00:00
|
|
|
} else if (!strcmp(opt, "-primes")) {
|
|
|
|
if (!val && argc > 1)
|
|
|
|
--argc, val = *++argv;
|
|
|
|
if (!val) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: option `-%s'"
|
|
|
|
" expects an argument\n", opt);
|
|
|
|
} else if (!strcmp(val, "probable") ||
|
|
|
|
!strcmp(val, "probabilistic")) {
|
|
|
|
primegen = &primegen_probabilistic;
|
|
|
|
} else if (!strcmp(val, "provable") ||
|
2020-03-01 20:37:09 +00:00
|
|
|
!strcmp(val, "proven") ||
|
2020-02-29 06:43:28 +00:00
|
|
|
!strcmp(val, "simple") ||
|
|
|
|
!strcmp(val, "maurer-simple")) {
|
|
|
|
primegen = &primegen_provable_maurer_simple;
|
|
|
|
} else if (!strcmp(val, "provable-even") ||
|
2020-03-01 20:37:09 +00:00
|
|
|
!strcmp(val, "proven-even") ||
|
2020-02-29 06:43:28 +00:00
|
|
|
!strcmp(val, "even") ||
|
|
|
|
!strcmp(val, "complex") ||
|
|
|
|
!strcmp(val, "maurer-complex")) {
|
|
|
|
primegen = &primegen_provable_maurer_complex;
|
|
|
|
} else {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: unrecognised prime-"
|
|
|
|
"generation mode `%s'\n", val);
|
|
|
|
}
|
RSA generation: option to generate strong primes.
A 'strong' prime, as defined by the Handbook of Applied Cryptography,
is a prime p such that each of p-1 and p+1 has a large prime factor,
and that the large factor q of p-1 is such that q-1 in turn _also_ has
a large prime factor.
HoAC says that making your RSA key using primes of this form defeats
some factoring algorithms - but there are other faster algorithms to
which it makes no difference. So this is probably not a useful
precaution in practice. However, it has been recommended in the past
by some official standards, and it's easy to implement given the new
general facility in PrimeCandidateSource that lets you ask for your
prime to satisfy an arbitrary modular congruence. (And HoAC also says
there's no particular reason _not_ to use strong primes.) So I provide
it as an option, just in case anyone wants to select it.
The change to the key generation algorithm is entirely in sshrsag.c,
and is neatly independent of the prime-generation system in use. If
you're using Maurer provable prime generation, then the known factor q
of p-1 can be used to help certify p, and the one for q-1 to help with
q in turn; if you switch to probabilistic prime generation then you
still get an RSA key with the right structure, except that every time
the definition says 'prime factor' you just append '(probably)'.
(The probabilistic version of this procedure is described as 'Gordon's
algorithm' in HoAC section 4.4.2.)
2020-03-02 06:52:09 +00:00
|
|
|
} else if (!strcmp(opt, "-strong-rsa")) {
|
|
|
|
strong_rsa = true;
|
2021-02-22 17:56:02 +00:00
|
|
|
} else if (!strcmp(opt, "-reencrypt")) {
|
|
|
|
reencrypt = true;
|
2021-02-22 18:13:12 +00:00
|
|
|
} else if (!strcmp(opt, "-ppk-param") ||
|
|
|
|
!strcmp(opt, "-ppk-params")) {
|
|
|
|
if (!val && argc > 1)
|
|
|
|
--argc, val = *++argv;
|
|
|
|
if (!val) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: option `-%s'"
|
|
|
|
" expects an argument\n", opt);
|
|
|
|
} else {
|
|
|
|
char *nextval;
|
|
|
|
for (; val; val = nextval) {
|
|
|
|
nextval = strchr(val, ',');
|
|
|
|
if (nextval)
|
|
|
|
*nextval++ = '\0';
|
|
|
|
|
|
|
|
char *optvalue = strchr(val, '=');
|
|
|
|
if (!optvalue) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: PPK parameter "
|
|
|
|
"'%s' expected a value\n", val);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*optvalue++ = '\0';
|
2021-02-23 18:26:50 +00:00
|
|
|
|
|
|
|
/* Non-numeric options */
|
|
|
|
if (!strcmp(val, "kdf")) {
|
|
|
|
if (!strcmp(optvalue, "Argon2id") ||
|
|
|
|
!strcmp(optvalue, "argon2id")) {
|
|
|
|
params.argon2_flavour = Argon2id;
|
|
|
|
} else if (!strcmp(optvalue, "Argon2i") ||
|
|
|
|
!strcmp(optvalue, "argon2i")) {
|
|
|
|
params.argon2_flavour = Argon2i;
|
|
|
|
} else if (!strcmp(optvalue, "Argon2d") ||
|
|
|
|
!strcmp(optvalue, "argon2d")) {
|
|
|
|
params.argon2_flavour = Argon2d;
|
|
|
|
} else {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: unrecognise"
|
|
|
|
"d kdf '%s'\n", optvalue);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-02-22 18:13:12 +00:00
|
|
|
char *end;
|
|
|
|
unsigned long n = strtoul(optvalue, &end, 0);
|
|
|
|
if (!*optvalue || *end) {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: value '%s' for "
|
|
|
|
"PPK parameter '%s': expected a "
|
|
|
|
"number\n", optvalue, val);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(val, "version")) {
|
|
|
|
params.fmt_version = n;
|
|
|
|
} else if (!strcmp(val, "memory") ||
|
|
|
|
!strcmp(val, "mem")) {
|
|
|
|
params.argon2_mem = n;
|
|
|
|
} else if (!strcmp(val, "time")) {
|
|
|
|
params.argon2_passes_auto = true;
|
|
|
|
params.argon2_milliseconds = n;
|
|
|
|
} else if (!strcmp(val, "passes")) {
|
|
|
|
params.argon2_passes_auto = false;
|
|
|
|
params.argon2_milliseconds = n;
|
|
|
|
} else if (!strcmp(val, "parallelism") ||
|
|
|
|
!strcmp(val, "parallel")) {
|
|
|
|
params.argon2_parallelism = n;
|
|
|
|
} else {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: unrecognised "
|
|
|
|
"PPK parameter '%s'\n", val);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
} else {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr,
|
|
|
|
"puttygen: no such option `-%s'\n", opt);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
p = NULL;
|
|
|
|
break;
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
case 'h':
|
|
|
|
case 'V':
|
|
|
|
case 'P':
|
|
|
|
case 'l':
|
|
|
|
case 'L':
|
|
|
|
case 'p':
|
|
|
|
case 'q':
|
|
|
|
/*
|
|
|
|
* Option requiring no parameter.
|
|
|
|
*/
|
|
|
|
switch (c) {
|
|
|
|
case 'h':
|
|
|
|
help();
|
|
|
|
nogo = true;
|
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
showversion();
|
|
|
|
nogo = true;
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
change_passphrase = true;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
outtype = FP;
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
outtype = PUBLICO;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
outtype = PUBLIC;
|
|
|
|
break;
|
|
|
|
case 'q':
|
2020-02-23 15:29:40 +00:00
|
|
|
progress_fp = NULL;
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
case 'b':
|
|
|
|
case 'C':
|
|
|
|
case 'O':
|
|
|
|
case 'o':
|
2021-03-13 09:57:02 +00:00
|
|
|
case 'E':
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
|
|
|
* Option requiring parameter.
|
|
|
|
*/
|
|
|
|
p++;
|
|
|
|
if (!*p && argc > 1)
|
|
|
|
--argc, p = *++argv;
|
|
|
|
else if (!*p) {
|
|
|
|
fprintf(stderr, "puttygen: option `-%c' expects a"
|
|
|
|
" parameter\n", c);
|
|
|
|
errs = true;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Now c is the option and p is the parameter.
|
|
|
|
*/
|
|
|
|
switch (c) {
|
|
|
|
case 't':
|
|
|
|
if (!strcmp(p, "rsa") || !strcmp(p, "rsa2"))
|
|
|
|
keytype = RSA2, sshver = 2;
|
|
|
|
else if (!strcmp(p, "rsa1"))
|
|
|
|
keytype = RSA1, sshver = 1;
|
|
|
|
else if (!strcmp(p, "dsa") || !strcmp(p, "dss"))
|
|
|
|
keytype = DSA, sshver = 2;
|
2014-11-01 09:45:20 +00:00
|
|
|
else if (!strcmp(p, "ecdsa"))
|
|
|
|
keytype = ECDSA, sshver = 2;
|
2020-03-02 07:05:19 +00:00
|
|
|
else if (!strcmp(p, "eddsa"))
|
|
|
|
keytype = EDDSA, sshver = 2;
|
2015-05-09 14:02:54 +00:00
|
|
|
else if (!strcmp(p, "ed25519"))
|
2020-03-02 07:05:19 +00:00
|
|
|
keytype = EDDSA, bits = 255, sshver = 2;
|
2020-03-02 07:09:08 +00:00
|
|
|
else if (!strcmp(p, "ed448"))
|
|
|
|
keytype = EDDSA, bits = 448, sshver = 2;
|
2019-09-08 19:29:00 +00:00
|
|
|
else {
|
|
|
|
fprintf(stderr,
|
|
|
|
"puttygen: unknown key type `%s'\n", p);
|
|
|
|
errs = true;
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
break;
|
2019-09-08 19:29:00 +00:00
|
|
|
case 'b':
|
|
|
|
bits = atoi(p);
|
2004-01-22 19:15:32 +00:00
|
|
|
break;
|
2019-09-08 19:29:00 +00:00
|
|
|
case 'C':
|
|
|
|
comment = p;
|
2004-01-22 19:15:32 +00:00
|
|
|
break;
|
2019-09-08 19:29:00 +00:00
|
|
|
case 'O':
|
|
|
|
if (!strcmp(p, "public"))
|
|
|
|
outtype = PUBLIC;
|
|
|
|
else if (!strcmp(p, "public-openssh"))
|
|
|
|
outtype = PUBLICO;
|
|
|
|
else if (!strcmp(p, "private"))
|
|
|
|
outtype = PRIVATE;
|
|
|
|
else if (!strcmp(p, "fingerprint"))
|
|
|
|
outtype = FP;
|
|
|
|
else if (!strcmp(p, "private-openssh"))
|
|
|
|
outtype = OPENSSH_AUTO, sshver = 2;
|
|
|
|
else if (!strcmp(p, "private-openssh-new"))
|
|
|
|
outtype = OPENSSH_NEW, sshver = 2;
|
|
|
|
else if (!strcmp(p, "private-sshcom"))
|
|
|
|
outtype = SSHCOM, sshver = 2;
|
cmdgen: add a --dump option.
Also spelled '-O text', this takes a public or private key as input,
and produces on standard output a dump of all the actual numbers
involved in the key: the exponent and modulus for RSA, the p,q,g,y
parameters for DSA, the affine x and y coordinates of the public
elliptic curve point for ECC keys, and all the extra bits and pieces
in the private keys too.
Partly I expect this to be useful to me for debugging: I've had to
paste key files a few too many times through base64 decoders and hex
dump tools, then manually decode SSH marshalling and paste the result
into the Python REPL to get an integer object. Now I should be able to
get _straight_ to text I can paste into Python.
But also, it's a way that other applications can use the key
generator: if you need to generate, say, an RSA key in some format I
don't support (I've recently heard of an XML-based one, for example),
then you can run 'puttygen -t rsa --dump' and have it print the
elements of a freshly generated keypair on standard output, and then
all you have to do is understand the output format.
2020-02-17 19:53:19 +00:00
|
|
|
else if (!strcmp(p, "text"))
|
|
|
|
outtype = TEXT;
|
2019-09-08 19:29:00 +00:00
|
|
|
else {
|
|
|
|
fprintf(stderr,
|
|
|
|
"puttygen: unknown output type `%s'\n", p);
|
|
|
|
errs = true;
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
break;
|
2019-09-08 19:29:00 +00:00
|
|
|
case 'o':
|
|
|
|
outfile = p;
|
2004-01-22 19:15:32 +00:00
|
|
|
break;
|
2021-03-13 09:57:02 +00:00
|
|
|
case 'E':
|
|
|
|
if (!strcmp(p, "md5"))
|
|
|
|
fptype = SSH_FPTYPE_MD5;
|
|
|
|
else if (!strcmp(p, "sha256"))
|
|
|
|
fptype = SSH_FPTYPE_SHA256;
|
|
|
|
else {
|
|
|
|
fprintf(stderr, "puttygen: unknown fingerprint "
|
|
|
|
"type `%s'\n", p);
|
|
|
|
errs = true;
|
|
|
|
}
|
|
|
|
break;
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
p = NULL; /* prevent continued processing */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* Unrecognised option.
|
|
|
|
*/
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: no such option `-%c'\n", c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* A non-option argument.
|
|
|
|
*/
|
|
|
|
if (!infile)
|
|
|
|
infile = p;
|
|
|
|
else {
|
|
|
|
errs = true;
|
|
|
|
fprintf(stderr, "puttygen: cannot handle more than one"
|
|
|
|
" input file\n");
|
|
|
|
}
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
2015-05-09 14:02:47 +00:00
|
|
|
if (bits == -1) {
|
|
|
|
/*
|
|
|
|
* No explicit key size was specified. Default varies
|
|
|
|
* depending on key type.
|
|
|
|
*/
|
|
|
|
switch (keytype) {
|
|
|
|
case ECDSA:
|
|
|
|
bits = 384;
|
|
|
|
break;
|
2020-03-02 07:05:19 +00:00
|
|
|
case EDDSA:
|
2020-01-14 06:39:32 +00:00
|
|
|
bits = 255;
|
2015-05-09 14:02:54 +00:00
|
|
|
break;
|
2015-05-09 14:02:47 +00:00
|
|
|
default:
|
2016-04-02 07:00:37 +00:00
|
|
|
bits = DEFAULT_RSADSA_BITS;
|
2015-05-09 14:02:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-02 07:05:19 +00:00
|
|
|
if (keytype == ECDSA || keytype == EDDSA) {
|
|
|
|
const char *name = (keytype == ECDSA ? "ECDSA" : "EdDSA");
|
|
|
|
const int *valid_lengths = (keytype == ECDSA ? ec_nist_curve_lengths :
|
|
|
|
ec_ed_curve_lengths);
|
|
|
|
size_t n_lengths = (keytype == ECDSA ? n_ec_nist_curve_lengths :
|
|
|
|
n_ec_ed_curve_lengths);
|
|
|
|
bool (*alg_and_curve_by_bits)(int, const struct ec_curve **,
|
|
|
|
const ssh_keyalg **) =
|
|
|
|
(keytype == ECDSA ? ec_nist_alg_and_curve_by_bits :
|
|
|
|
ec_ed_alg_and_curve_by_bits);
|
|
|
|
|
|
|
|
const struct ec_curve *curve;
|
|
|
|
const ssh_keyalg *alg;
|
|
|
|
|
|
|
|
if (!alg_and_curve_by_bits(bits, &curve, &alg)) {
|
|
|
|
fprintf(stderr, "puttygen: invalid bits for %s, choose", name);
|
|
|
|
for (size_t i = 0; i < n_lengths; i++)
|
|
|
|
fprintf(stderr, "%s%d", (i == 0 ? " " :
|
|
|
|
i == n_lengths-1 ? " or " : ", "),
|
|
|
|
valid_lengths[i]);
|
|
|
|
fputc('\n', stderr);
|
|
|
|
errs = true;
|
|
|
|
}
|
2015-05-09 14:02:54 +00:00
|
|
|
}
|
|
|
|
|
2016-03-30 10:41:11 +00:00
|
|
|
if (keytype == RSA2 || keytype == RSA1 || keytype == DSA) {
|
|
|
|
if (bits < 256) {
|
|
|
|
fprintf(stderr, "puttygen: cannot generate %s keys shorter than"
|
|
|
|
" 256 bits\n", (keytype == DSA ? "DSA" : "RSA"));
|
2018-10-29 19:50:29 +00:00
|
|
|
errs = true;
|
2016-04-02 07:00:37 +00:00
|
|
|
} else if (bits < DEFAULT_RSADSA_BITS) {
|
|
|
|
fprintf(stderr, "puttygen: warning: %s keys shorter than"
|
|
|
|
" %d bits are probably not secure\n",
|
|
|
|
(keytype == DSA ? "DSA" : "RSA"), DEFAULT_RSADSA_BITS);
|
|
|
|
/* but this is just a warning, so proceed anyway */
|
2016-03-30 10:41:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-22 19:15:32 +00:00
|
|
|
if (errs)
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2004-01-22 19:15:32 +00:00
|
|
|
|
|
|
|
if (nogo)
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(0);
|
2004-01-22 19:15:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If run with at least one argument _but_ not the required
|
|
|
|
* ones, print the usage message and return failure.
|
|
|
|
*/
|
|
|
|
if (!infile && keytype == NOKEYGEN) {
|
2019-09-08 19:29:00 +00:00
|
|
|
usage(true);
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------
|
|
|
|
* Figure out further details of exactly what we're going to do.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Bomb out if we've been asked to both load and generate a
|
|
|
|
* key.
|
|
|
|
*/
|
2006-07-07 14:18:47 +00:00
|
|
|
if (keytype != NOKEYGEN && infile) {
|
2019-09-08 19:29:00 +00:00
|
|
|
fprintf(stderr, "puttygen: cannot both load and generate a key\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
/*
|
2006-07-07 14:18:47 +00:00
|
|
|
* We must save the private part when generating a new key.
|
|
|
|
*/
|
|
|
|
if (keytype != NOKEYGEN &&
|
2019-09-08 19:29:00 +00:00
|
|
|
(outtype != PRIVATE && outtype != OPENSSH_AUTO &&
|
cmdgen: add a --dump option.
Also spelled '-O text', this takes a public or private key as input,
and produces on standard output a dump of all the actual numbers
involved in the key: the exponent and modulus for RSA, the p,q,g,y
parameters for DSA, the affine x and y coordinates of the public
elliptic curve point for ECC keys, and all the extra bits and pieces
in the private keys too.
Partly I expect this to be useful to me for debugging: I've had to
paste key files a few too many times through base64 decoders and hex
dump tools, then manually decode SSH marshalling and paste the result
into the Python REPL to get an integer object. Now I should be able to
get _straight_ to text I can paste into Python.
But also, it's a way that other applications can use the key
generator: if you need to generate, say, an RSA key in some format I
don't support (I've recently heard of an XML-based one, for example),
then you can run 'puttygen -t rsa --dump' and have it print the
elements of a freshly generated keypair on standard output, and then
all you have to do is understand the output format.
2020-02-17 19:53:19 +00:00
|
|
|
outtype != OPENSSH_NEW && outtype != SSHCOM && outtype != TEXT)) {
|
2019-09-08 19:29:00 +00:00
|
|
|
fprintf(stderr, "puttygen: this would generate a new key but "
|
|
|
|
"discard the private part\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2006-07-07 14:18:47 +00:00
|
|
|
}
|
|
|
|
|
2004-01-22 19:15:32 +00:00
|
|
|
/*
|
|
|
|
* Analyse the type of the input file, in case this affects our
|
|
|
|
* course of action.
|
|
|
|
*/
|
|
|
|
if (infile) {
|
2020-02-02 11:41:06 +00:00
|
|
|
const char *load_error;
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
infilename = filename_from_str(infile);
|
2020-02-02 11:41:06 +00:00
|
|
|
if (!strcmp(infile, "-"))
|
|
|
|
infile_lf = lf_load_keyfile_fp(stdin, &load_error);
|
|
|
|
else
|
|
|
|
infile_lf = lf_load_keyfile(infilename, &load_error);
|
|
|
|
|
|
|
|
if (!infile_lf) {
|
|
|
|
fprintf(stderr, "puttygen: unable to load file `%s': %s\n",
|
|
|
|
infile, load_error);
|
|
|
|
RETURN(1);
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2020-02-02 11:41:06 +00:00
|
|
|
infile_bs = BinarySource_UPCAST(infile_lf);
|
|
|
|
intype = key_type_s(infile_bs);
|
|
|
|
BinarySource_REWIND(infile_bs);
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
switch (intype) {
|
|
|
|
case SSH_KEYTYPE_UNOPENABLE:
|
|
|
|
case SSH_KEYTYPE_UNKNOWN:
|
|
|
|
fprintf(stderr, "puttygen: unable to load file `%s': %s\n",
|
|
|
|
infile, key_type_to_str(intype));
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
case SSH_KEYTYPE_SSH1:
|
2015-05-12 11:19:57 +00:00
|
|
|
case SSH_KEYTYPE_SSH1_PUBLIC:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (sshver == 2) {
|
|
|
|
fprintf(stderr, "puttygen: conversion from SSH-1 to SSH-2 keys"
|
|
|
|
" not supported\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
sshver = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSH_KEYTYPE_SSH2:
|
2015-05-12 11:19:57 +00:00
|
|
|
case SSH_KEYTYPE_SSH2_PUBLIC_RFC4716:
|
|
|
|
case SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH:
|
2019-09-08 19:29:00 +00:00
|
|
|
case SSH_KEYTYPE_OPENSSH_PEM:
|
|
|
|
case SSH_KEYTYPE_OPENSSH_NEW:
|
|
|
|
case SSH_KEYTYPE_SSHCOM:
|
|
|
|
if (sshver == 1) {
|
|
|
|
fprintf(stderr, "puttygen: conversion from SSH-2 to SSH-1 keys"
|
|
|
|
" not supported\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
sshver = 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSH_KEYTYPE_OPENSSH_AUTO:
|
2015-05-10 06:42:48 +00:00
|
|
|
default:
|
2019-01-03 08:12:19 +00:00
|
|
|
unreachable("Should never see these types on an input file");
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine the default output file, if none is provided.
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2004-01-22 19:15:32 +00:00
|
|
|
* This will usually be equal to stdout, except that if the
|
|
|
|
* input and output file formats are the same then the default
|
|
|
|
* output is to overwrite the input.
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2004-01-22 19:15:32 +00:00
|
|
|
* Also in this code, we bomb out if the input and output file
|
|
|
|
* formats are the same and no other action is performed.
|
|
|
|
*/
|
|
|
|
if ((intype == SSH_KEYTYPE_SSH1 && outtype == PRIVATE) ||
|
2019-09-08 19:29:00 +00:00
|
|
|
(intype == SSH_KEYTYPE_SSH2 && outtype == PRIVATE) ||
|
|
|
|
(intype == SSH_KEYTYPE_OPENSSH_PEM && outtype == OPENSSH_AUTO) ||
|
|
|
|
(intype == SSH_KEYTYPE_OPENSSH_NEW && outtype == OPENSSH_NEW) ||
|
|
|
|
(intype == SSH_KEYTYPE_SSHCOM && outtype == SSHCOM)) {
|
|
|
|
if (!outfile) {
|
|
|
|
outfile = infile;
|
Make dupcat() into a variadic macro.
Up until now, it's been a variadic _function_, whose argument list
consists of 'const char *' ASCIZ strings to concatenate, terminated by
one containing a null pointer. Now, that function is dupcat_fn(), and
it's wrapped by a C99 variadic _macro_ called dupcat(), which
automatically suffixes the null-pointer terminating argument.
This has three benefits. Firstly, it's just less effort at every call
site. Secondly, it protects against the risk of accidentally leaving
off the NULL, causing arbitrary words of stack memory to be
dereferenced as char pointers. And thirdly, it protects against the
more subtle risk of writing a bare 'NULL' as the terminating argument,
instead of casting it explicitly to a pointer. That last one is
necessary because C permits the macro NULL to expand to an integer
constant such as 0, so NULL by itself may not have pointer type, and
worse, it may not be marshalled in a variadic argument list in the
same way as a pointer. (For example, on a 64-bit machine it might only
occupy 32 bits. And yet, on another 64-bit platform, it might work
just fine, so that you don't notice the mistake!)
I was inspired to do this by happening to notice one of those bare
NULL terminators, and thinking I'd better check if there were any
more. Turned out there were quite a few. Now there are none.
2019-10-14 18:42:37 +00:00
|
|
|
outfiletmp = dupcat(outfile, ".tmp");
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
|
2021-02-22 17:56:02 +00:00
|
|
|
if (!change_passphrase && !comment && !reencrypt) {
|
2019-09-08 19:29:00 +00:00
|
|
|
fprintf(stderr, "puttygen: this command would perform no useful"
|
|
|
|
" action\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
} else {
|
2019-09-08 19:29:00 +00:00
|
|
|
if (!outfile) {
|
|
|
|
/*
|
|
|
|
* Bomb out rather than automatically choosing to write
|
|
|
|
* a private key file to stdout.
|
|
|
|
*/
|
|
|
|
if (outtype == PRIVATE || outtype == OPENSSH_AUTO ||
|
2015-04-28 18:46:58 +00:00
|
|
|
outtype == OPENSSH_NEW || outtype == SSHCOM) {
|
2019-09-08 19:29:00 +00:00
|
|
|
fprintf(stderr, "puttygen: need to specify an output file\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out whether we need to load the encrypted part of the
|
2021-04-07 21:57:51 +00:00
|
|
|
* key. This will be the case if (a) we need to write out
|
|
|
|
* a private key format, (b) the entire input key file is
|
|
|
|
* encrypted, or (c) we're outputting TEXT, in which case we
|
|
|
|
* want all of the input file including private material if it
|
|
|
|
* exists.
|
2004-01-22 19:15:32 +00:00
|
|
|
*/
|
2021-04-07 21:57:51 +00:00
|
|
|
bool intype_entirely_encrypted =
|
2019-09-08 19:29:00 +00:00
|
|
|
intype == SSH_KEYTYPE_OPENSSH_PEM ||
|
|
|
|
intype == SSH_KEYTYPE_OPENSSH_NEW ||
|
2021-04-07 21:57:51 +00:00
|
|
|
intype == SSH_KEYTYPE_SSHCOM;
|
|
|
|
bool intype_has_private =
|
|
|
|
!(intype == SSH_KEYTYPE_SSH1_PUBLIC ||
|
|
|
|
intype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 ||
|
|
|
|
intype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH);
|
|
|
|
bool outtype_has_private =
|
|
|
|
outtype == PRIVATE || outtype == OPENSSH_AUTO ||
|
|
|
|
outtype == OPENSSH_NEW || outtype == SSHCOM;
|
|
|
|
if (outtype_has_private || intype_entirely_encrypted ||
|
|
|
|
(outtype == TEXT && intype_has_private))
|
2019-09-08 19:29:00 +00:00
|
|
|
load_encrypted = true;
|
2004-01-22 19:15:32 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
load_encrypted = false;
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2021-04-07 21:57:51 +00:00
|
|
|
if (load_encrypted && !intype_has_private) {
|
2015-05-12 11:19:57 +00:00
|
|
|
fprintf(stderr, "puttygen: cannot perform this action on a "
|
|
|
|
"public-key-only input file\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2015-05-12 11:19:57 +00:00
|
|
|
}
|
|
|
|
|
2004-01-22 19:15:32 +00:00
|
|
|
/* ------------------------------------------------------------------
|
|
|
|
* Now we're ready to actually do some stuff.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Either load or generate a key.
|
|
|
|
*/
|
|
|
|
if (keytype != NOKEYGEN) {
|
2019-09-08 19:29:00 +00:00
|
|
|
char *entropy;
|
|
|
|
char default_comment[80];
|
|
|
|
struct tm tm;
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
tm = ltime();
|
|
|
|
if (keytype == DSA)
|
|
|
|
strftime(default_comment, 30, "dsa-key-%Y%m%d", &tm);
|
2014-11-01 09:45:20 +00:00
|
|
|
else if (keytype == ECDSA)
|
|
|
|
strftime(default_comment, 30, "ecdsa-key-%Y%m%d", &tm);
|
2020-03-02 07:05:19 +00:00
|
|
|
else if (keytype == EDDSA && bits == 255)
|
2015-05-09 14:02:54 +00:00
|
|
|
strftime(default_comment, 30, "ed25519-key-%Y%m%d", &tm);
|
2020-03-02 07:05:19 +00:00
|
|
|
else if (keytype == EDDSA)
|
|
|
|
strftime(default_comment, 30, "eddsa-key-%Y%m%d", &tm);
|
2019-09-08 19:29:00 +00:00
|
|
|
else
|
|
|
|
strftime(default_comment, 30, "rsa-key-%Y%m%d", &tm);
|
|
|
|
|
|
|
|
entropy = get_random_data(bits / 8, random_device);
|
|
|
|
if (!entropy) {
|
|
|
|
fprintf(stderr, "puttygen: failed to collect entropy, "
|
|
|
|
"could not generate key\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
random_setup_special();
|
Replace PuTTY's PRNG with a Fortuna-like system.
This tears out the entire previous random-pool system in sshrand.c. In
its place is a system pretty close to Ferguson and Schneier's
'Fortuna' generator, with the main difference being that I use SHA-256
instead of AES for the generation side of the system (rationale given
in comment).
The PRNG implementation lives in sshprng.c, and defines a self-
contained data type with no state stored outside the object, so you
can instantiate however many of them you like. The old sshrand.c still
exists, but in place of the previous random pool system, it's just
become a client of sshprng.c, whose job is to hold a single global
instance of the PRNG type, and manage its reference count, save file,
noise-collection timers and similar administrative business.
Advantages of this change include:
- Fortuna is designed with a more varied threat model in mind than my
old home-grown random pool. For example, after any request for
random numbers, it automatically re-seeds itself, so that if the
state of the PRNG should be leaked, it won't give enough
information to find out what past outputs _were_.
- The PRNG type can be instantiated with any hash function; the
instance used by the main tools is based on SHA-256, an improvement
on the old pool's use of SHA-1.
- The new PRNG only uses the completely standard interface to the
hash function API, instead of having to have privileged access to
the internal SHA-1 block transform function. This will make it
easier to revamp the hash code in general, and also it means that
hardware-accelerated versions of SHA-256 will automatically be used
for the PRNG as well as for everything else.
- The new PRNG can be _tested_! Because it has an actual (if not
quite explicit) specification for exactly what the output numbers
_ought_ to be derived from the hashes of, I can (and have) put
tests in cryptsuite that ensure the output really is being derived
in the way I think it is. The old pool could have been returning
any old nonsense and it would have been very hard to tell for sure.
2019-01-22 22:42:41 +00:00
|
|
|
random_reseed(make_ptrlen(entropy, bits / 8));
|
2019-09-08 19:29:00 +00:00
|
|
|
smemclr(entropy, bits/8);
|
|
|
|
sfree(entropy);
|
|
|
|
|
2020-02-29 06:43:28 +00:00
|
|
|
PrimeGenerationContext *pgc = primegen_new_context(primegen);
|
2020-02-29 09:10:47 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (keytype == DSA) {
|
|
|
|
struct dss_key *dsskey = snew(struct dss_key);
|
2020-02-29 09:10:47 +00:00
|
|
|
dsa_generate(dsskey, bits, pgc, &cmdgen_progress);
|
2019-09-08 19:29:00 +00:00
|
|
|
ssh2key = snew(ssh2_userkey);
|
|
|
|
ssh2key->key = &dsskey->sshk;
|
|
|
|
ssh1key = NULL;
|
2014-11-01 09:45:20 +00:00
|
|
|
} else if (keytype == ECDSA) {
|
Complete rewrite of PuTTY's bignum library.
The old 'Bignum' data type is gone completely, and so is sshbn.c. In
its place is a new thing called 'mp_int', handled by an entirely new
library module mpint.c, with API differences both large and small.
The main aim of this change is that the new library should be free of
timing- and cache-related side channels. I've written the code so that
it _should_ - assuming I haven't made any mistakes - do all of its
work without either control flow or memory addressing depending on the
data words of the input numbers. (Though, being an _arbitrary_
precision library, it does have to at least depend on the sizes of the
numbers - but there's a 'formal' size that can vary separately from
the actual magnitude of the represented integer, so if you want to
keep it secret that your number is actually small, it should work fine
to have a very long mp_int and just happen to store 23 in it.) So I've
done all my conditionalisation by means of computing both answers and
doing bit-masking to swap the right one into place, and all loops over
the words of an mp_int go up to the formal size rather than the actual
size.
I haven't actually tested the constant-time property in any rigorous
way yet (I'm still considering the best way to do it). But this code
is surely at the very least a big improvement on the old version, even
if I later find a few more things to fix.
I've also completely rewritten the low-level elliptic curve arithmetic
from sshecc.c; the new ecc.c is closer to being an adjunct of mpint.c
than it is to the SSH end of the code. The new elliptic curve code
keeps all coordinates in Montgomery-multiplication transformed form to
speed up all the multiplications mod the same prime, and only converts
them back when you ask for the affine coordinates. Also, I adopted
extended coordinates for the Edwards curve implementation.
sshecc.c has also had a near-total rewrite in the course of switching
it over to the new system. While I was there, I've separated ECDSA and
EdDSA more completely - they now have separate vtables, instead of a
single vtable in which nearly every function had a big if statement in
it - and also made the externally exposed types for an ECDSA key and
an ECDH context different.
A minor new feature: since the new arithmetic code includes a modular
square root function, we can now support the compressed point
representation for the NIST curves. We seem to have been getting along
fine without that so far, but it seemed a shame not to put it in,
since it was suddenly easy.
In sshrsa.c, one major change is that I've removed the RSA blinding
step in rsa_privkey_op, in which we randomise the ciphertext before
doing the decryption. The purpose of that was to avoid timing leaks
giving away the plaintext - but the new arithmetic code should take
that in its stride in the course of also being careful enough to avoid
leaking the _private key_, which RSA blinding had no way to do
anything about in any case.
Apart from those specific points, most of the rest of the changes are
more or less mechanical, just changing type names and translating code
into the new API.
2018-12-31 13:53:41 +00:00
|
|
|
struct ecdsa_key *ek = snew(struct ecdsa_key);
|
2020-02-23 15:29:40 +00:00
|
|
|
ecdsa_generate(ek, bits);
|
2019-01-04 06:51:44 +00:00
|
|
|
ssh2key = snew(ssh2_userkey);
|
Complete rewrite of PuTTY's bignum library.
The old 'Bignum' data type is gone completely, and so is sshbn.c. In
its place is a new thing called 'mp_int', handled by an entirely new
library module mpint.c, with API differences both large and small.
The main aim of this change is that the new library should be free of
timing- and cache-related side channels. I've written the code so that
it _should_ - assuming I haven't made any mistakes - do all of its
work without either control flow or memory addressing depending on the
data words of the input numbers. (Though, being an _arbitrary_
precision library, it does have to at least depend on the sizes of the
numbers - but there's a 'formal' size that can vary separately from
the actual magnitude of the represented integer, so if you want to
keep it secret that your number is actually small, it should work fine
to have a very long mp_int and just happen to store 23 in it.) So I've
done all my conditionalisation by means of computing both answers and
doing bit-masking to swap the right one into place, and all loops over
the words of an mp_int go up to the formal size rather than the actual
size.
I haven't actually tested the constant-time property in any rigorous
way yet (I'm still considering the best way to do it). But this code
is surely at the very least a big improvement on the old version, even
if I later find a few more things to fix.
I've also completely rewritten the low-level elliptic curve arithmetic
from sshecc.c; the new ecc.c is closer to being an adjunct of mpint.c
than it is to the SSH end of the code. The new elliptic curve code
keeps all coordinates in Montgomery-multiplication transformed form to
speed up all the multiplications mod the same prime, and only converts
them back when you ask for the affine coordinates. Also, I adopted
extended coordinates for the Edwards curve implementation.
sshecc.c has also had a near-total rewrite in the course of switching
it over to the new system. While I was there, I've separated ECDSA and
EdDSA more completely - they now have separate vtables, instead of a
single vtable in which nearly every function had a big if statement in
it - and also made the externally exposed types for an ECDSA key and
an ECDH context different.
A minor new feature: since the new arithmetic code includes a modular
square root function, we can now support the compressed point
representation for the NIST curves. We seem to have been getting along
fine without that so far, but it seemed a shame not to put it in,
since it was suddenly easy.
In sshrsa.c, one major change is that I've removed the RSA blinding
step in rsa_privkey_op, in which we randomise the ciphertext before
doing the decryption. The purpose of that was to avoid timing leaks
giving away the plaintext - but the new arithmetic code should take
that in its stride in the course of also being careful enough to avoid
leaking the _private key_, which RSA blinding had no way to do
anything about in any case.
Apart from those specific points, most of the rest of the changes are
more or less mechanical, just changing type names and translating code
into the new API.
2018-12-31 13:53:41 +00:00
|
|
|
ssh2key->key = &ek->sshk;
|
2014-11-01 09:45:20 +00:00
|
|
|
ssh1key = NULL;
|
2020-03-02 07:05:19 +00:00
|
|
|
} else if (keytype == EDDSA) {
|
Complete rewrite of PuTTY's bignum library.
The old 'Bignum' data type is gone completely, and so is sshbn.c. In
its place is a new thing called 'mp_int', handled by an entirely new
library module mpint.c, with API differences both large and small.
The main aim of this change is that the new library should be free of
timing- and cache-related side channels. I've written the code so that
it _should_ - assuming I haven't made any mistakes - do all of its
work without either control flow or memory addressing depending on the
data words of the input numbers. (Though, being an _arbitrary_
precision library, it does have to at least depend on the sizes of the
numbers - but there's a 'formal' size that can vary separately from
the actual magnitude of the represented integer, so if you want to
keep it secret that your number is actually small, it should work fine
to have a very long mp_int and just happen to store 23 in it.) So I've
done all my conditionalisation by means of computing both answers and
doing bit-masking to swap the right one into place, and all loops over
the words of an mp_int go up to the formal size rather than the actual
size.
I haven't actually tested the constant-time property in any rigorous
way yet (I'm still considering the best way to do it). But this code
is surely at the very least a big improvement on the old version, even
if I later find a few more things to fix.
I've also completely rewritten the low-level elliptic curve arithmetic
from sshecc.c; the new ecc.c is closer to being an adjunct of mpint.c
than it is to the SSH end of the code. The new elliptic curve code
keeps all coordinates in Montgomery-multiplication transformed form to
speed up all the multiplications mod the same prime, and only converts
them back when you ask for the affine coordinates. Also, I adopted
extended coordinates for the Edwards curve implementation.
sshecc.c has also had a near-total rewrite in the course of switching
it over to the new system. While I was there, I've separated ECDSA and
EdDSA more completely - they now have separate vtables, instead of a
single vtable in which nearly every function had a big if statement in
it - and also made the externally exposed types for an ECDSA key and
an ECDH context different.
A minor new feature: since the new arithmetic code includes a modular
square root function, we can now support the compressed point
representation for the NIST curves. We seem to have been getting along
fine without that so far, but it seemed a shame not to put it in,
since it was suddenly easy.
In sshrsa.c, one major change is that I've removed the RSA blinding
step in rsa_privkey_op, in which we randomise the ciphertext before
doing the decryption. The purpose of that was to avoid timing leaks
giving away the plaintext - but the new arithmetic code should take
that in its stride in the course of also being careful enough to avoid
leaking the _private key_, which RSA blinding had no way to do
anything about in any case.
Apart from those specific points, most of the rest of the changes are
more or less mechanical, just changing type names and translating code
into the new API.
2018-12-31 13:53:41 +00:00
|
|
|
struct eddsa_key *ek = snew(struct eddsa_key);
|
2020-02-23 15:29:40 +00:00
|
|
|
eddsa_generate(ek, bits);
|
2019-01-04 06:51:44 +00:00
|
|
|
ssh2key = snew(ssh2_userkey);
|
Complete rewrite of PuTTY's bignum library.
The old 'Bignum' data type is gone completely, and so is sshbn.c. In
its place is a new thing called 'mp_int', handled by an entirely new
library module mpint.c, with API differences both large and small.
The main aim of this change is that the new library should be free of
timing- and cache-related side channels. I've written the code so that
it _should_ - assuming I haven't made any mistakes - do all of its
work without either control flow or memory addressing depending on the
data words of the input numbers. (Though, being an _arbitrary_
precision library, it does have to at least depend on the sizes of the
numbers - but there's a 'formal' size that can vary separately from
the actual magnitude of the represented integer, so if you want to
keep it secret that your number is actually small, it should work fine
to have a very long mp_int and just happen to store 23 in it.) So I've
done all my conditionalisation by means of computing both answers and
doing bit-masking to swap the right one into place, and all loops over
the words of an mp_int go up to the formal size rather than the actual
size.
I haven't actually tested the constant-time property in any rigorous
way yet (I'm still considering the best way to do it). But this code
is surely at the very least a big improvement on the old version, even
if I later find a few more things to fix.
I've also completely rewritten the low-level elliptic curve arithmetic
from sshecc.c; the new ecc.c is closer to being an adjunct of mpint.c
than it is to the SSH end of the code. The new elliptic curve code
keeps all coordinates in Montgomery-multiplication transformed form to
speed up all the multiplications mod the same prime, and only converts
them back when you ask for the affine coordinates. Also, I adopted
extended coordinates for the Edwards curve implementation.
sshecc.c has also had a near-total rewrite in the course of switching
it over to the new system. While I was there, I've separated ECDSA and
EdDSA more completely - they now have separate vtables, instead of a
single vtable in which nearly every function had a big if statement in
it - and also made the externally exposed types for an ECDSA key and
an ECDH context different.
A minor new feature: since the new arithmetic code includes a modular
square root function, we can now support the compressed point
representation for the NIST curves. We seem to have been getting along
fine without that so far, but it seemed a shame not to put it in,
since it was suddenly easy.
In sshrsa.c, one major change is that I've removed the RSA blinding
step in rsa_privkey_op, in which we randomise the ciphertext before
doing the decryption. The purpose of that was to avoid timing leaks
giving away the plaintext - but the new arithmetic code should take
that in its stride in the course of also being careful enough to avoid
leaking the _private key_, which RSA blinding had no way to do
anything about in any case.
Apart from those specific points, most of the rest of the changes are
more or less mechanical, just changing type names and translating code
into the new API.
2018-12-31 13:53:41 +00:00
|
|
|
ssh2key->key = &ek->sshk;
|
2015-05-09 14:02:54 +00:00
|
|
|
ssh1key = NULL;
|
2019-09-08 19:29:00 +00:00
|
|
|
} else {
|
|
|
|
RSAKey *rsakey = snew(RSAKey);
|
RSA generation: option to generate strong primes.
A 'strong' prime, as defined by the Handbook of Applied Cryptography,
is a prime p such that each of p-1 and p+1 has a large prime factor,
and that the large factor q of p-1 is such that q-1 in turn _also_ has
a large prime factor.
HoAC says that making your RSA key using primes of this form defeats
some factoring algorithms - but there are other faster algorithms to
which it makes no difference. So this is probably not a useful
precaution in practice. However, it has been recommended in the past
by some official standards, and it's easy to implement given the new
general facility in PrimeCandidateSource that lets you ask for your
prime to satisfy an arbitrary modular congruence. (And HoAC also says
there's no particular reason _not_ to use strong primes.) So I provide
it as an option, just in case anyone wants to select it.
The change to the key generation algorithm is entirely in sshrsag.c,
and is neatly independent of the prime-generation system in use. If
you're using Maurer provable prime generation, then the known factor q
of p-1 can be used to help certify p, and the one for q-1 to help with
q in turn; if you switch to probabilistic prime generation then you
still get an RSA key with the right structure, except that every time
the definition says 'prime factor' you just append '(probably)'.
(The probabilistic version of this procedure is described as 'Gordon's
algorithm' in HoAC section 4.4.2.)
2020-03-02 06:52:09 +00:00
|
|
|
rsa_generate(rsakey, bits, strong_rsa, pgc, &cmdgen_progress);
|
2019-09-08 19:29:00 +00:00
|
|
|
rsakey->comment = NULL;
|
|
|
|
if (keytype == RSA1) {
|
|
|
|
ssh1key = rsakey;
|
|
|
|
} else {
|
|
|
|
ssh2key = snew(ssh2_userkey);
|
|
|
|
ssh2key->key = &rsakey->sshk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-29 09:10:47 +00:00
|
|
|
primegen_free_context(pgc);
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
if (ssh2key)
|
|
|
|
ssh2key->comment = dupstr(default_comment);
|
|
|
|
if (ssh1key)
|
|
|
|
ssh1key->comment = dupstr(default_comment);
|
2004-01-22 19:15:32 +00:00
|
|
|
|
|
|
|
} else {
|
2019-09-08 19:29:00 +00:00
|
|
|
const char *error = NULL;
|
|
|
|
bool encrypted;
|
|
|
|
|
|
|
|
assert(infile != NULL);
|
|
|
|
|
|
|
|
sfree(origcomment);
|
|
|
|
origcomment = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find out whether the input key is encrypted.
|
|
|
|
*/
|
|
|
|
if (intype == SSH_KEYTYPE_SSH1)
|
2020-02-02 11:41:06 +00:00
|
|
|
encrypted = rsa1_encrypted_s(infile_bs, &origcomment);
|
2019-09-08 19:29:00 +00:00
|
|
|
else if (intype == SSH_KEYTYPE_SSH2)
|
2020-02-02 11:41:06 +00:00
|
|
|
encrypted = ppk_encrypted_s(infile_bs, &origcomment);
|
2019-09-08 19:29:00 +00:00
|
|
|
else
|
2020-02-02 11:41:06 +00:00
|
|
|
encrypted = import_encrypted_s(infilename, infile_bs,
|
|
|
|
intype, &origcomment);
|
|
|
|
BinarySource_REWIND(infile_bs);
|
2019-09-08 19:29:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If so, ask for a passphrase.
|
|
|
|
*/
|
|
|
|
if (encrypted && load_encrypted) {
|
|
|
|
if (!old_passphrase) {
|
|
|
|
prompts_t *p = new_prompts();
|
|
|
|
int ret;
|
|
|
|
p->to_server = false;
|
|
|
|
p->from_server = false;
|
|
|
|
p->name = dupstr("SSH key passphrase");
|
|
|
|
add_prompt(p, dupstr("Enter passphrase to load key: "), false);
|
|
|
|
ret = console_get_userpass_input(p);
|
|
|
|
assert(ret >= 0);
|
|
|
|
if (!ret) {
|
|
|
|
free_prompts(p);
|
|
|
|
perror("puttygen: unable to read passphrase");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
} else {
|
2020-01-21 20:19:47 +00:00
|
|
|
old_passphrase = prompt_get_result(p->prompts[0]);
|
2019-09-08 19:29:00 +00:00
|
|
|
free_prompts(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
old_passphrase = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (intype) {
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
case SSH_KEYTYPE_SSH1:
|
2015-05-12 11:19:57 +00:00
|
|
|
case SSH_KEYTYPE_SSH1_PUBLIC:
|
2019-09-08 19:29:00 +00:00
|
|
|
ssh1key = snew(RSAKey);
|
2020-01-13 22:14:02 +00:00
|
|
|
memset(ssh1key, 0, sizeof(RSAKey));
|
2019-09-08 19:29:00 +00:00
|
|
|
if (!load_encrypted) {
|
|
|
|
strbuf *blob;
|
2018-05-29 19:36:21 +00:00
|
|
|
BinarySource src[1];
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2019-07-06 16:44:15 +00:00
|
|
|
sfree(origcomment);
|
|
|
|
origcomment = NULL;
|
|
|
|
|
2018-05-24 09:59:39 +00:00
|
|
|
blob = strbuf_new();
|
2019-07-06 16:44:15 +00:00
|
|
|
|
2020-02-02 11:41:06 +00:00
|
|
|
ret = rsa1_loadpub_s(infile_bs, BinarySink_UPCAST(blob),
|
2020-01-05 10:28:45 +00:00
|
|
|
&origcomment, &error);
|
2018-05-29 19:36:21 +00:00
|
|
|
BinarySource_BARE_INIT(src, blob->u, blob->len);
|
2018-06-03 07:23:07 +00:00
|
|
|
get_rsa_ssh1_pub(src, ssh1key, RSA_SSH1_EXPONENT_FIRST);
|
2018-05-24 09:59:39 +00:00
|
|
|
strbuf_free(blob);
|
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
ssh1key->comment = dupstr(origcomment);
|
|
|
|
ssh1key->private_exponent = NULL;
|
|
|
|
ssh1key->p = NULL;
|
|
|
|
ssh1key->q = NULL;
|
|
|
|
ssh1key->iqmp = NULL;
|
|
|
|
} else {
|
2020-02-02 11:41:06 +00:00
|
|
|
ret = rsa1_load_s(infile_bs, ssh1key, old_passphrase, &error);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2020-02-02 11:41:06 +00:00
|
|
|
BinarySource_REWIND(infile_bs);
|
2019-09-08 19:29:00 +00:00
|
|
|
if (ret > 0)
|
|
|
|
error = NULL;
|
|
|
|
else if (!error)
|
|
|
|
error = "unknown error";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSH_KEYTYPE_SSH2:
|
2015-05-12 11:19:57 +00:00
|
|
|
case SSH_KEYTYPE_SSH2_PUBLIC_RFC4716:
|
|
|
|
case SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH:
|
2019-09-08 19:29:00 +00:00
|
|
|
if (!load_encrypted) {
|
2019-07-06 16:44:15 +00:00
|
|
|
sfree(origcomment);
|
|
|
|
origcomment = NULL;
|
2018-05-24 09:59:39 +00:00
|
|
|
ssh2blob = strbuf_new();
|
2020-02-02 11:41:06 +00:00
|
|
|
if (ppk_loadpub_s(infile_bs, &ssh2alg,
|
2020-01-05 10:28:45 +00:00
|
|
|
BinarySink_UPCAST(ssh2blob),
|
|
|
|
&origcomment, &error)) {
|
2018-06-03 11:58:05 +00:00
|
|
|
const ssh_keyalg *alg = find_pubkey_alg(ssh2alg);
|
|
|
|
if (alg)
|
|
|
|
bits = ssh_key_public_bits(
|
2018-10-13 15:30:59 +00:00
|
|
|
alg, ptrlen_from_strbuf(ssh2blob));
|
2013-02-22 21:39:02 +00:00
|
|
|
else
|
|
|
|
bits = -1;
|
2018-05-24 09:59:39 +00:00
|
|
|
} else {
|
|
|
|
strbuf_free(ssh2blob);
|
2019-01-29 20:12:37 +00:00
|
|
|
ssh2blob = NULL;
|
2013-02-22 21:39:02 +00:00
|
|
|
}
|
2015-05-15 09:12:06 +00:00
|
|
|
sfree(ssh2alg);
|
2019-09-08 19:29:00 +00:00
|
|
|
} else {
|
2020-02-02 11:41:06 +00:00
|
|
|
ssh2key = ppk_load_s(infile_bs, old_passphrase, &error);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2020-02-02 11:41:06 +00:00
|
|
|
BinarySource_REWIND(infile_bs);
|
2019-09-08 19:29:00 +00:00
|
|
|
if ((ssh2key && ssh2key != SSH2_WRONG_PASSPHRASE) || ssh2blob)
|
|
|
|
error = NULL;
|
|
|
|
else if (!error) {
|
|
|
|
if (ssh2key == SSH2_WRONG_PASSPHRASE)
|
|
|
|
error = "wrong passphrase";
|
|
|
|
else
|
|
|
|
error = "unknown error";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSH_KEYTYPE_OPENSSH_PEM:
|
|
|
|
case SSH_KEYTYPE_OPENSSH_NEW:
|
|
|
|
case SSH_KEYTYPE_SSHCOM:
|
2020-02-02 11:41:06 +00:00
|
|
|
ssh2key = import_ssh2_s(infile_bs, intype, old_passphrase, &error);
|
2019-09-08 19:29:00 +00:00
|
|
|
if (ssh2key) {
|
|
|
|
if (ssh2key != SSH2_WRONG_PASSPHRASE)
|
|
|
|
error = NULL;
|
|
|
|
else
|
|
|
|
error = "wrong passphrase";
|
|
|
|
} else if (!error)
|
|
|
|
error = "unknown error";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
unreachable("bad input key type");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
fprintf(stderr, "puttygen: error loading `%s': %s\n",
|
|
|
|
infile, error);
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Change the comment if asked to.
|
|
|
|
*/
|
|
|
|
if (comment) {
|
2019-09-08 19:29:00 +00:00
|
|
|
if (sshver == 1) {
|
|
|
|
assert(ssh1key);
|
|
|
|
sfree(ssh1key->comment);
|
|
|
|
ssh1key->comment = dupstr(comment);
|
|
|
|
} else {
|
|
|
|
assert(ssh2key);
|
|
|
|
sfree(ssh2key->comment);
|
|
|
|
ssh2key->comment = dupstr(comment);
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
/*
|
|
|
|
* Unless we're changing the passphrase, the old one (if any) is a
|
|
|
|
* reasonable default.
|
|
|
|
*/
|
|
|
|
if (!change_passphrase && old_passphrase && !new_passphrase)
|
2019-09-08 19:29:00 +00:00
|
|
|
new_passphrase = dupstr(old_passphrase);
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
|
2004-01-22 19:15:32 +00:00
|
|
|
/*
|
|
|
|
* Prompt for a new passphrase if we have been asked to, or if
|
|
|
|
* we have just generated a key.
|
cmdgen: add a --dump option.
Also spelled '-O text', this takes a public or private key as input,
and produces on standard output a dump of all the actual numbers
involved in the key: the exponent and modulus for RSA, the p,q,g,y
parameters for DSA, the affine x and y coordinates of the public
elliptic curve point for ECC keys, and all the extra bits and pieces
in the private keys too.
Partly I expect this to be useful to me for debugging: I've had to
paste key files a few too many times through base64 decoders and hex
dump tools, then manually decode SSH marshalling and paste the result
into the Python REPL to get an integer object. Now I should be able to
get _straight_ to text I can paste into Python.
But also, it's a way that other applications can use the key
generator: if you need to generate, say, an RSA key in some format I
don't support (I've recently heard of an XML-based one, for example),
then you can run 'puttygen -t rsa --dump' and have it print the
elements of a freshly generated keypair on standard output, and then
all you have to do is understand the output format.
2020-02-17 19:53:19 +00:00
|
|
|
*
|
|
|
|
* In the latter case, an exception is if we're producing text
|
|
|
|
* output, because that output format doesn't support encryption
|
|
|
|
* in any case.
|
2004-01-22 19:15:32 +00:00
|
|
|
*/
|
cmdgen: add a --dump option.
Also spelled '-O text', this takes a public or private key as input,
and produces on standard output a dump of all the actual numbers
involved in the key: the exponent and modulus for RSA, the p,q,g,y
parameters for DSA, the affine x and y coordinates of the public
elliptic curve point for ECC keys, and all the extra bits and pieces
in the private keys too.
Partly I expect this to be useful to me for debugging: I've had to
paste key files a few too many times through base64 decoders and hex
dump tools, then manually decode SSH marshalling and paste the result
into the Python REPL to get an integer object. Now I should be able to
get _straight_ to text I can paste into Python.
But also, it's a way that other applications can use the key
generator: if you need to generate, say, an RSA key in some format I
don't support (I've recently heard of an XML-based one, for example),
then you can run 'puttygen -t rsa --dump' and have it print the
elements of a freshly generated keypair on standard output, and then
all you have to do is understand the output format.
2020-02-17 19:53:19 +00:00
|
|
|
if (!new_passphrase && (change_passphrase ||
|
|
|
|
(keytype != NOKEYGEN && outtype != TEXT))) {
|
2020-01-29 06:13:41 +00:00
|
|
|
prompts_t *p = new_prompts();
|
2019-09-08 19:29:00 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
p->to_server = false;
|
|
|
|
p->from_server = false;
|
|
|
|
p->name = dupstr("New SSH key passphrase");
|
|
|
|
add_prompt(p, dupstr("Enter passphrase to save key: "), false);
|
|
|
|
add_prompt(p, dupstr("Re-enter passphrase to verify: "), false);
|
|
|
|
ret = console_get_userpass_input(p);
|
|
|
|
assert(ret >= 0);
|
|
|
|
if (!ret) {
|
|
|
|
free_prompts(p);
|
|
|
|
perror("puttygen: unable to read new passphrase");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
} else {
|
2020-01-21 20:19:47 +00:00
|
|
|
if (strcmp(prompt_get_result_ref(p->prompts[0]),
|
|
|
|
prompt_get_result_ref(p->prompts[1]))) {
|
2019-09-08 19:29:00 +00:00
|
|
|
free_prompts(p);
|
|
|
|
fprintf(stderr, "puttygen: passphrases do not match\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
2020-01-21 20:19:47 +00:00
|
|
|
new_passphrase = prompt_get_result(p->prompts[0]);
|
2019-09-08 19:29:00 +00:00
|
|
|
free_prompts(p);
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
if (new_passphrase && !*new_passphrase) {
|
2019-09-08 19:29:00 +00:00
|
|
|
sfree(new_passphrase);
|
|
|
|
new_passphrase = NULL;
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Write output.
|
2019-09-08 19:29:00 +00:00
|
|
|
*
|
2004-01-22 19:15:32 +00:00
|
|
|
* (In the case where outfile and outfiletmp are both NULL,
|
|
|
|
* there is no semantic reason to initialise outfilename at
|
|
|
|
* all; but we have to write _something_ to it or some compiler
|
|
|
|
* will probably complain that it might be used uninitialised.)
|
|
|
|
*/
|
|
|
|
if (outfiletmp)
|
2019-09-08 19:29:00 +00:00
|
|
|
outfilename = filename_from_str(outfiletmp);
|
2004-01-22 19:15:32 +00:00
|
|
|
else
|
2019-09-08 19:29:00 +00:00
|
|
|
outfilename = filename_from_str(outfile ? outfile : "");
|
2004-01-22 19:15:32 +00:00
|
|
|
|
|
|
|
switch (outtype) {
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool ret;
|
|
|
|
int real_outtype;
|
2004-01-22 19:15:32 +00:00
|
|
|
|
|
|
|
case PRIVATE:
|
2019-03-24 14:05:35 +00:00
|
|
|
random_ref(); /* we'll need a few random bytes in the save file */
|
2019-09-08 19:29:00 +00:00
|
|
|
if (sshver == 1) {
|
|
|
|
assert(ssh1key);
|
2020-01-05 10:28:45 +00:00
|
|
|
ret = rsa1_save_f(outfilename, ssh1key, new_passphrase);
|
2019-09-08 19:29:00 +00:00
|
|
|
if (!ret) {
|
|
|
|
fprintf(stderr, "puttygen: unable to save SSH-1 private key\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(ssh2key);
|
2021-02-22 18:13:12 +00:00
|
|
|
ret = ppk_save_f(outfilename, ssh2key, new_passphrase, ¶ms);
|
2019-09-08 19:29:00 +00:00
|
|
|
if (!ret) {
|
|
|
|
fprintf(stderr, "puttygen: unable to save SSH-2 private key\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (outfiletmp) {
|
|
|
|
if (!move(outfiletmp, outfile))
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1); /* rename failed */
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2004-01-22 19:15:32 +00:00
|
|
|
|
|
|
|
case PUBLIC:
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
case PUBLICO: {
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
if (outfile) {
|
|
|
|
fp = f_open(outfilename, "w", false);
|
|
|
|
if (!fp) {
|
|
|
|
fprintf(stderr, "unable to open output file\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fp = stdout;
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
if (sshver == 1) {
|
|
|
|
ssh1_write_pubkey(fp, ssh1key);
|
|
|
|
} else {
|
|
|
|
if (!ssh2blob) {
|
|
|
|
assert(ssh2key);
|
|
|
|
ssh2blob = strbuf_new();
|
|
|
|
ssh_key_public_blob(ssh2key->key, BinarySink_UPCAST(ssh2blob));
|
|
|
|
}
|
|
|
|
|
|
|
|
ssh2_write_pubkey(fp, ssh2key ? ssh2key->comment : origcomment,
|
|
|
|
ssh2blob->s, ssh2blob->len,
|
|
|
|
(outtype == PUBLIC ?
|
|
|
|
SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 :
|
|
|
|
SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH));
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
if (outfile)
|
|
|
|
fclose(fp);
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
case FP: {
|
|
|
|
FILE *fp;
|
|
|
|
char *fingerprint;
|
2019-09-08 19:29:00 +00:00
|
|
|
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
if (sshver == 1) {
|
|
|
|
assert(ssh1key);
|
|
|
|
fingerprint = rsa_ssh1_fingerprint(ssh1key);
|
|
|
|
} else {
|
|
|
|
if (ssh2key) {
|
2021-03-13 09:57:02 +00:00
|
|
|
fingerprint = ssh2_fingerprint(ssh2key->key, fptype);
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
} else {
|
|
|
|
assert(ssh2blob);
|
|
|
|
fingerprint = ssh2_fingerprint_blob(
|
2021-03-13 09:57:02 +00:00
|
|
|
ptrlen_from_strbuf(ssh2blob), fptype);
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
if (outfile) {
|
|
|
|
fp = f_open(outfilename, "w", false);
|
|
|
|
if (!fp) {
|
|
|
|
fprintf(stderr, "unable to open output file\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fp = stdout;
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
fprintf(fp, "%s\n", fingerprint);
|
|
|
|
if (outfile)
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
sfree(fingerprint);
|
2019-09-08 19:29:00 +00:00
|
|
|
break;
|
Formatting change to braces around one case of a switch.
Sometimes, within a switch statement, you want to declare local
variables specific to the handler for one particular case. Until now
I've mostly been writing this in the form
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED:
{
declare variables;
do stuff;
}
break;
}
which is ugly because the two pieces of essentially similar code
appear at different indent levels, and also inconvenient because you
have less horizontal space available to write the complicated case
handler in - particuarly undesirable because _complicated_ case
handlers are the ones most likely to need all the space they can get!
After encountering a rather nicer idiom in the LLVM source code, and
after a bit of hackery this morning figuring out how to persuade
Emacs's auto-indent to do what I wanted with it, I've decided to move
to an idiom in which the open brace comes right after the case
statement, and the code within it is indented the same as it would
have been without the brace. Then the whole case handler (including
the break) lives inside those braces, and you get something that looks
more like this:
switch (discriminant) {
case SIMPLE:
do stuff;
break;
case COMPLICATED: {
declare variables;
do stuff;
break;
}
}
This commit is a big-bang change that reformats all the complicated
case handlers I could find into the new layout. This is particularly
nice in the Pageant main function, in which almost _every_ case
handler had a bundle of variables and was long and complicated. (In
fact that's what motivated me to get round to this.) Some of the
innermost parts of the terminal escape-sequence handling are also
breathing a bit easier now the horizontal pressure on them is
relieved.
(Also, in a few cases, I was able to remove the extra braces
completely, because the only variable local to the case handler was a
loop variable which our new C99 policy allows me to move into the
initialiser clause of its for statement.)
Viewed with whitespace ignored, this is not too disruptive a change.
Downstream patches that conflict with it may need to be reapplied
using --ignore-whitespace or similar.
2020-02-16 07:49:52 +00:00
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
|
2015-05-10 06:42:48 +00:00
|
|
|
case OPENSSH_AUTO:
|
2015-04-28 18:46:58 +00:00
|
|
|
case OPENSSH_NEW:
|
2004-01-22 19:15:32 +00:00
|
|
|
case SSHCOM:
|
2019-09-08 19:29:00 +00:00
|
|
|
assert(sshver == 2);
|
|
|
|
assert(ssh2key);
|
|
|
|
random_ref(); /* both foreign key types require randomness,
|
2014-01-16 19:16:19 +00:00
|
|
|
* for IV or padding */
|
2015-04-28 18:46:08 +00:00
|
|
|
switch (outtype) {
|
2015-05-10 06:42:48 +00:00
|
|
|
case OPENSSH_AUTO:
|
|
|
|
real_outtype = SSH_KEYTYPE_OPENSSH_AUTO;
|
2015-04-28 18:46:58 +00:00
|
|
|
break;
|
|
|
|
case OPENSSH_NEW:
|
|
|
|
real_outtype = SSH_KEYTYPE_OPENSSH_NEW;
|
2015-04-28 18:46:08 +00:00
|
|
|
break;
|
|
|
|
case SSHCOM:
|
|
|
|
real_outtype = SSH_KEYTYPE_SSHCOM;
|
|
|
|
break;
|
2015-04-28 18:46:58 +00:00
|
|
|
default:
|
2019-01-03 08:12:19 +00:00
|
|
|
unreachable("control flow goof");
|
2015-04-28 18:46:08 +00:00
|
|
|
}
|
2019-09-08 19:29:00 +00:00
|
|
|
ret = export_ssh2(outfilename, real_outtype, ssh2key, new_passphrase);
|
|
|
|
if (!ret) {
|
|
|
|
fprintf(stderr, "puttygen: unable to export key\n");
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1);
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
if (outfiletmp) {
|
|
|
|
if (!move(outfiletmp, outfile))
|
2020-01-13 22:14:02 +00:00
|
|
|
RETURN(1); /* rename failed */
|
2019-09-08 19:29:00 +00:00
|
|
|
}
|
|
|
|
break;
|
cmdgen: add a --dump option.
Also spelled '-O text', this takes a public or private key as input,
and produces on standard output a dump of all the actual numbers
involved in the key: the exponent and modulus for RSA, the p,q,g,y
parameters for DSA, the affine x and y coordinates of the public
elliptic curve point for ECC keys, and all the extra bits and pieces
in the private keys too.
Partly I expect this to be useful to me for debugging: I've had to
paste key files a few too many times through base64 decoders and hex
dump tools, then manually decode SSH marshalling and paste the result
into the Python REPL to get an integer object. Now I should be able to
get _straight_ to text I can paste into Python.
But also, it's a way that other applications can use the key
generator: if you need to generate, say, an RSA key in some format I
don't support (I've recently heard of an XML-based one, for example),
then you can run 'puttygen -t rsa --dump' and have it print the
elements of a freshly generated keypair on standard output, and then
all you have to do is understand the output format.
2020-02-17 19:53:19 +00:00
|
|
|
|
|
|
|
case TEXT: {
|
|
|
|
key_components *kc;
|
|
|
|
if (sshver == 1) {
|
|
|
|
assert(ssh1key);
|
|
|
|
kc = rsa_components(ssh1key);
|
|
|
|
} else {
|
|
|
|
if (ssh2key) {
|
|
|
|
kc = ssh_key_components(ssh2key->key);
|
|
|
|
} else {
|
|
|
|
assert(ssh2blob);
|
|
|
|
|
|
|
|
BinarySource src[1];
|
|
|
|
BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(ssh2blob));
|
|
|
|
ptrlen algname = get_string(src);
|
|
|
|
const ssh_keyalg *alg = find_pubkey_alg_len(algname);
|
|
|
|
if (!alg) {
|
|
|
|
fprintf(stderr, "puttygen: cannot extract key components "
|
|
|
|
"from public key of unknown type '%.*s'\n",
|
|
|
|
PTRLEN_PRINTF(algname));
|
|
|
|
RETURN(1);
|
|
|
|
}
|
|
|
|
ssh_key *sk = ssh_key_new_pub(
|
|
|
|
alg, ptrlen_from_strbuf(ssh2blob));
|
|
|
|
kc = ssh_key_components(sk);
|
|
|
|
ssh_key_free(sk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *fp;
|
|
|
|
if (outfile) {
|
|
|
|
fp = f_open(outfilename, "w", false);
|
|
|
|
if (!fp) {
|
|
|
|
fprintf(stderr, "unable to open output file\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fp = stdout;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < kc->ncomponents; i++) {
|
|
|
|
if (kc->components[i].is_mp_int) {
|
|
|
|
char *hex = mp_get_hex(kc->components[i].mp);
|
|
|
|
fprintf(fp, "%s=0x%s\n", kc->components[i].name, hex);
|
|
|
|
smemclr(hex, strlen(hex));
|
|
|
|
sfree(hex);
|
|
|
|
} else {
|
|
|
|
fprintf(fp, "%s=\"", kc->components[i].name);
|
|
|
|
write_c_string_literal(fp, ptrlen_from_asciz(
|
|
|
|
kc->components[i].text));
|
|
|
|
fputs("\"\n", fp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (outfile)
|
|
|
|
fclose(fp);
|
|
|
|
key_components_free(kc);
|
|
|
|
break;
|
|
|
|
}
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
2020-01-13 22:14:02 +00:00
|
|
|
out:
|
|
|
|
|
|
|
|
#undef RETURN
|
|
|
|
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
if (old_passphrase) {
|
2019-09-08 19:29:00 +00:00
|
|
|
smemclr(old_passphrase, strlen(old_passphrase));
|
|
|
|
sfree(old_passphrase);
|
Add command-line passphrase-file options to command-line PuTTYgen.
Patch due to Colin Watson.
Putting the passphrase in a file avoids exposing it to 'ps' which can
print out every process's command line, while at the same time not
being as platform-specific as the approach of providing an fd number
(since cmdgen.c is in principle a potential cross-platform PuTTYgen,
not just a Unix one, which is why it's not in the 'unix' directory).
Of course it introduces its own risks if someone can read the file
from your disk after you delete it; probably the best approach to
avoiding this, if possible, is to point the option at a file on an
in-memory tmpfs type file system. Or better still, use bash-style
/dev/fd options such as
puttygen --new-passphrase <(echo -n "my passphrase") [options]
Failing that, try a secure file-wipe utility, as the man page change
mentions.
(And a use case not to be overlooked, of course, is the one where you
actually want to generate an unprotected key - in which case, just
pass /dev/null as the filename.)
2016-03-17 18:42:46 +00:00
|
|
|
}
|
|
|
|
if (new_passphrase) {
|
2019-09-08 19:29:00 +00:00
|
|
|
smemclr(new_passphrase, strlen(new_passphrase));
|
|
|
|
sfree(new_passphrase);
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
2018-12-30 14:14:59 +00:00
|
|
|
if (ssh1key) {
|
2019-09-08 19:29:00 +00:00
|
|
|
freersakey(ssh1key);
|
2019-06-28 18:22:39 +00:00
|
|
|
sfree(ssh1key);
|
2018-12-30 14:14:59 +00:00
|
|
|
}
|
2020-01-13 22:14:02 +00:00
|
|
|
if (ssh2key && ssh2key != SSH2_WRONG_PASSPHRASE) {
|
2019-09-08 19:29:00 +00:00
|
|
|
sfree(ssh2key->comment);
|
2020-01-13 22:14:02 +00:00
|
|
|
if (ssh2key->key)
|
|
|
|
ssh_key_free(ssh2key->key);
|
2019-09-08 19:29:00 +00:00
|
|
|
sfree(ssh2key);
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|
2019-07-06 16:44:15 +00:00
|
|
|
if (ssh2blob)
|
|
|
|
strbuf_free(ssh2blob);
|
2019-02-28 06:19:31 +00:00
|
|
|
sfree(origcomment);
|
|
|
|
if (infilename)
|
|
|
|
filename_free(infilename);
|
2020-02-02 11:41:06 +00:00
|
|
|
if (infile_lf)
|
|
|
|
lf_free(infile_lf);
|
2020-01-13 22:14:02 +00:00
|
|
|
if (outfilename)
|
|
|
|
filename_free(outfilename);
|
|
|
|
sfree(outfiletmp);
|
2004-01-22 19:15:32 +00:00
|
|
|
|
2020-01-13 22:14:02 +00:00
|
|
|
return exit_status;
|
2004-01-22 19:15:32 +00:00
|
|
|
}
|