# include "phantasmal/ssh.h"
# include "phantasmal/ssh_asn1.h"
# define BASE64 ("...........................................\x3e..." + \
"\x3f\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d...=..." + \
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c" + \
"\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19" + \
"......" + \
"\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26" + \
"\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33" + \
"...................................................." + \
"...................................................." + \
".............................")
/*
* NAME: base64_decode()
* DESCRIPTION: decode a base64 string
*/
static string base64_decode(string str)
{
string result, bits;
int i, len, b1, b2, b3, b4;
result = "";
bits = "...";
for (i = 0, len = strlen(str); i < len; i += 4) {
b1 = BASE64[str[i]];
b2 = BASE64[str[i + 1]];
b3 = BASE64[str[i + 2]];
b4 = BASE64[str[i + 3]];
bits[0] = (b1 << 2) | (b2 >> 4);
bits[1] = (b2 << 4) | (b3 >> 2);
bits[2] = (b3 << 6) | b4;
result += bits;
}
if (b3 == '=') {
return result[.. strlen(result) - 3];
} else if (b4 == '=') {
return result[.. strlen(result) - 2];
}
return result;
}
/*
* NAME: parse_public_key()
* DESCRIPTION: check for a valid (DSA) public key.
*/
static string parse_public_key(string str)
{
if (sscanf(str, "ssh-dss %s ", str) == 0 &&
sscanf(str, "ssh-rsa %s ", str) == 0) {
return nil;
}
return base64_decode(str);
}
/*
* NAME: parse_private_key()
* DESCRIPTION: check for a valid (DSA) private key.
*/
static string parse_private_key(string str)
{
if (sscanf(str, "-----BEGIN DSA PRIVATE KEY-----%s" +
"-----END DSA PRIVATE KEY-----", str) == 0) {
return nil;
}
str = implode(explode(str, "\r"), "");
sscanf(str, "%*s\n\n%s", str); /* skip possible comments */
return base64_decode(implode(explode(str, "\n"), ""));
}
/*
* NAME: hexdump()
* DESCRIPTION: dump the string in hexadecimal form.
*/
static string hexdump(string str)
{
int i, len;
string result;
result = str + str + str;
len = strlen(str);
if (!len) {
return "";
}
for (i = 0; i < len; i++) {
int ch;
result[i * 3 + 0] = ':';
ch = str[i];
switch (ch >> 4) {
case 0.. 9:
result[i * 3 + 1] = '0' + (ch >> 4);
break;
case 10..15:
result[i * 3 + 1] = 'A' + (ch >> 4) - 10;
break;
}
switch (ch & 0x0f) {
case 0.. 9:
result[i * 3 + 2] = '0' + (ch & 0x0f);
break;
case 10..15:
result[i * 3 + 2] = 'A' + (ch & 0x0f) - 10;
break;
}
}
return result[1..];
}
/*
* NAME: random_string()
* DESCRIPTION: create a string of pseudo-random bytes
*/
static string random_string(int length)
{
string str;
int n, rand;
str = "................................";
while (strlen(str) < length) {
str += str;
}
str = str[.. length - 1];
for (n = length - length % 3; n != 0; ) {
/* create three random bytes at a time */
rand = random(0x1000000);
str[--n] = rand >> 16;
str[--n] = rand >> 8;
str[--n] = rand;
}
switch (length % 3) {
case 1:
str[length - 1] = random(0x100);
break;
case 2:
rand = random(0x10000);
str[length - 2] = rand >> 8;
str[length - 1] = rand;
break;
}
return str;
}
/*
* NAME: better_random_string()
* DESCRIPTION: create a slightly more random string
*/
static string better_random_string(int length)
{
string str;
str = "";
while (length >= 20) {
str += hash_sha1(random_string(20));
length -= 20;
}
if (length >= 0) {
str += hash_sha1(random_string(length))[.. length - 1];
}
return str;
}
/*
* NAME: make_int()
* DESCRIPTION: build a SSH int
*/
static string make_int(int i)
{
string str;
str = "....";
str[0] = i >> 24;
str[1] = i >> 16;
str[2] = i >> 8;
str[3] = i;
return str;
}
/*
* NAME: make_string()
* DESCRIPTION: build a SSH string
*/
static string make_string(string str)
{
string header;
int length;
length = strlen(str);
header = "\0\0..";
header[2] = length >> 8;
header[3] = length;
return header + str;
}
/*
* NAME: make_mpint()
* DESCRIPTION: build a multi-precision integer
*/
static string make_mpint(string str)
{
string header;
int length;
length = strlen(str);
header = "\0\0..";
header[2] = length >> 8;
header[3] = length;
return header + str;
}
/*
* NAME: make_mesg()
* DESCRIPTION: create a message code
*/
static string make_mesg(int code)
{
string str;
str = ".";
str[0] = code;
return str;
}
/*
* NAME: get_int()
* DESCRIPTION: get an int from a buffer
*/
static int get_int(string b, int i)
{
return (b[i] << 24) + (b[i + 1] << 16) + (b[i + 2] << 8) + b[i + 3];
}
/*
* NAME: get_string()
* DESCRIPTION: get a string from a buffer
*/
static string get_string(string b, int i)
{
return b[i + 4 .. i + (b[i] << 24) + (b[i + 1] << 16) + (b[i + 2] << 8) +
b[i + 3] + 3];
}
/*
* NAME: get_mpint()
* DESCRIPTION: get a multi-precision integer from a buffer
*/
static string get_mpint(string b, int i)
{
int len;
len = (b[i] << 24) + (b[i + 1] << 16) + (b[i + 2] << 8) + b[i + 3];
return b[i + 4 .. i + 3 + len];
}
#define STRCASE(foo) case foo: return #foo
/*
* NAME: dump_packet_type()
* DESCRIPTION: show the packet type in symbolic form
*/
static string dump_ssh_msg_type(int type)
{
switch (type) {
STRCASE(SSH_MSG_DISCONNECT);
STRCASE(SSH_MSG_IGNORE);
STRCASE(SSH_MSG_UNIMPLEMENTED);
STRCASE(SSH_MSG_DEBUG);
STRCASE(SSH_MSG_SERVICE_REQUEST);
STRCASE(SSH_MSG_SERVICE_ACCEPT);
STRCASE(SSH_MSG_KEXINIT);
STRCASE(SSH_MSG_NEWKEYS);
STRCASE(SSH_MSG_KEXDH_INIT);
STRCASE(SSH_MSG_KEXDH_REPLY);
STRCASE(SSH_MSG_USERAUTH_REQUEST);
STRCASE(SSH_MSG_USERAUTH_FAILURE);
STRCASE(SSH_MSG_USERAUTH_SUCCESS);
STRCASE(SSH_MSG_USERAUTH_BANNER);
STRCASE(SSH_MSG_USERAUTH_PK_OK);
STRCASE(SSH_MSG_GLOBAL_REQUEST);
STRCASE(SSH_MSG_REQUEST_SUCCESS);
STRCASE(SSH_MSG_REQUEST_FAILURE);
STRCASE(SSH_MSG_CHANNEL_OPEN);
STRCASE(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
STRCASE(SSH_MSG_CHANNEL_OPEN_FAILURE);
STRCASE(SSH_MSG_CHANNEL_WINDOW_ADJUST);
STRCASE(SSH_MSG_CHANNEL_DATA);
STRCASE(SSH_MSG_CHANNEL_EXTENDED_DATA);
STRCASE(SSH_MSG_CHANNEL_EOF);
STRCASE(SSH_MSG_CHANNEL_CLOSE);
STRCASE(SSH_MSG_CHANNEL_REQUEST);
STRCASE(SSH_MSG_CHANNEL_SUCCESS);
STRCASE(SSH_MSG_CHANNEL_FAILURE);
default:
return "Unknown(" + type + ")";
}
}
static string dump_ssh_disconnect_type(int type)
{
switch (type) {
STRCASE(SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT);
STRCASE(SSH_DISCONNECT_PROTOCOL_ERROR);
STRCASE(SSH_DISCONNECT_KEY_EXCHANGE_FAILED);
STRCASE(SSH_DISCONNECT_RESERVED);
STRCASE(SSH_DISCONNECT_MAC_ERROR);
STRCASE(SSH_DISCONNECT_COMPRESSION_ERROR);
STRCASE(SSH_DISCONNECT_SERVICE_NOT_AVAILABLE);
STRCASE(SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED);
STRCASE(SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
STRCASE(SSH_DISCONNECT_CONNECTON_LOST);
STRCASE(SSH_DISCONNECT_BY_APPLICATION);
STRCASE(SSH_DISCONNECT_TOO_MANY_CONNECTONS);
STRCASE(SSH_DISCONNECT_AUTH_CANCELED_BY_USER);
STRCASE(SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE);
STRCASE(SSH_DISCONNECT_ILLEGAL_USER_NAME);
default:
return "Unknown (" + type + ")";
}
}
static string dump_ssh_open_type(int type)
{
switch (type) {
STRCASE(SSH_OPEN_ADMINISTRATIVELY_PROHIBITED);
STRCASE(SSH_OPEN_CONNECT_FAILED);
STRCASE(SSH_OPEN_UNKNOWN_CHANNEL_TYPE);
STRCASE(SSH_OPEN_RESOURCE_SHORTAGE);
default:
return "Unknown (" + type + ")";
}
}