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 p
->cfg
.proxy_password
, &outbuf
[4]);
134 sk_write(p
->sub_socket
, (char *)outbuf
, 20);
137 /* Chose a protocol */
138 if (data
[0] != 0x85) {
139 plug_closing(p
->plug
, "Proxy error: Server chose "
140 "CHAP of other than HMAC-MD5 but we "
142 PROXY_ERROR_GENERAL
, 0);
147 p
->chap_current_attribute
= -1;
148 p
->chap_num_attributes_processed
++;
151 p
->chap_num_attributes_processed
>= p
->chap_num_attributes
) {
152 p
->chap_num_attributes
= 0;
153 p
->chap_num_attributes_processed
= 0;
154 p
->chap_current_datalen
= 0;
160 int proxy_socks5_selectchap(Proxy_Socket p
)
162 if (p
->cfg
.proxy_username
[0] || p
->cfg
.proxy_password
[0]) {
165 chapbuf
[0] = '\x01'; /* Version */
166 chapbuf
[1] = '\x02'; /* Number of attributes sent */
167 chapbuf
[2] = '\x11'; /* First attribute - algorithms list */
168 chapbuf
[3] = '\x01'; /* Only one CHAP algorithm */
169 chapbuf
[4] = '\x85'; /* ...and it's HMAC-MD5, the core one */
170 chapbuf
[5] = '\x02'; /* Second attribute - username */
172 ulen
= strlen(p
->cfg
.proxy_username
);
173 if (ulen
> 255) ulen
= 255; if (ulen
< 1) ulen
= 1;
176 memcpy(chapbuf
+7, p
->cfg
.proxy_username
, ulen
);
178 sk_write(p
->sub_socket
, chapbuf
, ulen
+ 7);
179 p
->chap_num_attributes
= 0;
180 p
->chap_num_attributes_processed
= 0;
181 p
->chap_current_attribute
= -1;
182 p
->chap_current_datalen
= 0;
186 plug_closing(p
->plug
, "Proxy error: Server chose "
187 "CHAP authentication but we didn't offer it!",
188 PROXY_ERROR_GENERAL
, 0);