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
12 #define DEFINE_PLUG_METHOD_MACROS
\r
14 #include "ssh.h" /* For MD5 support */
\r
15 #include "network.h"
\r
18 static void hmacmd5_chap(const unsigned char *challenge, int challen,
\r
19 const char *passwd, unsigned char *response)
\r
24 hmacmd5_ctx = hmacmd5_make_context();
\r
26 pwlen = strlen(passwd);
\r
28 unsigned char md5buf[16];
\r
29 MD5Simple(passwd, pwlen, md5buf);
\r
30 hmacmd5_key(hmacmd5_ctx, md5buf, 16);
\r
32 hmacmd5_key(hmacmd5_ctx, passwd, pwlen);
\r
35 hmacmd5_do_hmac(hmacmd5_ctx, challenge, challen, response);
\r
36 hmacmd5_free_context(hmacmd5_ctx);
\r
39 void proxy_socks5_offerencryptedauth(char *command, int *len)
\r
41 command[*len] = 0x03; /* CHAP */
\r
45 int proxy_socks5_handlechap (Proxy_Socket p)
\r
48 /* CHAP authentication reply format:
\r
49 * version number (1 bytes) = 1
\r
50 * number of commands (1 byte)
\r
53 * command identifier (1 byte)
\r
54 * data length (1 byte)
\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
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
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
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
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
94 p->chap_num_attributes = data[1];
\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
101 p->chap_current_attribute = data[0];
\r
102 p->chap_current_datalen = data[1];
\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
117 /* Successful authentication */
\r
118 if (data[0] == 0x00)
\r
121 plug_closing(p->plug, "Proxy error: SOCKS proxy"
\r
122 " refused CHAP authentication",
\r
123 PROXY_ERROR_GENERAL, 0);
\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 p->cfg.proxy_password, &outbuf[4]);
\r
134 sk_write(p->sub_socket, (char *)outbuf, 20);
\r
137 /* Chose a protocol */
\r
138 if (data[0] != 0x85) {
\r
139 plug_closing(p->plug, "Proxy error: Server chose "
\r
140 "CHAP of other than HMAC-MD5 but we "
\r
141 "didn't offer it!",
\r
142 PROXY_ERROR_GENERAL, 0);
\r
147 p->chap_current_attribute = -1;
\r
148 p->chap_num_attributes_processed++;
\r
150 if (p->state == 8 &&
\r
151 p->chap_num_attributes_processed >= p->chap_num_attributes) {
\r
152 p->chap_num_attributes = 0;
\r
153 p->chap_num_attributes_processed = 0;
\r
154 p->chap_current_datalen = 0;
\r
160 int proxy_socks5_selectchap(Proxy_Socket p)
\r
162 if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) {
\r
165 chapbuf[0] = '\x01'; /* Version */
\r
166 chapbuf[1] = '\x02'; /* Number of attributes sent */
\r
167 chapbuf[2] = '\x11'; /* First attribute - algorithms list */
\r
168 chapbuf[3] = '\x01'; /* Only one CHAP algorithm */
\r
169 chapbuf[4] = '\x85'; /* ...and it's HMAC-MD5, the core one */
\r
170 chapbuf[5] = '\x02'; /* Second attribute - username */
\r
172 ulen = strlen(p->cfg.proxy_username);
\r
173 if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1;
\r
176 memcpy(chapbuf+7, p->cfg.proxy_username, ulen);
\r
178 sk_write(p->sub_socket, chapbuf, ulen + 7);
\r
179 p->chap_num_attributes = 0;
\r
180 p->chap_num_attributes_processed = 0;
\r
181 p->chap_current_attribute = -1;
\r
182 p->chap_current_datalen = 0;
\r
186 plug_closing(p->plug, "Proxy error: Server chose "
\r
187 "CHAP authentication but we didn't offer it!",
\r
188 PROXY_ERROR_GENERAL, 0);
\r