mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-01 19:42:48 -05:00
New option to manually configure the expected host key(s).
This option is available from the command line as '-hostkey', and is also configurable through the GUI. When enabled, it completely replaces all of the automated host key management: the server's host key will be checked against the manually configured list, and the connection will be allowed or disconnected on that basis, and the host key store in the registry will not be either consulted or updated. The main aim is to provide a means of automatically running Plink, PSCP or PSFTP deep inside Windows services where HKEY_CURRENT_USER isn't available to have stored the right host key in. But it also permits you to specify a list of multiple host keys, which means a second use case for the same mechanism will probably be round-robin DNS names that select one of several servers with different host keys. Host keys can be specified as the standard MD5 fingerprint or as an SSH-2 base64 blob, and are canonicalised on input. (The base64 blob is more unwieldy, especially with Windows command-line length limits, but provides a means of specifying the _whole_ public key in case you don't trust MD5. I haven't bothered to provide an analogous mechanism for SSH-1, on the basis that anyone worrying about MD5 should have stopped using SSH-1 already!) [originally from svn r10220]
This commit is contained in:
97
misc.c
97
misc.c
@ -922,3 +922,100 @@ void smemclr(void *b, size_t n) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Validate a manual host key specification (either entered in the
|
||||
* GUI, or via -hostkey). If valid, we return TRUE, and update 'key'
|
||||
* to contain a canonicalised version of the key string in 'key'
|
||||
* (which is guaranteed to take up at most as much space as the
|
||||
* original version), suitable for putting into the Conf. If not
|
||||
* valid, we return FALSE.
|
||||
*/
|
||||
int validate_manual_hostkey(char *key)
|
||||
{
|
||||
char *p, *q, *r, *s;
|
||||
|
||||
/*
|
||||
* Step through the string word by word, looking for a word that's
|
||||
* in one of the formats we like.
|
||||
*/
|
||||
p = key;
|
||||
while ((p += strspn(p, " \t"))[0]) {
|
||||
q = p;
|
||||
p += strcspn(p, " \t");
|
||||
if (p) *p++ = '\0';
|
||||
|
||||
/*
|
||||
* Now q is our word.
|
||||
*/
|
||||
|
||||
if (strlen(q) == 16*3 - 1 &&
|
||||
q[strspn(q, "0123456789abcdefABCDEF:")] == 0) {
|
||||
/*
|
||||
* Might be a key fingerprint. Check the colons are in the
|
||||
* right places, and if so, return the same fingerprint
|
||||
* canonicalised into lowercase.
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
if (q[3*i] == ':' || q[3*i+1] == ':')
|
||||
goto not_fingerprint; /* sorry */
|
||||
for (i = 0; i < 15; i++)
|
||||
if (q[3*i+2] != ':')
|
||||
goto not_fingerprint; /* sorry */
|
||||
for (i = 0; i < 16*3 - 1; i++)
|
||||
key[i] = tolower(q[i]);
|
||||
key[16*3 - 1] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
not_fingerprint:;
|
||||
|
||||
/*
|
||||
* Before we check for a public-key blob, trim newlines out of
|
||||
* the middle of the word, in case someone's managed to paste
|
||||
* in a public-key blob _with_ them.
|
||||
*/
|
||||
for (r = s = q; *r; r++)
|
||||
if (*r != '\n' && *r != '\r')
|
||||
*s++ = *r;
|
||||
*s = '\0';
|
||||
|
||||
if (strlen(q) % 4 == 0 && strlen(q) > 2*4 &&
|
||||
q[strspn(q, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz+/=")] == 0) {
|
||||
/*
|
||||
* Might be a base64-encoded SSH-2 public key blob. Check
|
||||
* that it starts with a sensible algorithm string. No
|
||||
* canonicalisation is necessary for this string type.
|
||||
*
|
||||
* The algorithm string must be at most 64 characters long
|
||||
* (RFC 4251 section 6).
|
||||
*/
|
||||
unsigned char decoded[6];
|
||||
unsigned alglen;
|
||||
int minlen;
|
||||
int len = 0;
|
||||
|
||||
len += base64_decode_atom(q, decoded+len);
|
||||
if (len < 3)
|
||||
goto not_ssh2_blob; /* sorry */
|
||||
len += base64_decode_atom(q+4, decoded+len);
|
||||
if (len < 4)
|
||||
goto not_ssh2_blob; /* sorry */
|
||||
|
||||
alglen = GET_32BIT_MSB_FIRST(decoded);
|
||||
if (alglen > 64)
|
||||
goto not_ssh2_blob; /* sorry */
|
||||
|
||||
minlen = ((alglen + 4) + 2) / 3;
|
||||
if (strlen(q) < minlen)
|
||||
goto not_ssh2_blob; /* sorry */
|
||||
|
||||
strcpy(key, q);
|
||||
return TRUE;
|
||||
}
|
||||
not_ssh2_blob:;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
Reference in New Issue
Block a user