+++ /dev/null
-/*\r
- * Routines to do cryptographic interaction with proxies in PuTTY.\r
- * This is in a separate module from proxy.c, so that it can be\r
- * conveniently removed in PuTTYtel by replacing this module with\r
- * the stub version nocproxy.c.\r
- */\r
-\r
-#include <assert.h>\r
-#include <ctype.h>\r
-#include <string.h>\r
-\r
-#define DEFINE_PLUG_METHOD_MACROS\r
-#include "putty.h"\r
-#include "ssh.h" /* For MD5 support */\r
-#include "network.h"\r
-#include "proxy.h"\r
-\r
-static void hmacmd5_chap(const unsigned char *challenge, int challen,\r
- const char *passwd, unsigned char *response)\r
-{\r
- void *hmacmd5_ctx;\r
- int pwlen;\r
-\r
- hmacmd5_ctx = hmacmd5_make_context();\r
-\r
- pwlen = strlen(passwd);\r
- if (pwlen>64) {\r
- unsigned char md5buf[16];\r
- MD5Simple(passwd, pwlen, md5buf);\r
- hmacmd5_key(hmacmd5_ctx, md5buf, 16);\r
- } else {\r
- hmacmd5_key(hmacmd5_ctx, passwd, pwlen);\r
- }\r
-\r
- hmacmd5_do_hmac(hmacmd5_ctx, challenge, challen, response);\r
- hmacmd5_free_context(hmacmd5_ctx);\r
-}\r
-\r
-void proxy_socks5_offerencryptedauth(char *command, int *len)\r
-{\r
- command[*len] = 0x03; /* CHAP */\r
- (*len)++;\r
-}\r
-\r
-int proxy_socks5_handlechap (Proxy_Socket p)\r
-{\r
-\r
- /* CHAP authentication reply format:\r
- * version number (1 bytes) = 1\r
- * number of commands (1 byte)\r
- *\r
- * For each command:\r
- * command identifier (1 byte)\r
- * data length (1 byte)\r
- */\r
- unsigned char data[260];\r
- unsigned char outbuf[20];\r
-\r
- while(p->chap_num_attributes == 0 ||\r
- p->chap_num_attributes_processed < p->chap_num_attributes) {\r
- if (p->chap_num_attributes == 0 ||\r
- p->chap_current_attribute == -1) {\r
- /* CHAP normally reads in two bytes, either at the\r
- * beginning or for each attribute/value pair. But if\r
- * we're waiting for the value's data, we might not want\r
- * to read 2 bytes.\r
- */\r
- \r
- if (bufchain_size(&p->pending_input_data) < 2)\r
- return 1; /* not got anything yet */\r
-\r
- /* get the response */\r
- bufchain_fetch(&p->pending_input_data, data, 2);\r
- bufchain_consume(&p->pending_input_data, 2);\r
- }\r
-\r
- if (p->chap_num_attributes == 0) {\r
- /* If there are no attributes, this is our first msg\r
- * with the server, where we negotiate version and \r
- * number of attributes\r
- */\r
- if (data[0] != 0x01) {\r
- plug_closing(p->plug, "Proxy error: SOCKS proxy wants"\r
- " a different CHAP version",\r
- PROXY_ERROR_GENERAL, 0);\r
- return 1;\r
- }\r
- if (data[1] == 0x00) {\r
- plug_closing(p->plug, "Proxy error: SOCKS proxy won't"\r
- " negotiate CHAP with us",\r
- PROXY_ERROR_GENERAL, 0);\r
- return 1;\r
- }\r
- p->chap_num_attributes = data[1];\r
- } else {\r
- if (p->chap_current_attribute == -1) {\r
- /* We have to read in each attribute/value pair -\r
- * those we don't understand can be ignored, but\r
- * there are a few we'll need to handle.\r
- */\r
- p->chap_current_attribute = data[0];\r
- p->chap_current_datalen = data[1];\r
- }\r
- if (bufchain_size(&p->pending_input_data) <\r
- p->chap_current_datalen)\r
- return 1; /* not got everything yet */\r
-\r
- /* get the response */\r
- bufchain_fetch(&p->pending_input_data, data,\r
- p->chap_current_datalen);\r
-\r
- bufchain_consume(&p->pending_input_data,\r
- p->chap_current_datalen);\r
-\r
- switch (p->chap_current_attribute) {\r
- case 0x00:\r
- /* Successful authentication */\r
- if (data[0] == 0x00)\r
- p->state = 2;\r
- else {\r
- plug_closing(p->plug, "Proxy error: SOCKS proxy"\r
- " refused CHAP authentication",\r
- PROXY_ERROR_GENERAL, 0);\r
- return 1;\r
- }\r
- break;\r
- case 0x03:\r
- outbuf[0] = 0x01; /* Version */\r
- outbuf[1] = 0x01; /* One attribute */\r
- outbuf[2] = 0x04; /* Response */\r
- outbuf[3] = 0x10; /* Length */\r
- hmacmd5_chap(data, p->chap_current_datalen,\r
- p->cfg.proxy_password, &outbuf[4]);\r
- sk_write(p->sub_socket, (char *)outbuf, 20);\r
- break;\r
- case 0x11:\r
- /* Chose a protocol */\r
- if (data[0] != 0x85) {\r
- plug_closing(p->plug, "Proxy error: Server chose "\r
- "CHAP of other than HMAC-MD5 but we "\r
- "didn't offer it!",\r
- PROXY_ERROR_GENERAL, 0);\r
- return 1;\r
- }\r
- break;\r
- }\r
- p->chap_current_attribute = -1;\r
- p->chap_num_attributes_processed++;\r
- }\r
- if (p->state == 8 &&\r
- p->chap_num_attributes_processed >= p->chap_num_attributes) {\r
- p->chap_num_attributes = 0;\r
- p->chap_num_attributes_processed = 0;\r
- p->chap_current_datalen = 0;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-int proxy_socks5_selectchap(Proxy_Socket p)\r
-{\r
- if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) {\r
- char chapbuf[514];\r
- int ulen;\r
- chapbuf[0] = '\x01'; /* Version */\r
- chapbuf[1] = '\x02'; /* Number of attributes sent */\r
- chapbuf[2] = '\x11'; /* First attribute - algorithms list */\r
- chapbuf[3] = '\x01'; /* Only one CHAP algorithm */\r
- chapbuf[4] = '\x85'; /* ...and it's HMAC-MD5, the core one */\r
- chapbuf[5] = '\x02'; /* Second attribute - username */\r
-\r
- ulen = strlen(p->cfg.proxy_username);\r
- if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1;\r
-\r
- chapbuf[6] = ulen;\r
- memcpy(chapbuf+7, p->cfg.proxy_username, ulen);\r
-\r
- sk_write(p->sub_socket, chapbuf, ulen + 7);\r
- p->chap_num_attributes = 0;\r
- p->chap_num_attributes_processed = 0;\r
- p->chap_current_attribute = -1;\r
- p->chap_current_datalen = 0;\r
-\r
- p->state = 8;\r
- } else \r
- plug_closing(p->plug, "Proxy error: Server chose "\r
- "CHAP authentication but we didn't offer it!",\r
- PROXY_ERROR_GENERAL, 0);\r
- return 1;\r
-}\r