163afb9a5SDavid du Colombier #include <bio.h> 263afb9a5SDavid du Colombier #include "ssh2.h" /* ugh */ 363afb9a5SDavid du Colombier 463afb9a5SDavid du Colombier #define MYID "SSH-2.0-Plan9" 563afb9a5SDavid du Colombier 663afb9a5SDavid du Colombier #pragma varargck type "M" mpint* 763afb9a5SDavid du Colombier 863afb9a5SDavid du Colombier enum { 963afb9a5SDavid du Colombier Server = 0, 1063afb9a5SDavid du Colombier Client, 1163afb9a5SDavid du Colombier 1263afb9a5SDavid du Colombier Maxpktpay = 35000, 1363afb9a5SDavid du Colombier 1463afb9a5SDavid du Colombier /* qid.path components: level (2), type (4), conn (7), chan (7) */ 1563afb9a5SDavid du Colombier Connshift = 7, 1663afb9a5SDavid du Colombier MAXCONN = 1 << Connshift, /* also Maxchan */ 1763afb9a5SDavid du Colombier Chanmask = MAXCONN - 1, 1863afb9a5SDavid du Colombier Connmask = Chanmask, 1963afb9a5SDavid du Colombier 2063afb9a5SDavid du Colombier Qtypeshift = 2 * Connshift, /* conn + chan */ 2163afb9a5SDavid du Colombier 2263afb9a5SDavid du Colombier Qroot = 0, 2363afb9a5SDavid du Colombier Qclone = 1 << Qtypeshift, 2463afb9a5SDavid du Colombier Qctl = 2 << Qtypeshift, 2563afb9a5SDavid du Colombier Qdata = 3 << Qtypeshift, 2663afb9a5SDavid du Colombier Qlisten = 4 << Qtypeshift, 2763afb9a5SDavid du Colombier Qlocal = 5 << Qtypeshift, 2863afb9a5SDavid du Colombier Qreqrem = 6 << Qtypeshift, /* request or remote */ 2963afb9a5SDavid du Colombier Qstatus = 7 << Qtypeshift, 3063afb9a5SDavid du Colombier Qtcp = 8 << Qtypeshift, 3163afb9a5SDavid du Colombier Qtypemask = 017 << Qtypeshift, 3263afb9a5SDavid du Colombier 3363afb9a5SDavid du Colombier Levshift = Qtypeshift + 4, 3463afb9a5SDavid du Colombier 3563afb9a5SDavid du Colombier /* levels of /net/ssh hierarchy */ 3663afb9a5SDavid du Colombier Top = 0, 3763afb9a5SDavid du Colombier Connection, 3863afb9a5SDavid du Colombier Subchannel, 3963afb9a5SDavid du Colombier }; 4063afb9a5SDavid du Colombier 4163afb9a5SDavid du Colombier /* 4263afb9a5SDavid du Colombier * The stylistic anomaly with these names of unbounded length 4363afb9a5SDavid du Colombier * is a result of following the RFCs in using the same names for 4463afb9a5SDavid du Colombier * these constants. I did that to make it easier to search and 4563afb9a5SDavid du Colombier * cross-reference between the code and the RFCs. 4663afb9a5SDavid du Colombier */ 4763afb9a5SDavid du Colombier enum { /* SSH2 Protocol Packet Types */ 4863afb9a5SDavid du Colombier SSH_MSG_DISCONNECT = 1, 4963afb9a5SDavid du Colombier SSH_MSG_IGNORE = 2, 5063afb9a5SDavid du Colombier SSH_MSG_UNIMPLEMENTED, 5163afb9a5SDavid du Colombier SSH_MSG_DEBUG, 5263afb9a5SDavid du Colombier SSH_MSG_SERVICE_REQUEST, 5363afb9a5SDavid du Colombier SSH_MSG_SERVICE_ACCEPT, 5463afb9a5SDavid du Colombier 5563afb9a5SDavid du Colombier SSH_MSG_KEXINIT = 20, 5663afb9a5SDavid du Colombier SSH_MSG_NEWKEYS, 5763afb9a5SDavid du Colombier 5863afb9a5SDavid du Colombier SSH_MSG_KEXDH_INIT = 30, 5963afb9a5SDavid du Colombier SSH_MSG_KEXDH_REPLY, 6063afb9a5SDavid du Colombier 6163afb9a5SDavid du Colombier SSH_MSG_USERAUTH_REQUEST = 50, 6263afb9a5SDavid du Colombier SSH_MSG_USERAUTH_FAILURE, 6363afb9a5SDavid du Colombier SSH_MSG_USERAUTH_SUCCESS, 6463afb9a5SDavid du Colombier SSH_MSG_USERAUTH_BANNER, 6563afb9a5SDavid du Colombier 6663afb9a5SDavid du Colombier SSH_MSG_USERAUTH_PK_OK = 60, 6763afb9a5SDavid du Colombier SSH_MSG_USERAUTH_PASSWD_CHANGEREQ = 60, 6863afb9a5SDavid du Colombier 6963afb9a5SDavid du Colombier SSH_MSG_GLOBAL_REQUEST = 80, 7063afb9a5SDavid du Colombier SSH_MSG_REQUEST_SUCCESS, 7163afb9a5SDavid du Colombier SSH_MSG_REQUEST_FAILURE, 7263afb9a5SDavid du Colombier 7363afb9a5SDavid du Colombier SSH_MSG_CHANNEL_OPEN = 90, 7463afb9a5SDavid du Colombier SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 7563afb9a5SDavid du Colombier SSH_MSG_CHANNEL_OPEN_FAILURE, 7663afb9a5SDavid du Colombier SSH_MSG_CHANNEL_WINDOW_ADJUST, 7763afb9a5SDavid du Colombier SSH_MSG_CHANNEL_DATA, 7863afb9a5SDavid du Colombier SSH_MSG_CHANNEL_EXTENDED_DATA, 7963afb9a5SDavid du Colombier SSH_MSG_CHANNEL_EOF, 8063afb9a5SDavid du Colombier SSH_MSG_CHANNEL_CLOSE, 8163afb9a5SDavid du Colombier SSH_MSG_CHANNEL_REQUEST, 8263afb9a5SDavid du Colombier SSH_MSG_CHANNEL_SUCCESS, 8363afb9a5SDavid du Colombier SSH_MSG_CHANNEL_FAILURE, 8463afb9a5SDavid du Colombier }; 8563afb9a5SDavid du Colombier 8663afb9a5SDavid du Colombier enum { /* SSH2 reason codes */ 8763afb9a5SDavid du Colombier SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1, 8863afb9a5SDavid du Colombier SSH_DISCONNECT_PROTOCOL_ERROR, 8963afb9a5SDavid du Colombier SSH_DISCONNECT_KEY_EXCHANGE_FAILED, 9063afb9a5SDavid du Colombier SSH_DISCONNECT_RESERVED, 9163afb9a5SDavid du Colombier SSH_DISCONNECT_MAC_ERROR, 9263afb9a5SDavid du Colombier SSH_DISCONNECT_COMPRESSION_ERROR, 9363afb9a5SDavid du Colombier SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, 9463afb9a5SDavid du Colombier SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, 9563afb9a5SDavid du Colombier SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 9663afb9a5SDavid du Colombier SSH_DISCONNECT_CONNECTION_LOST, 9763afb9a5SDavid du Colombier SSH_DISCONNECT_BY_APPLICATION, 9863afb9a5SDavid du Colombier SSH_DISCONNECT_TOO_MANY_CONNECTIONS, 9963afb9a5SDavid du Colombier SSH_DISCONNECT_AUTH_CANCELLED_BY_USER, 10063afb9a5SDavid du Colombier SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, 10163afb9a5SDavid du Colombier SSH_DISCONNECT_ILLEGAL_USR_NAME, 10263afb9a5SDavid du Colombier 10363afb9a5SDavid du Colombier SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1, 10463afb9a5SDavid du Colombier SSH_OPEN_CONNECT_FAILED, 10563afb9a5SDavid du Colombier SSH_OPEN_UNKNOWN_CHANNEL_TYPE, 10663afb9a5SDavid du Colombier SSH_OPEN_RESOURCE_SHORTAGE, 10763afb9a5SDavid du Colombier }; 10863afb9a5SDavid du Colombier 10963afb9a5SDavid du Colombier enum { /* SSH2 type code */ 11063afb9a5SDavid du Colombier SSH_EXTENDED_DATA_STDERR = 1, 11163afb9a5SDavid du Colombier }; 11263afb9a5SDavid du Colombier 11363afb9a5SDavid du Colombier enum { /* connection and channel states */ 11463afb9a5SDavid du Colombier Empty = 0, 11563afb9a5SDavid du Colombier Allocated, 11663afb9a5SDavid du Colombier Initting, 11763afb9a5SDavid du Colombier Listening, 11863afb9a5SDavid du Colombier Opening, 11963afb9a5SDavid du Colombier Negotiating, 12063afb9a5SDavid du Colombier Authing, 12163afb9a5SDavid du Colombier Established, 12263afb9a5SDavid du Colombier Eof, 12363afb9a5SDavid du Colombier Closing, 12463afb9a5SDavid du Colombier Closed, 12563afb9a5SDavid du Colombier }; 12663afb9a5SDavid du Colombier 12763afb9a5SDavid du Colombier enum { 12863afb9a5SDavid du Colombier NoKeyFile, 12963afb9a5SDavid du Colombier NoKey, 13063afb9a5SDavid du Colombier KeyWrong, 13163afb9a5SDavid du Colombier KeyOk, 13263afb9a5SDavid du Colombier }; 13363afb9a5SDavid du Colombier 13463afb9a5SDavid du Colombier typedef struct Cipher Cipher; 13563afb9a5SDavid du Colombier typedef struct CipherState CipherState; 13663afb9a5SDavid du Colombier typedef struct Conn Conn; 13763afb9a5SDavid du Colombier typedef struct Kex Kex; 13863afb9a5SDavid du Colombier typedef struct MBox MBox; 13963afb9a5SDavid du Colombier typedef struct PKA PKA; 14063afb9a5SDavid du Colombier typedef struct Packet Packet; 14163afb9a5SDavid du Colombier typedef struct Plist Plist; 14263afb9a5SDavid du Colombier typedef struct SSHChan SSHChan; 14363afb9a5SDavid du Colombier 14463afb9a5SDavid du Colombier #pragma incomplete CipherState 14563afb9a5SDavid du Colombier 14663afb9a5SDavid du Colombier struct Plist { 14763afb9a5SDavid du Colombier Packet *pack; 14863afb9a5SDavid du Colombier uchar *st; 14963afb9a5SDavid du Colombier int rem; 15063afb9a5SDavid du Colombier Plist *next; 15163afb9a5SDavid du Colombier }; 15263afb9a5SDavid du Colombier 15363afb9a5SDavid du Colombier struct SSHChan { 15463afb9a5SDavid du Colombier Rendez r; /* awaiting input? */ 15563afb9a5SDavid du Colombier int id; 15663afb9a5SDavid du Colombier int otherid; 15763afb9a5SDavid du Colombier int state; 15863afb9a5SDavid du Colombier int waker; 15963afb9a5SDavid du Colombier int conn; 16063afb9a5SDavid du Colombier ulong rwindow; 16163afb9a5SDavid du Colombier ulong twindow; 16263afb9a5SDavid du Colombier ulong sent; 16363afb9a5SDavid du Colombier ulong inrqueue; 16463afb9a5SDavid du Colombier char *ann; 16563afb9a5SDavid du Colombier Req *lreq; 16663afb9a5SDavid du Colombier 16763afb9a5SDavid du Colombier /* File* for each Qid type */ 16863afb9a5SDavid du Colombier File *dir; 16963afb9a5SDavid du Colombier File *ctl; 17063afb9a5SDavid du Colombier File *data; 17163afb9a5SDavid du Colombier File *listen; 17263afb9a5SDavid du Colombier File *request; 17363afb9a5SDavid du Colombier File *status; 17463afb9a5SDavid du Colombier File *tcp; 17563afb9a5SDavid du Colombier 17663afb9a5SDavid du Colombier Plist *dataq; 17763afb9a5SDavid du Colombier Plist *datatl; 17863afb9a5SDavid du Colombier Plist *reqq; 17963afb9a5SDavid du Colombier Plist *reqtl; 18063afb9a5SDavid du Colombier 18163afb9a5SDavid du Colombier Channel *inchan; 18263afb9a5SDavid du Colombier Channel *reqchan; 18363afb9a5SDavid du Colombier QLock xmtlock; 18463afb9a5SDavid du Colombier Rendez xmtrendez; 18563afb9a5SDavid du Colombier }; 18663afb9a5SDavid du Colombier 18763afb9a5SDavid du Colombier struct Conn { 18863afb9a5SDavid du Colombier QLock l; 18963afb9a5SDavid du Colombier Rendez r; /* awaiting input? */ 19063afb9a5SDavid du Colombier 19163afb9a5SDavid du Colombier Ioproc *dio; 19263afb9a5SDavid du Colombier Ioproc *cio; 19363afb9a5SDavid du Colombier Ioproc *rio; 19463afb9a5SDavid du Colombier 19563afb9a5SDavid du Colombier int state; 19663afb9a5SDavid du Colombier int role; 19763afb9a5SDavid du Colombier int id; 19863afb9a5SDavid du Colombier 19963afb9a5SDavid du Colombier char *remote; 20063afb9a5SDavid du Colombier char *user; 20163afb9a5SDavid du Colombier char *password; 20263afb9a5SDavid du Colombier 20363afb9a5SDavid du Colombier char *service; 20463afb9a5SDavid du Colombier char *cap; 20563afb9a5SDavid du Colombier char *authkey; 20663afb9a5SDavid du Colombier int nchan; 20763afb9a5SDavid du Colombier 20863afb9a5SDavid du Colombier /* underlying tcp connection */ 20963afb9a5SDavid du Colombier int datafd; 21063afb9a5SDavid du Colombier int ctlfd; 21163afb9a5SDavid du Colombier int stifle; /* flag: no i/o between listen and sshsession */ 21263afb9a5SDavid du Colombier int poisoned; 21363afb9a5SDavid du Colombier int tcpconn; 21463afb9a5SDavid du Colombier 21563afb9a5SDavid du Colombier int rpid; 21663afb9a5SDavid du Colombier 21763afb9a5SDavid du Colombier int inseq; 21863afb9a5SDavid du Colombier int outseq; 21963afb9a5SDavid du Colombier int kexalg; 22063afb9a5SDavid du Colombier int pkalg; 22163afb9a5SDavid du Colombier 22263afb9a5SDavid du Colombier int cscrypt; 22363afb9a5SDavid du Colombier int ncscrypt; 22463afb9a5SDavid du Colombier int sccrypt; 22563afb9a5SDavid du Colombier int nsccrypt; 22663afb9a5SDavid du Colombier 22763afb9a5SDavid du Colombier int csmac; 22863afb9a5SDavid du Colombier int ncsmac; 22963afb9a5SDavid du Colombier int scmac; 23063afb9a5SDavid du Colombier int nscmac; 23163afb9a5SDavid du Colombier 23263afb9a5SDavid du Colombier int encrypt; 23363afb9a5SDavid du Colombier int decrypt; 23463afb9a5SDavid du Colombier 23563afb9a5SDavid du Colombier int outmac; 23663afb9a5SDavid du Colombier int inmac; 23763afb9a5SDavid du Colombier 23863afb9a5SDavid du Colombier /* File* for each Qid type */ 23963afb9a5SDavid du Colombier File *dir; 24063afb9a5SDavid du Colombier File *clonefile; 24163afb9a5SDavid du Colombier File *ctlfile; 24263afb9a5SDavid du Colombier File *datafile; 24363afb9a5SDavid du Colombier File *listenfile; 24463afb9a5SDavid du Colombier File *localfile; 24563afb9a5SDavid du Colombier File *remotefile; 24663afb9a5SDavid du Colombier File *statusfile; 24763afb9a5SDavid du Colombier File *tcpfile; 24863afb9a5SDavid du Colombier 24963afb9a5SDavid du Colombier Packet *skexinit; 25063afb9a5SDavid du Colombier Packet *rkexinit; 25163afb9a5SDavid du Colombier mpint *x; 25263afb9a5SDavid du Colombier mpint *e; 25363afb9a5SDavid du Colombier int got_sessid; 25463afb9a5SDavid du Colombier uchar sessid[SHA1dlen]; 25563afb9a5SDavid du Colombier 25663afb9a5SDavid du Colombier uchar c2siv[SHA1dlen*2]; 25763afb9a5SDavid du Colombier uchar nc2siv[SHA1dlen*2]; 25863afb9a5SDavid du Colombier uchar s2civ[SHA1dlen*2]; 25963afb9a5SDavid du Colombier uchar ns2civ[SHA1dlen*2]; 26063afb9a5SDavid du Colombier 26163afb9a5SDavid du Colombier uchar c2sek[SHA1dlen*2]; 26263afb9a5SDavid du Colombier uchar nc2sek[SHA1dlen*2]; 26363afb9a5SDavid du Colombier uchar s2cek[SHA1dlen*2]; 26463afb9a5SDavid du Colombier uchar ns2cek[SHA1dlen*2]; 26563afb9a5SDavid du Colombier 26663afb9a5SDavid du Colombier uchar c2sik[SHA1dlen*2]; 26763afb9a5SDavid du Colombier uchar nc2sik[SHA1dlen*2]; 26863afb9a5SDavid du Colombier uchar s2cik[SHA1dlen*2]; 26963afb9a5SDavid du Colombier uchar ns2cik[SHA1dlen*2]; 27063afb9a5SDavid du Colombier 27163afb9a5SDavid du Colombier char *otherid; 27263afb9a5SDavid du Colombier uchar *inik; 27363afb9a5SDavid du Colombier uchar *outik; 27463afb9a5SDavid du Colombier CipherState *s2ccs; 27563afb9a5SDavid du Colombier CipherState *c2scs; 27663afb9a5SDavid du Colombier CipherState *enccs; 27763afb9a5SDavid du Colombier CipherState *deccs; 27863afb9a5SDavid du Colombier SSHChan *chans[MAXCONN]; 27963afb9a5SDavid du Colombier 28063afb9a5SDavid du Colombier char idstring[256]; /* max allowed by SSH spec */ 28163afb9a5SDavid du Colombier }; 28263afb9a5SDavid du Colombier 28363afb9a5SDavid du Colombier struct Packet { 28463afb9a5SDavid du Colombier Conn *c; 28563afb9a5SDavid du Colombier ulong rlength; 28663afb9a5SDavid du Colombier ulong tlength; 28763afb9a5SDavid du Colombier uchar nlength[4]; 28863afb9a5SDavid du Colombier uchar pad_len; 28963afb9a5SDavid du Colombier uchar payload[Maxpktpay]; 29063afb9a5SDavid du Colombier }; 29163afb9a5SDavid du Colombier 29263afb9a5SDavid du Colombier struct Cipher { 29363afb9a5SDavid du Colombier char *name; 29463afb9a5SDavid du Colombier int blklen; 29563afb9a5SDavid du Colombier CipherState *(*init)(Conn*, int); 29663afb9a5SDavid du Colombier void (*encrypt)(CipherState*, uchar*, int); 29763afb9a5SDavid du Colombier void (*decrypt)(CipherState*, uchar*, int); 29863afb9a5SDavid du Colombier }; 29963afb9a5SDavid du Colombier 30063afb9a5SDavid du Colombier struct Kex { 30163afb9a5SDavid du Colombier char *name; 30263afb9a5SDavid du Colombier int (*serverkex)(Conn *, Packet *); 30363afb9a5SDavid du Colombier int (*clientkex1)(Conn *, Packet *); 30463afb9a5SDavid du Colombier int (*clientkex2)(Conn *, Packet *); 30563afb9a5SDavid du Colombier }; 30663afb9a5SDavid du Colombier 30763afb9a5SDavid du Colombier struct PKA { 30863afb9a5SDavid du Colombier char *name; 30963afb9a5SDavid du Colombier Packet *(*ks)(Conn *); 31063afb9a5SDavid du Colombier Packet *(*sign)(Conn *, uchar *, int); 31163afb9a5SDavid du Colombier int (*verify)(Conn *, uchar *, int, char *, char *, int); 31263afb9a5SDavid du Colombier }; 31363afb9a5SDavid du Colombier 31463afb9a5SDavid du Colombier struct MBox { 31563afb9a5SDavid du Colombier Channel *mchan; 31663afb9a5SDavid du Colombier char *msg; 31763afb9a5SDavid du Colombier int state; 31863afb9a5SDavid du Colombier }; 31963afb9a5SDavid du Colombier 32063afb9a5SDavid du Colombier extern Cipher cipheraes128, cipheraes192, cipheraes256; 321*c7034505SDavid du Colombier extern Cipher cipheraes128ctr, cipheraes192ctr, cipheraes256ctr; 32263afb9a5SDavid du Colombier extern Cipher cipherblowfish, cipher3des, cipherrc4; 32363afb9a5SDavid du Colombier extern int debug; 32463afb9a5SDavid du Colombier extern int sshkeychan[]; 32563afb9a5SDavid du Colombier extern Kex dh1sha1, dh14sha1; 32663afb9a5SDavid du Colombier extern MBox keymbox; 32763afb9a5SDavid du Colombier extern PKA rsa_pka, dss_pka, *pkas[]; 32863afb9a5SDavid du Colombier 32963afb9a5SDavid du Colombier /* pubkey.c */ 33063afb9a5SDavid du Colombier int appendkey(char *, char *, RSApub *); 33163afb9a5SDavid du Colombier int findkey(char *, char *, RSApub *); 33263afb9a5SDavid du Colombier RSApub *readpublickey(Biobuf *, char **); 33363afb9a5SDavid du Colombier int replacekey(char *, char *, RSApub *); 33463afb9a5SDavid du Colombier 33563afb9a5SDavid du Colombier /* dh.c */ 33663afb9a5SDavid du Colombier void dh_init(PKA *[]); 33763afb9a5SDavid du Colombier 33863afb9a5SDavid du Colombier /* transport.c */ 33963afb9a5SDavid du Colombier void add_block(Packet *, void *, int); 34063afb9a5SDavid du Colombier void add_byte(Packet *, char); 34163afb9a5SDavid du Colombier void add_mp(Packet *, mpint *); 34263afb9a5SDavid du Colombier int add_packet(Packet *, void *, int); 34363afb9a5SDavid du Colombier void add_string(Packet *, char *); 34463afb9a5SDavid du Colombier void add_uint32(Packet *, ulong); 34563afb9a5SDavid du Colombier void dump_packet(Packet *); 34663afb9a5SDavid du Colombier int finish_packet(Packet *); 34763afb9a5SDavid du Colombier mpint *get_mp(uchar *q); 34863afb9a5SDavid du Colombier uchar *get_string(Packet *, uchar *, char *, int, int *); 34963afb9a5SDavid du Colombier ulong get_uint32(Packet *, uchar **); 35063afb9a5SDavid du Colombier void init_packet(Packet *); 35163afb9a5SDavid du Colombier Packet *new_packet(Conn *); 35263afb9a5SDavid du Colombier int undo_packet(Packet *); 353