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