Update libgit2 AutoCRLF patches
[TortoiseGit.git] / src / TortoisePlink / CPROXY.C
blobd5049af3a68159538e0c2ccd1cc7aa15db78c694
1 /*\r
2  * Routines to do cryptographic interaction with proxies in PuTTY.\r
3  * This is in a separate module from proxy.c, so that it can be\r
4  * conveniently removed in PuTTYtel by replacing this module with\r
5  * the stub version nocproxy.c.\r
6  */\r
7 \r
8 #include <assert.h>\r
9 #include <ctype.h>\r
10 #include <string.h>\r
12 #define DEFINE_PLUG_METHOD_MACROS\r
13 #include "putty.h"\r
14 #include "ssh.h" /* For MD5 support */\r
15 #include "network.h"\r
16 #include "proxy.h"\r
18 static void hmacmd5_chap(const unsigned char *challenge, int challen,\r
19                          const char *passwd, unsigned char *response)\r
20 {\r
21     void *hmacmd5_ctx;\r
22     int pwlen;\r
24     hmacmd5_ctx = hmacmd5_make_context();\r
26     pwlen = strlen(passwd);\r
27     if (pwlen>64) {\r
28         unsigned char md5buf[16];\r
29         MD5Simple(passwd, pwlen, md5buf);\r
30         hmacmd5_key(hmacmd5_ctx, md5buf, 16);\r
31     } else {\r
32         hmacmd5_key(hmacmd5_ctx, passwd, pwlen);\r
33     }\r
35     hmacmd5_do_hmac(hmacmd5_ctx, challenge, challen, response);\r
36     hmacmd5_free_context(hmacmd5_ctx);\r
37 }\r
39 void proxy_socks5_offerencryptedauth(char *command, int *len)\r
40 {\r
41     command[*len] = 0x03; /* CHAP */\r
42     (*len)++;\r
43 }\r
45 int proxy_socks5_handlechap (Proxy_Socket p)\r
46 {\r
48     /* CHAP authentication reply format:\r
49      *  version number (1 bytes) = 1\r
50      *  number of commands (1 byte)\r
51      *\r
52      * For each command:\r
53      *  command identifier (1 byte)\r
54      *  data length (1 byte)\r
55      */\r
56     unsigned char data[260];\r
57     unsigned char outbuf[20];\r
59     while(p->chap_num_attributes == 0 ||\r
60           p->chap_num_attributes_processed < p->chap_num_attributes) {\r
61         if (p->chap_num_attributes == 0 ||\r
62             p->chap_current_attribute == -1) {\r
63             /* CHAP normally reads in two bytes, either at the\r
64              * beginning or for each attribute/value pair.  But if\r
65              * we're waiting for the value's data, we might not want\r
66              * to read 2 bytes.\r
67              */\r
68  \r
69             if (bufchain_size(&p->pending_input_data) < 2)\r
70                 return 1;              /* not got anything yet */\r
72             /* get the response */\r
73             bufchain_fetch(&p->pending_input_data, data, 2);\r
74             bufchain_consume(&p->pending_input_data, 2);\r
75         }\r
77         if (p->chap_num_attributes == 0) {\r
78             /* If there are no attributes, this is our first msg\r
79              * with the server, where we negotiate version and \r
80              * number of attributes\r
81              */\r
82             if (data[0] != 0x01) {\r
83                 plug_closing(p->plug, "Proxy error: SOCKS proxy wants"\r
84                              " a different CHAP version",\r
85                              PROXY_ERROR_GENERAL, 0);\r
86                 return 1;\r
87             }\r
88             if (data[1] == 0x00) {\r
89                 plug_closing(p->plug, "Proxy error: SOCKS proxy won't"\r
90                              " negotiate CHAP with us",\r
91                              PROXY_ERROR_GENERAL, 0);\r
92                 return 1;\r
93             }\r
94             p->chap_num_attributes = data[1];\r
95         } else {\r
96             if (p->chap_current_attribute == -1) {\r
97                 /* We have to read in each attribute/value pair -\r
98                  * those we don't understand can be ignored, but\r
99                  * there are a few we'll need to handle.\r
100                  */\r
101                 p->chap_current_attribute = data[0];\r
102                 p->chap_current_datalen = data[1];\r
103             }\r
104             if (bufchain_size(&p->pending_input_data) <\r
105                 p->chap_current_datalen)\r
106                 return 1;              /* not got everything yet */\r
108             /* get the response */\r
109             bufchain_fetch(&p->pending_input_data, data,\r
110                            p->chap_current_datalen);\r
112             bufchain_consume(&p->pending_input_data,\r
113                              p->chap_current_datalen);\r
115             switch (p->chap_current_attribute) {\r
116               case 0x00:\r
117                 /* Successful authentication */\r
118                 if (data[0] == 0x00)\r
119                     p->state = 2;\r
120                 else {\r
121                     plug_closing(p->plug, "Proxy error: SOCKS proxy"\r
122                                  " refused CHAP authentication",\r
123                                  PROXY_ERROR_GENERAL, 0);\r
124                     return 1;\r
125                 }\r
126               break;\r
127               case 0x03:\r
128                 outbuf[0] = 0x01; /* Version */\r
129                 outbuf[1] = 0x01; /* One attribute */\r
130                 outbuf[2] = 0x04; /* Response */\r
131                 outbuf[3] = 0x10; /* Length */\r
132                 hmacmd5_chap(data, p->chap_current_datalen,\r
133                              conf_get_str(p->conf, CONF_proxy_password),\r
134                              &outbuf[4]);\r
135                 sk_write(p->sub_socket, (char *)outbuf, 20);\r
136               break;\r
137               case 0x11:\r
138                 /* Chose a protocol */\r
139                 if (data[0] != 0x85) {\r
140                     plug_closing(p->plug, "Proxy error: Server chose "\r
141                                  "CHAP of other than HMAC-MD5 but we "\r
142                                  "didn't offer it!",\r
143                                  PROXY_ERROR_GENERAL, 0);\r
144                     return 1;\r
145                 }\r
146               break;\r
147             }\r
148             p->chap_current_attribute = -1;\r
149             p->chap_num_attributes_processed++;\r
150         }\r
151         if (p->state == 8 &&\r
152             p->chap_num_attributes_processed >= p->chap_num_attributes) {\r
153             p->chap_num_attributes = 0;\r
154             p->chap_num_attributes_processed = 0;\r
155             p->chap_current_datalen = 0;\r
156         }\r
157     }\r
158     return 0;\r
161 int proxy_socks5_selectchap(Proxy_Socket p)\r
163     char *username = conf_get_str(p->conf, CONF_proxy_username);\r
164     char *password = conf_get_str(p->conf, CONF_proxy_password);\r
165     if (username[0] || password[0]) {\r
166         char chapbuf[514];\r
167         int ulen;\r
168         chapbuf[0] = '\x01'; /* Version */\r
169         chapbuf[1] = '\x02'; /* Number of attributes sent */\r
170         chapbuf[2] = '\x11'; /* First attribute - algorithms list */\r
171         chapbuf[3] = '\x01'; /* Only one CHAP algorithm */\r
172         chapbuf[4] = '\x85'; /* ...and it's HMAC-MD5, the core one */\r
173         chapbuf[5] = '\x02'; /* Second attribute - username */\r
175         ulen = strlen(username);\r
176         if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1;\r
178         chapbuf[6] = ulen;\r
179         memcpy(chapbuf+7, username, ulen);\r
181         sk_write(p->sub_socket, chapbuf, ulen + 7);\r
182         p->chap_num_attributes = 0;\r
183         p->chap_num_attributes_processed = 0;\r
184         p->chap_current_attribute = -1;\r
185         p->chap_current_datalen = 0;\r
187         p->state = 8;\r
188     } else \r
189         plug_closing(p->plug, "Proxy error: Server chose "\r
190                      "CHAP authentication but we didn't offer it!",\r
191                  PROXY_ERROR_GENERAL, 0);\r
192     return 1;\r