1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00
putty-source/utils/validate_manual_hostkey.c

122 lines
3.8 KiB
C
Raw Permalink Normal View History

/*
* 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.
*/
#include <string.h>
#include <ctype.h>
#include "putty.h"
#include "misc.h"
#define BASE64_CHARS_NOEQ \
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
#define BASE64_CHARS_ALL BASE64_CHARS_NOEQ "="
bool 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 (strstartswith(q, "SHA256:")) {
/* Test for a valid SHA256 key fingerprint. */
r = q + 7;
if (strspn(r, BASE64_CHARS_NOEQ) == 43) {
memmove(key, q, 50); /* 7-char prefix + 43-char base64 */
key[50] = '\0';
return true;
}
}
r = q;
if (strstartswith(r, "MD5:"))
r += 4;
if (strlen(r) == 16*3 - 1 &&
r[strspn(r, "0123456789abcdefABCDEF:")] == 0) {
/*
* Test for a valid MD5 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 (r[3*i] == ':' || r[3*i+1] == ':')
goto not_fingerprint; /* sorry */
for (i = 0; i < 15; i++)
if (r[3*i+2] != ':')
goto not_fingerprint; /* sorry */
for (i = 0; i < 16*3 - 1; i++)
key[i] = tolower((unsigned char)r[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, BASE64_CHARS_ALL)] == 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 */
size_t base64_len = strspn(q, BASE64_CHARS_ALL);
memmove(key, q, base64_len);
key[base64_len] = '\0';
return true;
}
not_ssh2_blob:;
}
return false;
}