1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 - 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of KTH nor the names of its contributors may be
18178825Sdfr *    used to endorse or promote products derived from this software without
19178825Sdfr *    specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22178825Sdfr * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24178825Sdfr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25178825Sdfr * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26178825Sdfr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27178825Sdfr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28178825Sdfr * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29178825Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30178825Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31178825Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "config.h"
35178825Sdfr
36178825Sdfr#include <stdio.h>
37178825Sdfr#include <err.h>
38178825Sdfr#include <roken.h>
39178825Sdfr#include <getarg.h>
40178825Sdfr
41233294Sstas#include <krb5-types.h> /* or <inttypes.h> */
42178825Sdfr#include <heimntlm.h>
43178825Sdfr
44178825Sdfrstatic int
45178825Sdfrtest_parse(void)
46178825Sdfr{
47233294Sstas    const char *user = "foo",
48178825Sdfr	*domain = "mydomain",
49178825Sdfr	*password = "digestpassword",
50178825Sdfr	*target = "DOMAIN";
51178825Sdfr    struct ntlm_type1 type1;
52178825Sdfr    struct ntlm_type2 type2;
53178825Sdfr    struct ntlm_type3 type3;
54178825Sdfr    struct ntlm_buf data;
55233294Sstas    int ret, flags;
56233294Sstas
57178825Sdfr    memset(&type1, 0, sizeof(type1));
58178825Sdfr
59178825Sdfr    type1.flags = NTLM_NEG_UNICODE|NTLM_NEG_TARGET|NTLM_NEG_NTLM;
60178825Sdfr    type1.domain = rk_UNCONST(domain);
61178825Sdfr    type1.hostname = NULL;
62178825Sdfr    type1.os[0] = 0;
63178825Sdfr    type1.os[1] = 0;
64178825Sdfr
65178825Sdfr    ret = heim_ntlm_encode_type1(&type1, &data);
66178825Sdfr    if (ret)
67178825Sdfr	errx(1, "heim_ntlm_encode_type1");
68178825Sdfr
69178825Sdfr    memset(&type1, 0, sizeof(type1));
70178825Sdfr
71178825Sdfr    ret = heim_ntlm_decode_type1(&data, &type1);
72178825Sdfr    free(data.data);
73178825Sdfr    if (ret)
74178825Sdfr	errx(1, "heim_ntlm_encode_type1");
75178825Sdfr
76178825Sdfr    heim_ntlm_free_type1(&type1);
77178825Sdfr
78178825Sdfr    /*
79178825Sdfr     *
80178825Sdfr     */
81178825Sdfr
82178825Sdfr    memset(&type2, 0, sizeof(type2));
83178825Sdfr
84178825Sdfr    flags = NTLM_NEG_UNICODE | NTLM_NEG_NTLM | NTLM_TARGET_DOMAIN;
85178825Sdfr    type2.flags = flags;
86178825Sdfr
87233294Sstas    memset(type2.challenge, 0x7f, sizeof(type2.challenge));
88178825Sdfr    type2.targetname = rk_UNCONST(target);
89178825Sdfr    type2.targetinfo.data = NULL;
90178825Sdfr    type2.targetinfo.length = 0;
91178825Sdfr
92178825Sdfr    ret = heim_ntlm_encode_type2(&type2, &data);
93178825Sdfr    if (ret)
94178825Sdfr	errx(1, "heim_ntlm_encode_type2");
95178825Sdfr
96178825Sdfr    memset(&type2, 0, sizeof(type2));
97178825Sdfr
98178825Sdfr    ret = heim_ntlm_decode_type2(&data, &type2);
99178825Sdfr    free(data.data);
100178825Sdfr    if (ret)
101178825Sdfr	errx(1, "heim_ntlm_decode_type2");
102178825Sdfr
103178825Sdfr    heim_ntlm_free_type2(&type2);
104178825Sdfr
105178825Sdfr    /*
106178825Sdfr     *
107178825Sdfr     */
108178825Sdfr
109178825Sdfr    memset(&type3, 0, sizeof(type3));
110178825Sdfr
111178825Sdfr    type3.flags = flags;
112178825Sdfr    type3.username = rk_UNCONST(user);
113178825Sdfr    type3.targetname = rk_UNCONST(target);
114178825Sdfr    type3.ws = rk_UNCONST("workstation");
115178825Sdfr
116178825Sdfr    {
117178825Sdfr	struct ntlm_buf key;
118178825Sdfr	heim_ntlm_nt_key(password, &key);
119178825Sdfr
120178825Sdfr	heim_ntlm_calculate_ntlm1(key.data, key.length,
121233294Sstas				  type2.challenge,
122178825Sdfr				  &type3.ntlm);
123178825Sdfr	free(key.data);
124178825Sdfr    }
125178825Sdfr
126178825Sdfr    ret = heim_ntlm_encode_type3(&type3, &data);
127178825Sdfr    if (ret)
128178825Sdfr	errx(1, "heim_ntlm_encode_type3");
129178825Sdfr
130178825Sdfr    free(type3.ntlm.data);
131178825Sdfr
132178825Sdfr    memset(&type3, 0, sizeof(type3));
133178825Sdfr
134178825Sdfr    ret = heim_ntlm_decode_type3(&data, 1, &type3);
135178825Sdfr    free(data.data);
136178825Sdfr    if (ret)
137178825Sdfr	errx(1, "heim_ntlm_decode_type3");
138178825Sdfr
139178825Sdfr    if (strcmp("workstation", type3.ws) != 0)
140178825Sdfr	errx(1, "type3 ws wrong");
141178825Sdfr
142178825Sdfr    if (strcmp(target, type3.targetname) != 0)
143178825Sdfr	errx(1, "type3 targetname wrong");
144178825Sdfr
145178825Sdfr    if (strcmp(user, type3.username) != 0)
146178825Sdfr	errx(1, "type3 username wrong");
147178825Sdfr
148178825Sdfr
149178825Sdfr    heim_ntlm_free_type3(&type3);
150178825Sdfr
151178825Sdfr    /*
152178825Sdfr     * NTLMv2
153178825Sdfr     */
154178825Sdfr
155178825Sdfr    memset(&type2, 0, sizeof(type2));
156178825Sdfr
157178825Sdfr    flags = NTLM_NEG_UNICODE | NTLM_NEG_NTLM | NTLM_TARGET_DOMAIN;
158178825Sdfr    type2.flags = flags;
159178825Sdfr
160233294Sstas    memset(type2.challenge, 0x7f, sizeof(type2.challenge));
161178825Sdfr    type2.targetname = rk_UNCONST(target);
162178825Sdfr    type2.targetinfo.data = "\x00\x00";
163178825Sdfr    type2.targetinfo.length = 2;
164178825Sdfr
165178825Sdfr    ret = heim_ntlm_encode_type2(&type2, &data);
166178825Sdfr    if (ret)
167178825Sdfr	errx(1, "heim_ntlm_encode_type2");
168178825Sdfr
169178825Sdfr    memset(&type2, 0, sizeof(type2));
170178825Sdfr
171178825Sdfr    ret = heim_ntlm_decode_type2(&data, &type2);
172178825Sdfr    free(data.data);
173178825Sdfr    if (ret)
174178825Sdfr	errx(1, "heim_ntlm_decode_type2");
175178825Sdfr
176178825Sdfr    heim_ntlm_free_type2(&type2);
177178825Sdfr
178178825Sdfr    return 0;
179178825Sdfr}
180178825Sdfr
181178825Sdfrstatic int
182178825Sdfrtest_keys(void)
183178825Sdfr{
184178825Sdfr    const char
185178825Sdfr	*username = "test",
186178825Sdfr	*password = "test1234",
187178825Sdfr	*target = "TESTNT";
188233294Sstas    const unsigned char
189233294Sstas	serverchallenge[8] = "\x67\x7f\x1c\x55\x7a\x5e\xe9\x6c";
190178825Sdfr    struct ntlm_buf infotarget, infotarget2, answer, key;
191178825Sdfr    unsigned char ntlmv2[16], ntlmv2_1[16];
192178825Sdfr    int ret;
193233294Sstas
194178825Sdfr    infotarget.length = 70;
195178825Sdfr    infotarget.data =
196178825Sdfr	"\x02\x00\x0c\x00\x54\x00\x45\x00\x53\x00\x54\x00\x4e\x00\x54\x00"
197178825Sdfr	"\x01\x00\x0c\x00\x4d\x00\x45\x00\x4d\x00\x42\x00\x45\x00\x52\x00"
198178825Sdfr	"\x03\x00\x1e\x00\x6d\x00\x65\x00\x6d\x00\x62\x00\x65\x00\x72\x00"
199178825Sdfr	    "\x2e\x00\x74\x00\x65\x00\x73\x00\x74\x00\x2e\x00\x63\x00\x6f"
200178825Sdfr	    "\x00\x6d\x00"
201178825Sdfr	"\x00\x00\x00\x00";
202178825Sdfr
203178825Sdfr    answer.length = 0;
204178825Sdfr    answer.data = NULL;
205178825Sdfr
206178825Sdfr    heim_ntlm_nt_key(password, &key);
207178825Sdfr
208178825Sdfr    ret = heim_ntlm_calculate_ntlm2(key.data,
209178825Sdfr				    key.length,
210178825Sdfr				    username,
211178825Sdfr				    target,
212233294Sstas				    serverchallenge,
213178825Sdfr				    &infotarget,
214178825Sdfr				    ntlmv2,
215178825Sdfr				    &answer);
216178825Sdfr    if (ret)
217178825Sdfr	errx(1, "heim_ntlm_calculate_ntlm2");
218178825Sdfr
219178825Sdfr    ret = heim_ntlm_verify_ntlm2(key.data,
220178825Sdfr				 key.length,
221178825Sdfr				 username,
222178825Sdfr				 target,
223178825Sdfr				 0,
224233294Sstas				 serverchallenge,
225178825Sdfr				 &answer,
226178825Sdfr				 &infotarget2,
227178825Sdfr				 ntlmv2_1);
228178825Sdfr    if (ret)
229178825Sdfr	errx(1, "heim_ntlm_verify_ntlm2");
230178825Sdfr
231178825Sdfr    if (memcmp(ntlmv2, ntlmv2_1, sizeof(ntlmv2)) != 0)
232178825Sdfr	errx(1, "ntlm master key not same");
233178825Sdfr
234178825Sdfr    if (infotarget.length > infotarget2.length)
235178825Sdfr	errx(1, "infotarget length");
236178825Sdfr
237178825Sdfr    if (memcmp(infotarget.data, infotarget2.data, infotarget.length) != 0)
238178825Sdfr	errx(1, "infotarget not the same");
239178825Sdfr
240178825Sdfr    free(key.data);
241178825Sdfr    free(answer.data);
242178825Sdfr    free(infotarget2.data);
243178825Sdfr
244178825Sdfr    return 0;
245178825Sdfr}
246178825Sdfr
247178825Sdfrstatic int
248178825Sdfrtest_ntlm2_session_resp(void)
249178825Sdfr{
250178825Sdfr    int ret;
251178825Sdfr    struct ntlm_buf lm, ntlm;
252178825Sdfr
253233294Sstas    const unsigned char lm_resp[24] =
254178825Sdfr	"\xff\xff\xff\x00\x11\x22\x33\x44"
255178825Sdfr	"\x00\x00\x00\x00\x00\x00\x00\x00"
256178825Sdfr	"\x00\x00\x00\x00\x00\x00\x00\x00";
257233294Sstas    const unsigned char ntlm2_sess_resp[24] =
258178825Sdfr	"\x10\xd5\x50\x83\x2d\x12\xb2\xcc"
259178825Sdfr	"\xb7\x9d\x5a\xd1\xf4\xee\xd3\xdf"
260178825Sdfr	"\x82\xac\xa4\xc3\x68\x1d\xd4\x55";
261233294Sstas
262178825Sdfr    const unsigned char client_nonce[8] =
263178825Sdfr	"\xff\xff\xff\x00\x11\x22\x33\x44";
264233294Sstas    const unsigned char server_challenge[8] =
265178825Sdfr	"\x01\x23\x45\x67\x89\xab\xcd\xef";
266178825Sdfr
267178825Sdfr    const unsigned char ntlm_hash[16] =
268178825Sdfr	"\xcd\x06\xca\x7c\x7e\x10\xc9\x9b"
269178825Sdfr	"\x1d\x33\xb7\x48\x5a\x2e\xd8\x08";
270178825Sdfr
271178825Sdfr    ret = heim_ntlm_calculate_ntlm2_sess(client_nonce,
272233294Sstas					 server_challenge,
273178825Sdfr					 ntlm_hash,
274178825Sdfr					 &lm,
275178825Sdfr					 &ntlm);
276178825Sdfr    if (ret)
277178825Sdfr	errx(1, "heim_ntlm_calculate_ntlm2_sess_resp");
278178825Sdfr
279178825Sdfr    if (lm.length != 24 || memcmp(lm.data, lm_resp, 24) != 0)
280178825Sdfr	errx(1, "lm_resp wrong");
281178825Sdfr    if (ntlm.length != 24 || memcmp(ntlm.data, ntlm2_sess_resp, 24) != 0)
282178825Sdfr	errx(1, "ntlm2_sess_resp wrong");
283233294Sstas
284178825Sdfr    free(lm.data);
285178825Sdfr    free(ntlm.data);
286178825Sdfr
287178825Sdfr
288178825Sdfr    return 0;
289178825Sdfr}
290178825Sdfr
291233294Sstasstatic int
292233294Sstastest_targetinfo(void)
293233294Sstas{
294233294Sstas    struct ntlm_targetinfo ti;
295233294Sstas    struct ntlm_buf buf;
296233294Sstas    const char *dnsservername = "dnsservername";
297233294Sstas    int ret;
298233294Sstas
299233294Sstas    memset(&ti, 0, sizeof(ti));
300233294Sstas
301233294Sstas    ti.dnsservername = rk_UNCONST(dnsservername);
302233294Sstas    ti.avflags = 1;
303233294Sstas    ret = heim_ntlm_encode_targetinfo(&ti, 1, &buf);
304233294Sstas    if (ret)
305233294Sstas	return ret;
306233294Sstas
307233294Sstas    memset(&ti, 0, sizeof(ti));
308233294Sstas
309233294Sstas    ret = heim_ntlm_decode_targetinfo(&buf, 1, &ti);
310233294Sstas    if (ret)
311233294Sstas	return ret;
312233294Sstas
313233294Sstas    if (ti.dnsservername == NULL ||
314233294Sstas	strcmp(ti.dnsservername, dnsservername) != 0)
315233294Sstas	errx(1, "ti.dnshostname != %s", dnsservername);
316233294Sstas    if (ti.avflags != 1)
317233294Sstas	errx(1, "ti.avflags != 1");
318233294Sstas
319233294Sstas    heim_ntlm_free_targetinfo(&ti);
320233294Sstas
321233294Sstas    return 0;
322233294Sstas}
323233294Sstas
324233294Sstasstatic int verbose_flag = 0;
325178825Sdfrstatic int version_flag = 0;
326178825Sdfrstatic int help_flag	= 0;
327178825Sdfr
328178825Sdfrstatic struct getargs args[] = {
329233294Sstas    {"verbose",	0,	arg_flag,	&verbose_flag, "verbose printing", NULL },
330178825Sdfr    {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
331178825Sdfr    {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
332178825Sdfr};
333178825Sdfr
334178825Sdfrstatic void
335178825Sdfrusage (int ret)
336178825Sdfr{
337178825Sdfr    arg_printusage (args, sizeof(args)/sizeof(*args),
338178825Sdfr		    NULL, "");
339178825Sdfr    exit (ret);
340178825Sdfr}
341178825Sdfr
342178825Sdfrint
343178825Sdfrmain(int argc, char **argv)
344178825Sdfr{
345178825Sdfr    int ret = 0, optind = 0;
346178825Sdfr
347178825Sdfr    setprogname(argv[0]);
348178825Sdfr
349178825Sdfr    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
350178825Sdfr	usage(1);
351233294Sstas
352178825Sdfr    if (help_flag)
353178825Sdfr	usage (0);
354178825Sdfr
355178825Sdfr    if(version_flag){
356178825Sdfr	print_version(NULL);
357178825Sdfr	exit(0);
358178825Sdfr    }
359178825Sdfr
360178825Sdfr    argc -= optind;
361178825Sdfr    argv += optind;
362178825Sdfr
363233294Sstas    if (verbose_flag)
364233294Sstas	printf("test_parse\n");
365233294Sstas
366178825Sdfr    ret += test_parse();
367233294Sstas    if (verbose_flag)
368233294Sstas	printf("test_keys\n");
369233294Sstas
370178825Sdfr    ret += test_keys();
371233294Sstas    if (verbose_flag)
372233294Sstas	printf("test_ntlm2_session_resp\n");
373178825Sdfr    ret += test_ntlm2_session_resp();
374178825Sdfr
375233294Sstas    if (verbose_flag)
376233294Sstas	printf("test_targetinfo\n");
377233294Sstas    ret += test_targetinfo();
378233294Sstas
379233294Sstas    return ret;
380178825Sdfr}
381