2 * ntlm proxy support for OpenVPN
4 * Copyright (C) 2004 William Preston
6 * *NTLMv2 support and domain name parsing by Miroslav Zajic, Nextsoft s.r.o.*
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program (see the file COPYING included with this
20 * distribution); if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41 /* 64bit datatype macros */
44 # define UINTEGER64 __int64
45 # define UINT64(c) c ## Ui64
47 /* Non MS compilers */
48 # define UINTEGER64 unsigned long long
49 # define UINT64(c) c ## LL
56 create_des_keys(const unsigned char *hash
, unsigned char *key
)
59 key
[1] = ((hash
[0]&1)<<7)|(hash
[1]>>1);
60 key
[2] = ((hash
[1]&3)<<6)|(hash
[2]>>2);
61 key
[3] = ((hash
[2]&7)<<5)|(hash
[3]>>3);
62 key
[4] = ((hash
[3]&15)<<4)|(hash
[4]>>4);
63 key
[5] = ((hash
[4]&31)<<3)|(hash
[5]>>5);
64 key
[6] = ((hash
[5]&63)<<2)|(hash
[6]>>6);
65 key
[7] = ((hash
[6]&127)<<1);
66 des_set_odd_parity((des_cblock
*)key
);
70 gen_md4_hash (const char* data
, int data_len
, char *result
)
72 /* result is 16 byte md4 hash */
78 MD4_Update (&c
, data
, data_len
);
79 MD4_Final ((unsigned char *)md
, &c
);
81 memcpy (result
, md
, 16);
85 gen_hmac_md5 (const char* data
, int data_len
, const char* key
, int key_len
,char *result
)
90 HMAC_Init (&c
, key
, key_len
, EVP_md5());
91 HMAC_Update (&c
, (const unsigned char *)data
, data_len
);
92 HMAC_Final (&c
, (unsigned char *)result
, &len
);
97 gen_timestamp (unsigned char *timestamp
)
99 /* Copies 8 bytes long timestamp into "timestamp" buffer.
100 * Timestamp is Little-endian, 64-bit signed value representing the number of tenths of a microsecond since January 1, 1601.
103 UINTEGER64 timestamp_ull
;
105 timestamp_ull
= openvpn_time(NULL
);
106 timestamp_ull
= (timestamp_ull
+ UINT64(11644473600)) * UINT64(10000000);
108 /* store little endian value */
109 timestamp
[0]= timestamp_ull
& UINT64(0xFF);
110 timestamp
[1]= (timestamp_ull
>> 8) & UINT64(0xFF);
111 timestamp
[2]= (timestamp_ull
>> 16) & UINT64(0xFF);
112 timestamp
[3]= (timestamp_ull
>> 24) & UINT64(0xFF);
113 timestamp
[4]= (timestamp_ull
>> 32) & UINT64(0xFF);
114 timestamp
[5]= (timestamp_ull
>> 40) & UINT64(0xFF);
115 timestamp
[6]= (timestamp_ull
>> 48) & UINT64(0xFF);
116 timestamp
[7]= (timestamp_ull
>> 56) & UINT64(0xFF);
120 gen_nonce (unsigned char *nonce
)
122 /* Generates 8 random bytes to be used as client nonce */
126 nonce
[i
] = (unsigned char)get_random();
130 unsigned char *my_strupr(unsigned char *str
)
132 /* converts string to uppercase in place */
133 unsigned char *tmp
= str
;;
135 do *str
= toupper(*str
); while (*(++str
));
140 unicodize (char *dst
, const char *src
)
142 /* not really unicode... */
155 add_security_buffer(int sb_offset
, void *data
, int length
, unsigned char *msg_buf
, int *msg_bufpos
)
157 /* Adds security buffer data to a message and sets security buffer's offset and length */
158 msg_buf
[sb_offset
] = (unsigned char)length
;
159 msg_buf
[sb_offset
+ 2] = msg_buf
[sb_offset
];
160 msg_buf
[sb_offset
+ 4] = (unsigned char)(*msg_bufpos
& 0xff);
161 msg_buf
[sb_offset
+ 5] = (unsigned char)((*msg_bufpos
>> 8) & 0xff);
162 memcpy(&msg_buf
[*msg_bufpos
], data
, msg_buf
[sb_offset
]);
163 *msg_bufpos
+= length
;
167 ntlm_phase_1 (const struct http_proxy_info
*p
, struct gc_arena
*gc
)
169 struct buffer out
= alloc_buf_gc (96, gc
);
170 /* try a minimal NTLM handshake
172 * http://davenport.sourceforge.net/ntlm.html
174 * This message contains only the NTLMSSP signature,
175 * the NTLM message type,
176 * and the minimal set of flags (Negotiate NTLM and Negotiate OEM).
179 buf_printf (&out
, "%s", "TlRMTVNTUAABAAAAAgIAAA==");
180 return (BSTR (&out
));
184 ntlm_phase_3 (const struct http_proxy_info
*p
, const char *phase_2
, struct gc_arena
*gc
)
188 * http://davenport.sourceforge.net/ntlm.html
192 char pwbuf
[sizeof (p
->up
.password
) * 2]; /* for unicode password */
193 char buf2
[128]; /* decoded reply from proxy */
194 unsigned char phase3
[464];
197 char challenge
[8], ntlm_response
[24];
199 des_cblock key1
, key2
, key3
;
200 des_key_schedule sched1
, sched2
, sched3
;
202 char ntlmv2_response
[144];
203 char userdomain_u
[256]; /* for uppercase unicode username and domain */
204 char userdomain
[128]; /* the same as previous but ascii */
205 char ntlmv2_hash
[16];
206 char ntlmv2_hmacmd5
[16];
207 char *ntlmv2_blob
= ntlmv2_response
+ 16; /* inside ntlmv2_response, length: 128 */
208 int ntlmv2_blob_size
=0;
209 int phase3_bufpos
= 0x40; /* offset to next security buffer data to be added */
216 bool ntlmv2_enabled
= (p
->auth_method
== HTTP_AUTH_NTLM2
);
220 ASSERT (strlen (p
->up
.username
) > 0);
221 ASSERT (strlen (p
->up
.password
) > 0);
223 /* username parsing */
224 separator
= strchr(p
->up
.username
, '\\');
225 if (separator
== NULL
) {
226 strncpy(username
, p
->up
.username
, sizeof(username
)-1);
227 username
[sizeof(username
)-1]=0;
230 strncpy(username
, separator
+1, sizeof(username
)-1);
231 username
[sizeof(username
)-1]=0;
232 len
= separator
- p
->up
.username
;
233 if (len
> sizeof(domain
) - 1) len
= sizeof(domain
) - 1;
234 strncpy(domain
, p
->up
.username
, len
);
239 /* fill 1st 16 bytes with md4 hash, disregard terminating null */
240 gen_md4_hash (pwbuf
, unicodize (pwbuf
, p
->up
.password
) - 2, md4_hash
);
242 /* pad to 21 bytes */
243 memset (md4_hash
+ 16, 0, 5);
245 ret_val
= base64_decode( phase_2
, (void *)buf2
);
249 /* we can be sure that phase_2 is less than 128
250 * therefore buf2 needs to be (3/4 * 128) */
252 /* extract the challenge from bytes 24-31 */
255 challenge
[i
] = buf2
[i
+24];
258 if (ntlmv2_enabled
){ /* Generate NTLMv2 response */
262 my_strupr((unsigned char *)strcpy(userdomain
, username
));
263 if (strlen(username
) + strlen(domain
) < sizeof(userdomain
))
264 strcat(userdomain
, domain
);
266 msg (M_INFO
, "Warning: Username or domain too long");
267 unicodize (userdomain_u
, userdomain
);
268 gen_hmac_md5(userdomain_u
, 2 * strlen(userdomain
), md4_hash
, 16, ntlmv2_hash
);
271 memset(ntlmv2_blob
, 0, 128); /* Clear blob buffer */
272 ntlmv2_blob
[0x00]=1; /* Signature */
273 ntlmv2_blob
[0x01]=1; /* Signature */
274 ntlmv2_blob
[0x04]=0; /* Reserved */
275 gen_timestamp((unsigned char *)&ntlmv2_blob
[0x08]); /* 64-bit Timestamp */
276 gen_nonce((unsigned char *)&ntlmv2_blob
[0x10]); /* 64-bit Client Nonce */
277 ntlmv2_blob
[0x18]=0; /* Unknown, zero should work */
279 /* Add target information block to the blob */
280 if (( *((long *)&buf2
[0x14]) & 0x00800000) == 0x00800000){ /* Check for Target Information block */
281 tib_len
= buf2
[0x28];/* Get Target Information block size */
282 if (tib_len
> 96) tib_len
= 96;
284 char *tib_ptr
= buf2
+ buf2
[0x2c]; /* Get Target Information block pointer */
285 memcpy(&ntlmv2_blob
[0x1c], tib_ptr
, tib_len
); /* Copy Target Information block into the blob */
291 ntlmv2_blob
[0x1c + tib_len
] = 0; /* Unknown, zero works */
293 /* Get blob length */
294 ntlmv2_blob_size
= 0x20 + tib_len
;
296 /* Add challenge from message 2 */
297 memcpy(&ntlmv2_response
[8], challenge
, 8);
300 gen_hmac_md5(&ntlmv2_response
[8], ntlmv2_blob_size
+ 8, ntlmv2_hash
, 16, ntlmv2_hmacmd5
);
302 /* Add hmac-md5 result to the blob */
303 memcpy(ntlmv2_response
, ntlmv2_hmacmd5
, 16); /* Note: This overwrites challenge previously written at ntlmv2_response[8..15] */
305 } else { /* Generate NTLM response */
307 create_des_keys ((unsigned char *)md4_hash
, key1
);
308 des_set_key_unchecked ((des_cblock
*)key1
, sched1
);
309 des_ecb_encrypt ((des_cblock
*)challenge
, (des_cblock
*)ntlm_response
, sched1
, DES_ENCRYPT
);
311 create_des_keys ((unsigned char *)&(md4_hash
[7]), key2
);
312 des_set_key_unchecked ((des_cblock
*)key2
, sched2
);
313 des_ecb_encrypt ((des_cblock
*)challenge
, (des_cblock
*)&(ntlm_response
[8]), sched2
, DES_ENCRYPT
);
315 create_des_keys ((unsigned char *)&(md4_hash
[14]), key3
);
316 des_set_key_unchecked ((des_cblock
*)key3
, sched3
);
317 des_ecb_encrypt ((des_cblock
*)challenge
, (des_cblock
*)&(ntlm_response
[16]), sched3
, DES_ENCRYPT
);
321 memset (phase3
, 0, sizeof (phase3
)); /* clear reply */
323 strcpy ((char *)phase3
, "NTLMSSP\0"); /* signature */
324 phase3
[8] = 3; /* type 3 */
326 if (ntlmv2_enabled
){ /* NTLMv2 response */
327 add_security_buffer(0x14, ntlmv2_response
, ntlmv2_blob_size
+ 16, phase3
, &phase3_bufpos
);
328 }else{ /* NTLM response */
329 add_security_buffer(0x14, ntlm_response
, 24, phase3
, &phase3_bufpos
);
332 /* username in ascii */
333 add_security_buffer(0x24, username
, strlen (username
), phase3
, &phase3_bufpos
);
335 /* Set domain. If <domain> is empty, default domain will be used (i.e. proxy's domain) */
336 add_security_buffer(0x1c, domain
, strlen (domain
), phase3
, &phase3_bufpos
);
339 /* other security buffers will be empty */
340 phase3
[0x10] = phase3_bufpos
; /* lm not used */
341 phase3
[0x30] = phase3_bufpos
; /* no workstation name supplied */
342 phase3
[0x38] = phase3_bufpos
; /* no session key */
345 phase3
[0x3c] = 0x02; /* negotiate oem */
346 phase3
[0x3d] = 0x02; /* negotiate ntlm */
348 return ((const char *)make_base64_string2 ((unsigned char *)phase3
, phase3_bufpos
, gc
));
352 static void dummy(void) {}