henesyinit from p9f0ed2a895 years agoHistory
410 lines · 8.4 KB · C
RawDownload
#include <u.h>#include <libc.h> #include "ssh.h" #define CRC(c) crc = crctab[(crc ^ (c)) & 0xff] ^ (crc >> 8)/* This evaluates c only once */ ulong	crctab[256]; DESstate	inDESstate[3], outDESstate[3]; RC4state	rc4c2skey, rc4s2ckey; char *packet_names[] = {	[0] = "SSH_MSG_NONE",	[1] = "SSH_MSG_DISCONNECT",	[2] = "SSH_SMSG_PUBLIC_KEY",	[3] = "SSH_CMSG_SESSION_KEY",	[4] = "SSH_CMSG_USER",	[5] = "SSH_CMSG_AUTH_RHOSTS",	[6] = "SSH_CMSG_AUTH_RSA",	[7] = "SSH_SMSG_AUTH_RSA_CHALLENGE",	[8] = "SSH_CMSG_AUTH_RSA_RESPONSE",	[9] = "SSH_CMSG_AUTH_PASSWORD",	[10] = "SSH_CMSG_REQUEST_PTY",	[11] = "SSH_CMSG_WINDOW_SIZE",	[12] = "SSH_CMSG_EXEC_SHELL",	[13] = "SSH_CMSG_EXEC_CMD",	[14] = "SSH_SMSG_SUCCESS",	[15] = "SSH_SMSG_FAILURE",	[16] = "SSH_CMSG_STDIN_DATA",	[17] = "SSH_SMSG_STDOUT_DATA",	[18] = "SSH_SMSG_STDERR_DATA",	[19] = "SSH_CMSG_EOF",	[20] = "SSH_SMSG_EXITSTATUS",	[21] = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",	[22] = "SSH_MSG_CHANNEL_OPEN_FAILURE",	[23] = "SSH_MSG_CHANNEL_DATA",	[24] = "SSH_MSG_CHANNEL_CLOSE",	[25] = "SSH_MSG_CHANNEL_CLOSE_CONFIRMATION",	[27] = "SSH_SMSG_X11_OPEN",	[28] = "SSH_CMSG_PORT_FORWARD_REQUEST",	[29] = "SSH_MSG_PORT_OPEN",	[30] = "SSH_CMSG_AGENT_REQUEST_FORWARDING",	[31] = "SSH_SMSG_AGENT_OPEN",	[32] = "SSH_MSG_IGNORE",	[33] = "SSH_CMSG_EXIT_CONFIRMATION",	[34] = "SSH_CMSG_X11_REQUEST_FORWARDING",	[35] = "SSH_CMSG_AUTH_RHOSTS_RSA",	[36] = "SSH_MSG_DEBUG",	[37] = "SSH_CMSG_REQUEST_COMPRESSION",	[38] = "SSH_CMSG_MAX_PACKET_SIZE",	[39] = "SSH_CMSG_AUTH_TIS",	[40] = "SSH_SMSG_AUTH_TIS_CHALLENGE",	[41] = "SSH_CMSG_AUTH_TIS_RESPONSE",	[42] = "SSH_CMSG_AUTH_KERBEROS",	[43] = "SSH_SMSG_AUTH_KERBEROS_RESPONSE",	[44] = "SSH_CMSG_HAVE_KERBEROS_TGT"}; voidpreparekey() {	switch (encryption) {	case SSH_CIPHER_NONE:		break;	case SSH_CIPHER_IDEA:		error("Not implemented");	case SSH_CIPHER_DES:		setupDESstate(&inDESstate[0], session_key, nil);		setupDESstate(&outDESstate[0], session_key, nil);		break;	case SSH_CIPHER_3DES:		setupDESstate(&inDESstate[0], session_key, nil);		setupDESstate(&outDESstate[0], session_key, nil);		setupDESstate(&inDESstate[1], session_key+8, nil);		setupDESstate(&outDESstate[1], session_key+8, nil);		setupDESstate(&inDESstate[2], session_key+16, nil);		setupDESstate(&outDESstate[2], session_key+16, nil);		break;	case SSH_CIPHER_TSS:		error("Not implemented");	case SSH_CIPHER_RC4:		setupRC4state(&rc4s2ckey, &session_key[0], 16);		setupRC4state(&rc4c2skey, &session_key[16], 16);		break;	}} Packet *getpacket(int direction) {	ulong	l;	int	n, c, i, pad;	Packet	*packet;	uchar	ll[4];	uchar	*p;	ulong	crc; 	n = readn(dfdin, ll, 4);	if (n != 4)		return 0; 	l = (ll[0]<<24) | (ll[1]<<16) | (ll[2]<<8) | ll[3]; 	/* allocate packet */	packet = (Packet *)mmalloc(sizeof(Packet) + l); 	pad = l & 7;	packet->length = l - 5;	/* Subtract length of CRC and type */	debug(DBG_PACKET, "Receiving packet, data length %lx, wire length %lx, padded length %lx\n",		packet->length, l, packet->length + 13 - pad);	l += 8 - pad; 	n = l;	i = pad;	while (n > 0) {		if ((c = read(dfdin, &packet->pad[i], n)) <= 0) {			mfree(packet);			return 0;		}		n -= c;		i += c;	} 	i = l;	p = &packet->pad[pad];	switch (encryption) {	case SSH_CIPHER_NONE:		break;	case SSH_CIPHER_IDEA:		error("Not implemented");	case SSH_CIPHER_DES:		desCBCdecrypt(p, i, &inDESstate[0]);		break;	case SSH_CIPHER_3DES:		desCBCdecrypt(p, i, &inDESstate[2]);		desCBCencrypt(p, i, &inDESstate[1]);		desCBCdecrypt(p, i, &inDESstate[0]);		break;	case SSH_CIPHER_TSS:		error("Not implemented");	case SSH_CIPHER_RC4:		if (direction == s2c)			rc4(&rc4s2ckey, p, i);		else			rc4(&rc4c2skey, p, i);		break;	} 	/* crc of pad bytes */	crc = 0;	for(i = pad; i < 8; i++) {		CRC(packet->pad[i]);	}	/* Calculate Remainder of CRC */	CRC(packet->type); 	i = packet->length;	p = packet->data;	while (i--) CRC(*p++); 	l = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];	if (l != crc) {		error("CRC error, calculated 0x%lx, actual 0x%lx", crc, l);		abort();	} else		debug(DBG_PACKET, "CRC = 0x%8.8x\n", crc); 	if (packet->type == SSH_MSG_DEBUG) {		free(packet);		return getpacket(direction);	}	if (packet->type == 0)		error("Impossible packet type");	debug(DBG_PACKET|DBG_PROTO, "Received %s Packet\n",		packet_names[packet->type]); 	packet->pos = packet->data;	return packet;} intputpacket(Packet *packet, int direction) {	ulong	l;	int	pad, i;	uchar	*p;	ulong	crc; 	l = packet->length + 5;	/* add type and CRC */ 	/* create pad bytes */	pad = l & 7; 	p = &(packet->pad[pad-4]);	/* Write length field */	/* This partially overwrites packet->length!! */	*p++ = l >> 24;	*p++ = l >> 16;	*p++ = l >>  8;	*p   = l      ; 	debug(DBG_PACKET|DBG_PROTO, "Sending %s Packet\n",		packet_names[packet->type]);	debug(DBG_PACKET, "Data length %lx, wire length %lx, pad length %lx\n",		l - 5 , l, 8 - pad); 	crc = 0;	for(i = pad; i < 8; i++) {		packet->pad[i] = encryption?nrand(0x100):0;		CRC(packet->pad[i]);	}	/* Calculate Remainder of CRC */	CRC(packet->type); 	i = l - 5;	p = packet->data;	while (i--) CRC(*p++); 	*p++ = crc >> 24;	*p++ = crc >> 16;	*p++ = crc >>  8;	*p   = crc; 	l += 8 - pad; 	debug(DBG_PACKET, "CRC = 0x%lux\n", crc); 	i = l;	p = &packet->pad[pad];	switch (encryption) {	case SSH_CIPHER_NONE:		break;	case SSH_CIPHER_IDEA:		error("Not implemented");	case SSH_CIPHER_DES:		desCBCencrypt(p, i, &outDESstate[0]);		break;	case SSH_CIPHER_3DES:		desCBCencrypt(p, i, &outDESstate[0]);		desCBCdecrypt(p, i, &outDESstate[1]);		desCBCencrypt(p, i, &outDESstate[2]);		break;	case SSH_CIPHER_TSS:		error("Not implemented");	case SSH_CIPHER_RC4:		if (direction == s2c)			rc4(&rc4s2ckey, p, i);		else			rc4(&rc4c2skey, p, i);		break;	}	if (write(dfdout, &packet->pad[pad-4], l+4) != l+4) {		mfree(packet);		return 1;	}	mfree(packet);	return 0;} voidmkcrctab(ulong poly){	ulong crc;	int i, j; 	for(i = 0; i < 256; i++){		crc = i;		for(j = 0; j < 8; j++){			if(crc & 1)				crc = (crc >> 1) ^ poly;			else				crc >>= 1;		}		crctab[i] = crc;	}} RSApub *getRSApublic(Packet *packet) {	RSApub *key;	ulong skl; 	skl = getlong(packet);	USED(skl);	key = rsapuballoc();	key->ek = getBigInt(packet);	key->n = getBigInt(packet);	setmalloctag(key, getcallerpc(&packet));	return key;} ulonggetlong(Packet *packet) {	ulong x; 	if (packet->length < 4) error("Packet too small");	packet->length -= 4;	x =            *(packet->pos)++;	x = (x << 8) | *(packet->pos)++;	x = (x << 8) | *(packet->pos)++;	x = (x << 8) | *(packet->pos)++;	return x;} ushortgetshort(Packet *packet) {	ushort x; 	if ((packet->length -= 2) < 0) error("Packet too small");	x =            *(packet->pos)++;	x = (x << 8) | *(packet->pos)++;	return x;} uchargetbyte(Packet *packet) { 	if (packet->length-- == 0) error("Packet too small");	return *(packet->pos)++;} voidgetbytes(Packet *packet, uchar *buf, int n) { 	if ((packet->length -= n) < 0) error("Packet too small");	while (n--) *buf++ = *(packet->pos)++;} intgetstring(Packet *packet, char *s, int n) {	ulong l; 	l = getlong(packet);	if (l >= n) {		error("Insufficient length for string, need %lud, have %d", l, n);		abort();	}	getbytes(packet, (uchar *)s, l);	s[l] = 0;	return l;} voidputstring(Packet *packet, char *s, int n) { 	putlong(packet, n);	putbytes(packet, (uchar *)s, n);} mpint*getBigInt(Packet *packet) {	ushort bytes;	uchar buf[1024]; 	bytes = (getshort(packet)+7) >> 3;	getbytes(packet, buf, bytes);	return betomp(buf, bytes, nil);} voidputlong(Packet *packet, ulong x) { 	packet->length += 4;	*(packet->pos)++ = x >> 24;	*(packet->pos)++ = x >> 16;	*(packet->pos)++ = x >>  8;	*(packet->pos)++ = x;} voidputshort(Packet *packet, ushort x) { 	packet->length += 2;	*(packet->pos)++ = x >>  8;	*(packet->pos)++ = x;} voidputbyte(Packet *packet, uchar x) { 	packet->length++;	*(packet->pos)++ = x;} voidputbytes(Packet *packet, uchar *buf, int n) { 	packet->length += n;	memmove(packet->pos, buf, n);	packet->pos += n;} voidputBigInt(Packet *packet, mpint *b) {	ushort bits, bytes;	uchar buf[1024]; 	bits = mpsignif(b);	bytes = mptobe(b, buf, 1024, nil);	putshort(packet, bits);	putbytes(packet, buf, bytes);if((bits+7)/8 != bytes) sysfatal("putBigInt %B(%d) %d bits, %d bytes", b, b->top, bits, bytes);} voidputRSApublic(Packet *packet, RSApub *key) { 	putlong(packet, mpsignif(key->n));	putBigInt(packet, key->ek);	putBigInt(packet, key->n);}