OpenVPN
ntlm.c
Go to the documentation of this file.
1/*
2 * ntlm proxy support for OpenVPN
3 *
4 * Copyright (C) 2004 William Preston
5 *
6 * *NTLMv2 support and domain name parsing by Miroslav Zajic, Nextsoft s.r.o.*
7 *
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.
12 *
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.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28
29#if NTLM
30
31#include "common.h"
32#include "buffer.h"
33#include "misc.h"
34#include "socket.h"
35#include "fdmisc.h"
36#include "proxy.h"
37#include "ntlm.h"
38#include "base64.h"
39#include "crypto.h"
40
41#include "memdbg.h"
42
43
44/* 64bit datatype macros */
45#ifdef _MSC_VER
46/* MS compilers */
47#define UINTEGER64 __int64
48#define UINT64(c) c ## Ui64
49#else
50/* Non MS compilers */
51#define UINTEGER64 unsigned long long
52#define UINT64(c) c ## LL
53#endif
54
55
56
57static void
58gen_md4_hash(const uint8_t *data, int data_len, uint8_t *result)
59{
60 /* result is 16 byte md4 hash */
61 uint8_t md[MD4_DIGEST_LENGTH];
62
63 md_full("MD4", data, data_len, md);
64 memcpy(result, md, MD4_DIGEST_LENGTH);
65}
66
67static void
68gen_hmac_md5(const uint8_t *data, int data_len, const uint8_t *key,
69 uint8_t *result)
70{
71 hmac_ctx_t *hmac_ctx = hmac_ctx_new();
72
73 hmac_ctx_init(hmac_ctx, key, "MD5");
74 hmac_ctx_update(hmac_ctx, data, data_len);
75 hmac_ctx_final(hmac_ctx, result);
76 hmac_ctx_cleanup(hmac_ctx);
77 hmac_ctx_free(hmac_ctx);
78}
79
80static void
81gen_timestamp(uint8_t *timestamp)
82{
83 /* Copies 8 bytes long timestamp into "timestamp" buffer.
84 * Timestamp is Little-endian, 64-bit signed value representing the
85 * number of tenths of a microsecond since January 1, 1601.
86 */
87
88 UINTEGER64 timestamp_ull;
89
90 timestamp_ull = openvpn_time(NULL);
91 timestamp_ull = (timestamp_ull + UINT64(11644473600)) * UINT64(10000000);
92
93 /* store little endian value */
94 timestamp[0] = timestamp_ull & UINT64(0xFF);
95 timestamp[1] = (timestamp_ull >> 8) & UINT64(0xFF);
96 timestamp[2] = (timestamp_ull >> 16) & UINT64(0xFF);
97 timestamp[3] = (timestamp_ull >> 24) & UINT64(0xFF);
98 timestamp[4] = (timestamp_ull >> 32) & UINT64(0xFF);
99 timestamp[5] = (timestamp_ull >> 40) & UINT64(0xFF);
100 timestamp[6] = (timestamp_ull >> 48) & UINT64(0xFF);
101 timestamp[7] = (timestamp_ull >> 56) & UINT64(0xFF);
102}
103
104static void
105gen_nonce(unsigned char *nonce)
106{
107 /* Generates 8 random bytes to be used as client nonce */
108 int i;
109
110 for (i = 0; i<8; i++)
111 {
112 nonce[i] = (unsigned char)get_random();
113 }
114}
115
116static void
117my_strupr(char *str)
118{
119 /* converts string to uppercase in place */
120
121 while (*str)
122 {
123 *str = toupper(*str);
124 str++;
125 }
126}
127
141static int
142unicodize(char *dst, const char *src)
143{
144 /* not really unicode... */
145 int i = 0;
146 do
147 {
148 dst[i++] = *src;
149 dst[i++] = 0;
150 } while (*src++);
151
152 return i;
153}
154
155static void
156add_security_buffer(int sb_offset, void *data, int length,
157 unsigned char *msg_buf, int *msg_bufpos, size_t msg_bufsize)
158{
159 if (*msg_bufpos + length > msg_bufsize)
160 {
161 msg(M_WARN, "NTLM: security buffer too big for message buffer");
162 return;
163 }
164 /* Adds security buffer data to a message and sets security buffer's
165 * offset and length */
166 msg_buf[sb_offset] = (unsigned char)length;
167 msg_buf[sb_offset + 2] = msg_buf[sb_offset];
168 msg_buf[sb_offset + 4] = (unsigned char)(*msg_bufpos & 0xff);
169 msg_buf[sb_offset + 5] = (unsigned char)((*msg_bufpos >> 8) & 0xff);
170 memcpy(&msg_buf[*msg_bufpos], data, msg_buf[sb_offset]);
171 *msg_bufpos += length;
172}
173
174const char *
175ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
176{
177 struct buffer out = alloc_buf_gc(96, gc);
178 /* try a minimal NTLM handshake
179 *
180 * http://davenport.sourceforge.net/ntlm.html
181 *
182 * This message contains only the NTLMSSP signature,
183 * the NTLM message type,
184 * and the minimal set of flags (Negotiate NTLM and Negotiate OEM).
185 *
186 */
187 buf_printf(&out, "%s", "TlRMTVNTUAABAAAAAgIAAA==");
188 return (BSTR(&out));
189}
190
191const char *
192ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2,
193 struct gc_arena *gc)
194{
195 /* NTLM handshake
196 *
197 * http://davenport.sourceforge.net/ntlm.html
198 *
199 */
200
201 char pwbuf[sizeof(p->up.password) * 2]; /* for unicode password */
202 uint8_t phase3[464];
203
206 int i, ret_val;
207
209 char userdomain_u[256]; /* for uppercase unicode username and domain */
210 char userdomain[128]; /* the same as previous but ascii */
213 uint8_t *ntlmv2_blob = ntlmv2_response + 16; /* inside ntlmv2_response, length: 128 */
214 int ntlmv2_blob_size = 0;
215 int phase3_bufpos = 0x40; /* offset to next security buffer data to be added */
216 size_t len;
217
218 char domain[128];
219 char username[128];
220 char *separator;
221
222 ASSERT(strlen(p->up.username) > 0);
223 ASSERT(strlen(p->up.password) > 0);
224
225 /* username parsing */
226 separator = strchr(p->up.username, '\\');
227 if (separator == NULL)
228 {
229 strncpy(username, p->up.username, sizeof(username)-1);
230 username[sizeof(username)-1] = 0;
231 domain[0] = 0;
232 }
233 else
234 {
235 strncpy(username, separator+1, sizeof(username)-1);
236 username[sizeof(username)-1] = 0;
237 len = separator - p->up.username;
238 if (len > sizeof(domain) - 1)
239 {
240 len = sizeof(domain) - 1;
241 }
242 strncpy(domain, p->up.username, len);
243 domain[len] = 0;
244 }
245
246
247 /* fill 1st 16 bytes with md4 hash, disregard terminating null */
248 int unicode_len = unicodize(pwbuf, p->up.password) - 2;
250
251 /* pad to 21 bytes */
253
254 /* If the decoded challenge is shorter than required by the protocol,
255 * the missing bytes will be NULL, as buf2 is known to be zeroed
256 * when this decode happens.
257 */
258 uint8_t buf2[512]; /* decoded reply from proxy */
259 CLEAR(buf2);
261 if (ret_val < 0)
262 {
263 msg(M_WARN, "NTLM: base64 decoding of phase 2 response failed");
264 return NULL;
265 }
266
267 /* extract the challenge from bytes 24-31 */
268 for (i = 0; i<8; i++)
269 {
270 challenge[i] = buf2[i+24];
271 }
272
273 /* Generate NTLMv2 response */
274 int tib_len;
275
276 /* NTLMv2 hash */
277 strcpy(userdomain, username);
279 if (strlen(username) + strlen(domain) < sizeof(userdomain))
280 {
281 strcat(userdomain, domain);
282 }
283 else
284 {
285 msg(M_INFO, "NTLM: Username or domain too long");
286 }
290
291 /* NTLMv2 Blob */
292 memset(ntlmv2_blob, 0, 128); /* Clear blob buffer */
293 ntlmv2_blob[0x00] = 1; /* Signature */
294 ntlmv2_blob[0x01] = 1; /* Signature */
295 ntlmv2_blob[0x04] = 0; /* Reserved */
296 gen_timestamp(&ntlmv2_blob[0x08]); /* 64-bit Timestamp */
297 gen_nonce(&ntlmv2_blob[0x10]); /* 64-bit Client Nonce */
298 ntlmv2_blob[0x18] = 0; /* Unknown, zero should work */
299
300 /* Add target information block to the blob */
301
302 /* Check for Target Information block */
303 /* The NTLM spec instructs to interpret these 4 consecutive bytes as a
304 * 32bit long integer. However, no endianness is specified.
305 * The code here and that found in other NTLM implementations point
306 * towards the assumption that the byte order on the wire has to
307 * match the order on the sending and receiving hosts. Probably NTLM has
308 * been thought to be always running on x86_64/i386 machine thus
309 * implying Little-Endian everywhere.
310 *
311 * This said, in case of future changes, we should keep in mind that the
312 * byte order on the wire for the NTLM header is LE.
313 */
314 const size_t hoff = 0x14;
315 unsigned long flags = buf2[hoff] | (buf2[hoff + 1] << 8)
316 |(buf2[hoff + 2] << 16) | (buf2[hoff + 3] << 24);
317 if ((flags & 0x00800000) == 0x00800000)
318 {
319 tib_len = buf2[0x28]; /* Get Target Information block size */
320 if (tib_len + 0x1c + 16 > sizeof(ntlmv2_response))
321 {
322 msg(M_WARN, "NTLM: target information buffer too long for response (len=%d)", tib_len);
323 return NULL;
324 }
325
326 {
328 uint8_t tib_pos = buf2[0x2c];
329 if (tib_pos + tib_len > sizeof(buf2))
330 {
331 msg(M_ERR, "NTLM: phase 2 response from server too long (need %d bytes at offset %u)", tib_len, tib_pos);
332 return NULL;
333 }
334 /* Get Target Information block pointer */
335 tib_ptr = buf2 + tib_pos;
336 /* Copy Target Information block into the blob */
338 }
339 }
340 else
341 {
342 tib_len = 0;
343 }
344
345 /* Unknown, zero works */
346 ntlmv2_blob[0x1c + tib_len] = 0;
347
348 /* Get blob length */
349 ntlmv2_blob_size = 0x20 + tib_len;
350
351 /* Add challenge from message 2 */
353
354 /* hmac-md5 */
357
358 /* Add hmac-md5 result to the blob.
359 * Note: This overwrites challenge previously written at
360 * ntlmv2_response[8..15] */
362
363 memset(phase3, 0, sizeof(phase3)); /* clear reply */
364
365 strcpy((char *)phase3, "NTLMSSP\0"); /* signature */
366 phase3[8] = 3; /* type 3 */
367
368 /* NTLMv2 response */
370 phase3, &phase3_bufpos, sizeof(phase3));
371
372 /* username in ascii */
373 add_security_buffer(0x24, username, strlen(username), phase3,
374 &phase3_bufpos, sizeof(phase3));
375
376 /* Set domain. If <domain> is empty, default domain will be used
377 * (i.e. proxy's domain) */
378 add_security_buffer(0x1c, domain, strlen(domain), phase3, &phase3_bufpos, sizeof(phase3));
379
380 /* other security buffers will be empty */
381 phase3[0x10] = phase3_bufpos; /* lm not used */
382 phase3[0x30] = phase3_bufpos; /* no workstation name supplied */
383 phase3[0x38] = phase3_bufpos; /* no session key */
384
385 /* flags */
386 phase3[0x3c] = 0x02; /* negotiate oem */
387 phase3[0x3d] = 0x02; /* negotiate ntlm */
388
389 return ((const char *)make_base64_string2((unsigned char *)phase3,
390 phase3_bufpos, gc));
391}
392#endif /* if NTLM */
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
#define BSTR(buf)
Definition buffer.h:129
long int get_random(void)
Definition crypto.c:1757
Data Channel Cryptography Module.
void hmac_ctx_update(hmac_ctx_t *ctx, const uint8_t *src, int src_len)
hmac_ctx_t * hmac_ctx_new(void)
int md_full(const char *mdname, const uint8_t *src, int src_len, uint8_t *dst)
Calculates the message digest for the given buffer.
void hmac_ctx_init(hmac_ctx_t *ctx, const uint8_t *key, const char *mdname)
void hmac_ctx_final(hmac_ctx_t *ctx, uint8_t *dst)
void hmac_ctx_free(hmac_ctx_t *ctx)
void hmac_ctx_cleanup(hmac_ctx_t *ctx)
#define MD5_DIGEST_LENGTH
mbedtls_md_context_t hmac_ctx_t
Generic HMAC context.
#define MD4_DIGEST_LENGTH
#define M_INFO
Definition errlevel.h:55
static void gen_timestamp(uint8_t *timestamp)
Definition ntlm.c:81
static void gen_hmac_md5(const uint8_t *data, int data_len, const uint8_t *key, uint8_t *result)
Definition ntlm.c:68
static void add_security_buffer(int sb_offset, void *data, int length, unsigned char *msg_buf, int *msg_bufpos, size_t msg_bufsize)
Definition ntlm.c:156
static void my_strupr(char *str)
Definition ntlm.c:117
const char * ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc)
Definition ntlm.c:192
#define UINTEGER64
Definition ntlm.c:51
const char * ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
Definition ntlm.c:175
static int unicodize(char *dst, const char *src)
This function expects a null-terminated string in src and will copy it (including the terminating NUL...
Definition ntlm.c:142
static void gen_md4_hash(const uint8_t *data, int data_len, uint8_t *result)
Definition ntlm.c:58
static void gen_nonce(unsigned char *nonce)
Definition ntlm.c:105
#define UINT64(c)
Definition ntlm.c:52
#define CLEAR(x)
Definition basic.h:33
#define M_ERR
Definition error.h:105
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
static time_t openvpn_time(time_t *t)
Definition otime.h:90
uint8_t * make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc)
Definition proxy.c:227
int openvpn_base64_decode(const char *str, void *data, int size)
Definition base64.c:158
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
struct gc_arena gc
Definition test_ssl.c:155