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