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
77#if defined(__GNUC__) || defined(__clang__)
78#pragma GCC diagnostic push
79#pragma GCC diagnostic ignored "-Wconversion"
80#endif
81
82static void
83gen_timestamp(uint8_t *timestamp)
84{
85 /* Copies 8 bytes long timestamp into "timestamp" buffer.
86 * Timestamp is Little-endian, 64-bit signed value representing the
87 * number of tenths of a microsecond since January 1, 1601.
88 */
89
90 UINTEGER64 timestamp_ull;
91
92 timestamp_ull = openvpn_time(NULL);
93 timestamp_ull = (timestamp_ull + UINT64(11644473600)) * UINT64(10000000);
94
95 /* store little endian value */
96 timestamp[0] = timestamp_ull & UINT64(0xFF);
97 timestamp[1] = (timestamp_ull >> 8) & UINT64(0xFF);
98 timestamp[2] = (timestamp_ull >> 16) & UINT64(0xFF);
99 timestamp[3] = (timestamp_ull >> 24) & UINT64(0xFF);
100 timestamp[4] = (timestamp_ull >> 32) & UINT64(0xFF);
101 timestamp[5] = (timestamp_ull >> 40) & UINT64(0xFF);
102 timestamp[6] = (timestamp_ull >> 48) & UINT64(0xFF);
103 timestamp[7] = (timestamp_ull >> 56) & UINT64(0xFF);
104}
105
106static void
107gen_nonce(unsigned char *nonce)
108{
109 /* Generates 8 random bytes to be used as client nonce */
110 int i;
111
112 for (i = 0; i < 8; i++)
113 {
114 nonce[i] = (unsigned char)get_random();
115 }
116}
117
118static void
119my_strupr(char *str)
120{
121 /* converts string to uppercase in place */
122
123 while (*str)
124 {
125 *str = toupper(*str);
126 str++;
127 }
128}
129
143static int
144unicodize(char *dst, const char *src)
145{
146 /* not really unicode... */
147 int i = 0;
148 do
149 {
150 dst[i++] = *src;
151 dst[i++] = 0;
152 } while (*src++);
153
154 return i;
155}
156
157static void
158add_security_buffer(int sb_offset, void *data, int length, unsigned char *msg_buf, int *msg_bufpos,
159 size_t msg_bufsize)
160{
161 if (*msg_bufpos + length > msg_bufsize)
162 {
163 msg(M_WARN, "NTLM: security buffer too big for message buffer");
164 return;
165 }
166 /* Adds security buffer data to a message and sets security buffer's
167 * offset and length */
168 msg_buf[sb_offset] = (unsigned char)length;
169 msg_buf[sb_offset + 2] = msg_buf[sb_offset];
170 msg_buf[sb_offset + 4] = (unsigned char)(*msg_bufpos & 0xff);
171 msg_buf[sb_offset + 5] = (unsigned char)((*msg_bufpos >> 8) & 0xff);
172 memcpy(&msg_buf[*msg_bufpos], data, msg_buf[sb_offset]);
173 *msg_bufpos += length;
174}
175
176const char *
177ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
178{
179 struct buffer out = alloc_buf_gc(96, gc);
180 /* try a minimal NTLM handshake
181 *
182 * http://davenport.sourceforge.net/ntlm.html
183 *
184 * This message contains only the NTLMSSP signature,
185 * the NTLM message type,
186 * and the minimal set of flags (Negotiate NTLM and Negotiate OEM).
187 *
188 */
189 buf_printf(&out, "%s", "TlRMTVNTUAABAAAAAgIAAA==");
190 return (BSTR(&out));
191}
192
193const char *
194ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc)
195{
196 /* NTLM handshake
197 *
198 * http://davenport.sourceforge.net/ntlm.html
199 *
200 */
201
202 char pwbuf[sizeof(p->up.password) * 2]; /* for unicode password */
203 uint8_t phase3[464];
204
207 int i, ret_val;
208
210 char userdomain_u[256]; /* for uppercase unicode username and domain */
211 char userdomain[128]; /* the same as previous but ascii */
214 uint8_t *ntlmv2_blob = ntlmv2_response + 16; /* inside ntlmv2_response, length: 128 */
215 int ntlmv2_blob_size = 0;
216 int phase3_bufpos = 0x40; /* offset to next security buffer data to be added */
217 size_t len;
218
219 char domain[128];
220 char username[128];
221 char *separator;
222
223 ASSERT(strlen(p->up.username) > 0);
224 ASSERT(strlen(p->up.password) > 0);
225
226 /* username parsing */
227 separator = strchr(p->up.username, '\\');
228 if (separator == NULL)
229 {
230 strncpy(username, p->up.username, sizeof(username) - 1);
231 username[sizeof(username) - 1] = 0;
232 domain[0] = 0;
233 }
234 else
235 {
236 strncpy(username, separator + 1, sizeof(username) - 1);
237 username[sizeof(username) - 1] = 0;
238 len = separator - p->up.username;
239 if (len > sizeof(domain) - 1)
240 {
241 len = sizeof(domain) - 1;
242 }
243 strncpy(domain, p->up.username, len);
244 domain[len] = 0;
245 }
246
247
248 /* fill 1st 16 bytes with md4 hash, disregard terminating null */
249 int unicode_len = unicodize(pwbuf, p->up.password) - 2;
251
252 /* pad to 21 bytes */
254
255 /* If the decoded challenge is shorter than required by the protocol,
256 * the missing bytes will be NULL, as buf2 is known to be zeroed
257 * when this decode happens.
258 */
259 uint8_t buf2[512]; /* decoded reply from proxy */
260 CLEAR(buf2);
262 if (ret_val < 0)
263 {
264 msg(M_WARN, "NTLM: base64 decoding of phase 2 response failed");
265 return NULL;
266 }
267
268 /* extract the challenge from bytes 24-31 */
269 for (i = 0; i < 8; i++)
270 {
271 challenge[i] = buf2[i + 24];
272 }
273
274 /* Generate NTLMv2 response */
275 int tib_len;
276
277 /* NTLMv2 hash */
278 strcpy(userdomain, username);
280 if (strlen(username) + strlen(domain) < sizeof(userdomain))
281 {
282 strcat(userdomain, domain);
283 }
284 else
285 {
286 msg(M_INFO, "NTLM: Username or domain too long");
287 }
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 =
316 buf2[hoff] | (buf2[hoff + 1] << 8) | (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,
332 "NTLM: phase 2 response from server too long (need %d bytes at offset %u)",
334 return NULL;
335 }
336 /* Get Target Information block pointer */
337 tib_ptr = buf2 + tib_pos;
338 /* Copy Target Information block into the blob */
340 }
341 }
342 else
343 {
344 tib_len = 0;
345 }
346
347 /* Unknown, zero works */
348 ntlmv2_blob[0x1c + tib_len] = 0;
349
350 /* Get blob length */
351 ntlmv2_blob_size = 0x20 + tib_len;
352
353 /* Add challenge from message 2 */
355
356 /* hmac-md5 */
358
359 /* Add hmac-md5 result to the blob.
360 * Note: This overwrites challenge previously written at
361 * ntlmv2_response[8..15] */
363
364 memset(phase3, 0, sizeof(phase3)); /* clear reply */
365
366 strcpy((char *)phase3, "NTLMSSP\0"); /* signature */
367 phase3[8] = 3; /* type 3 */
368
369 /* NTLMv2 response */
371 sizeof(phase3));
372
373 /* username in ascii */
374 add_security_buffer(0x24, username, strlen(username), phase3, &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, phase3_bufpos, gc));
390}
391
392#if defined(__GNUC__) || defined(__clang__)
393#pragma GCC diagnostic pop
394#endif
395#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:1725
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:83
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:158
static void my_strupr(char *str)
Definition ntlm.c:119
const char * ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc)
Definition ntlm.c:194
#define UINTEGER64
Definition ntlm.c:50
const char * ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
Definition ntlm.c:177
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:144
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:107
#define UINT64(c)
Definition ntlm.c:51
#define CLEAR(x)
Definition basic.h:32
#define M_ERR
Definition error.h:106
#define msg(flags,...)
Definition error.h:152
#define ASSERT(x)
Definition error.h:219
#define M_WARN
Definition error.h:92
static time_t openvpn_time(time_t *t)
Definition otime.h:94
uint8_t * make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc)
Definition proxy.c:224
int openvpn_base64_decode(const char *str, void *data, int size)
Definition base64.c:160
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:131