mingw: fix build break
[siplcs.git] / src / core / sip-sec-ntlm.c
bloba70ca26d0eba825dbf845b731336e2466739b10d
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2017 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2009, 2010 pier11 <pier11@operamail.com>
8 * Copyright (C) 2008 Novell, Inc.
9 * Modify 2007, Anibal Avelar <avelar@gmail.com>
10 * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
12 * Implemented with reference to the follow documentation:
13 * - http://davenport.sourceforge.net/ntlm.html
14 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
15 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 * Byte order policy:
35 * - NTLM messages (byte streams) should be in LE (Little-Endian) byte order.
36 * - internal int16, int32, int64 should contain proper values.
37 * For example: 01 00 00 00 LE should be translated to (int32)1
38 * - When reading/writing from/to NTLM message appropriate conversion should
39 * be taken to properly present integer values. glib's "Byte Order Macros"
40 * should be used for that, for example GUINT32_FROM_LE
42 * NOTE: The Byte Order Macros can have side effects!
43 * Do *NOT* make any calculations inside the macros!
45 * - All calculations should be made in dedicated local variables (system-endian),
46 * not in NTLM (LE) structures.
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
53 #include <stdlib.h>
54 #include <string.h>
55 #include <time.h>
57 #include <glib.h>
59 #ifdef HAVE_LANGINFO_CODESET
60 #include <langinfo.h>
61 #endif /* HAVE_LANGINFO_CODESET */
63 #include "sipe-common.h"
64 #include "sip-sec.h"
65 #include "sip-sec-mech.h"
66 #include "sip-sec-ntlm.h"
67 #include "sipe-backend.h"
68 #include "sipe-crypt.h"
69 #include "sipe-digest.h"
70 #include "sipe-utils.h"
72 #include "md4.h"
74 /* [MS-NLMP] */
75 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
76 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
77 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
78 #define r9 0x00000008 /* r9 */
79 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
80 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
81 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
82 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
83 #define r8 0x00000100 /* r8 */
84 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
85 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
86 #define anonymous 0x00000800 /* J */
87 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
88 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
89 #define r7 0x00004000 /* r7 */
90 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
91 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
92 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
93 #define r6 0x00040000 /* r6 */
94 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
95 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
96 #define r5 0x00200000 /* r5 */
97 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
98 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
99 #define r4 0x01000000 /* r4 */
100 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
101 #define r3 0x04000000 /* r3 */
102 #define r2 0x08000000 /* r2 */
103 #define r1 0x10000000 /* r1 */
104 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
105 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
106 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
108 /* AvId */
109 #define MsvAvEOL 0
110 #define MsvAvNbComputerName 1
111 #define MsvAvNbDomainName 2
112 #define MsvAvDnsComputerName 3
113 #define MsvAvDnsDomainName 4
114 /** @since Windows XP */
115 #define MsvAvDnsTreeName 5
116 /** @since Windows XP */
117 #define MsvAvFlags 6
118 /** @since Windows Vista */
119 #define MsvAvTimestamp 7
120 /** @since Windows Vista */
121 #define MsAvRestrictions 8
122 /** @since Windows 7 */
123 #define MsvAvTargetName 9
124 /** @since Windows 7 */
125 #define MsvChannelBindings 10
127 /* time_t <-> (guint64) time_val conversion */
128 #define TIME_VAL_FACTOR 10000000
129 #define TIME_VAL_OFFSET 116444736000000000LL
130 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
131 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
133 /* 8 bytes */
134 /* LE (Little Endian) byte order */
135 struct version {
136 guint8 product_major_version;
137 guint8 product_minor_version;
138 guint16 product_build;
139 guint8 zero2[3];
140 guint8 ntlm_revision_current;
144 * NTLMv1 is no longer used except in tests. R.I.P.
146 * It remains in this file only for documentary purposes
148 #ifdef _SIPE_COMPILING_TESTS
149 static gboolean use_ntlm_v2 = FALSE;
151 guint64 test_time_val = 0; /* actual time in implementation */
152 guchar test_client_challenge [8]; /* random in implementation */
153 guchar test_random_session_key[16]; /* random in implementation */
154 struct version test_version; /* hard-coded in implementation */
155 #endif
157 /* Minimum set of common features we need to work. */
158 /* we operate in NTLMv2 mode */
159 #define NEGOTIATE_FLAGS_COMMON_MIN \
160 ( NTLMSSP_NEGOTIATE_UNICODE | \
161 NTLMSSP_NEGOTIATE_NTLM | \
162 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
163 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
164 NTLMSSP_NEGOTIATE_TARGET_INFO \
167 /* Negotiate flags for connection-based mode. Nice to have but optional. */
168 #define NEGOTIATE_FLAGS_CONN \
169 ( NEGOTIATE_FLAGS_COMMON_MIN | \
170 NTLMSSP_NEGOTIATE_VERSION | \
171 NTLMSSP_NEGOTIATE_128 | \
172 NTLMSSP_NEGOTIATE_56 | \
173 NTLMSSP_REQUEST_TARGET \
176 /* Extra negotiate flags required in connectionless NTLM */
177 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
178 ( NTLMSSP_NEGOTIATE_SIGN | \
179 NTLMSSP_NEGOTIATE_DATAGRAM | \
180 NTLMSSP_NEGOTIATE_IDENTIFY | \
181 NTLMSSP_NEGOTIATE_KEY_EXCH \
184 /* Negotiate flags required in connectionless NTLM */
185 #define NEGOTIATE_FLAGS_CONNLESS \
186 ( NEGOTIATE_FLAGS_CONN | \
187 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
190 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
191 #define NTLMSSP_LM_RESP_LEN 24
192 #define NTLMSSP_SESSION_KEY_LEN 16
194 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
196 /* 4 bytes */
197 /* LE (Little Endian) byte order */
198 struct av_pair {
199 guint16 av_id;
200 guint16 av_len;
201 /* value */
204 /* to meet sparc's alignment requirement */
205 #define ALIGN_AV \
206 memcpy(&av_aligned, av, sizeof(av_aligned)); \
207 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
208 av_len = GUINT16_FROM_LE(av_aligned.av_len)
209 #define ALIGN_AV_LOOP_START \
210 struct av_pair av_aligned; \
211 guint16 av_id; \
212 guint16 av_len; \
213 ALIGN_AV; \
214 while (av_id != MsvAvEOL) { \
215 gchar *av_value = ((gchar *)av) + \
216 sizeof(struct av_pair); \
217 switch (av_id)
218 #define ALIGN_AV_LOOP_END \
219 av = av_value + av_len; \
220 ALIGN_AV; \
223 /* 8 bytes */
224 /* LE (Little Endian) byte order */
225 struct smb_header {
226 guint16 len;
227 guint16 maxlen;
228 guint32 offset;
231 /* LE (Little Endian) byte order */
232 struct ntlm_message {
233 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
234 guint32 type; /* 0x00000003 */
237 /* LE (Little Endian) byte order */
238 struct negotiate_message {
239 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
240 guint32 type; /* 0x00000001 */
241 guint32 flags; /* 0xb203 */
242 struct smb_header domain;
243 struct smb_header host;
244 struct version ver;
245 /* payload
246 * - DomainName (always ASCII)
247 * - WorkstationName (always ASCII)
251 /* LE (Little Endian) byte order */
252 struct challenge_message {
253 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
254 guint32 type; /* 0x00000002 */
255 struct smb_header target_name;
256 guint32 flags; /* 0x8201 */
257 guint8 nonce[8];
258 guint8 zero1[8];
259 struct smb_header target_info;
260 struct version ver;
261 /* payload
262 * - TargetName (negotiated encoding)
263 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
267 /* LE (Little Endian) byte order */
268 struct authenticate_message {
269 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
270 guint32 type; /* 0x00000003 */
271 /** LmChallengeResponseFields */
272 struct smb_header lm_resp;
273 /** NtChallengeResponseFields */
274 struct smb_header nt_resp;
275 /** DomainNameFields */
276 struct smb_header domain;
277 /** UserNameFields */
278 struct smb_header user;
279 /** WorkstationFields */
280 struct smb_header host;
281 /** EncryptedRandomSessionKeyFields */
282 struct smb_header session_key;
283 guint32 flags;
284 struct version ver;
285 //guint8 mic[16];
286 /* payload
287 * - LmChallengeResponse
288 * - NtChallengeResponse
289 * - DomainName (negotiated encoding)
290 * - UserName (negotiated encoding)
291 * - Workstation (negotiated encoding)
292 * - EncryptedRandomSessionKey
296 #ifndef HAVE_LANGINFO_CODESET
297 #ifdef __sun__
298 static char SIPE_DEFAULT_CODESET[] = "US-ASCII";
299 #else
300 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
301 #endif
302 #endif
304 /* Private Methods */
306 /* Utility Functions */
307 static GIConv convert_from_utf16le = (GIConv)-1;
308 static GIConv convert_to_utf16le = (GIConv)-1;
310 /* Analyzer only needs the _describe() functions */
311 #ifndef _SIPE_COMPILING_ANALYZER
313 static gsize
314 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
316 gsize inbytes = strlen(source);
317 gsize outbytes = remlen;
318 if (remlen)
319 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
320 return(remlen - outbytes);
323 #endif /* !_SIPE_COMPILING_ANALYZER */
325 /* UTF-16LE to native encoding
326 * Must be g_free'd after use */
327 static gchar *
328 unicode_strconvcopy_back(const gchar *source, gsize len)
330 gsize outbytes = 2 * len;
331 gchar *dest = g_new0(gchar, outbytes + 1);
332 gchar *outbuf = dest;
333 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
334 return dest;
337 /* Analyzer only needs the _describe() functions */
338 #ifndef _SIPE_COMPILING_ANALYZER
340 /* crc32 source copy from gg's common.c */
341 static guint32 crc32_table[256];
342 static int crc32_initialized = 0;
344 static void crc32_make_table()
346 guint32 h = 1;
347 unsigned int i, j;
349 memset(crc32_table, 0, sizeof(crc32_table));
351 for (i = 128; i; i >>= 1) {
352 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
354 for (j = 0; j < 256; j += 2 * i)
355 crc32_table[i + j] = crc32_table[j] ^ h;
358 crc32_initialized = 1;
361 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
363 if (!crc32_initialized)
364 crc32_make_table();
366 if (!buf || len < 0)
367 return crc;
369 crc ^= 0xffffffffL;
371 while (len--)
372 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
374 return crc ^ 0xffffffffL;
377 static guint32
378 CRC32 (const char *msg, int len)
380 guint32 crc = 0L;
381 crc = crc32(crc, (guint8 *) msg, len);
382 return crc;
385 /* Cyphers */
387 #ifdef _SIPE_COMPILING_TESTS
388 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
390 key[0] = key_56[0];
391 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
392 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
393 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
394 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
395 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
396 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
397 key[7] = (key_56[6] << 1) & 0xFF;
400 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
401 static void
402 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
404 unsigned char key[8];
405 setup_des_key(k, key);
406 sipe_crypt_des(key, d, 8, results);
409 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
410 static void
411 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
413 unsigned char keys[21];
415 /* Copy the first 16 bytes */
416 memcpy(keys, k, 16);
418 /* Zero out the last 5 bytes of the key */
419 memset(keys + 16, 0, 5);
421 DES(keys, d, results);
422 DES(keys + 7, d, results + 8);
423 DES(keys + 14, d, results + 16);
425 #endif
427 #define RC4K(key, key_len, plain, plain_len, encrypted) \
428 sipe_crypt_rc4((key), (key_len), (plain), (plain_len), (encrypted))
430 /* out 16 bytes */
431 #define MD4(d, len, result) sipe_digest_md4((d), (len), (result))
433 /* out 16 bytes */
434 #define MD5(d, len, result) sipe_digest_md5((d), (len), (result))
436 /* out 16 bytes */
438 static void
439 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
441 int i;
442 unsigned char ibuff[64 + data_len];
443 unsigned char obuff[64 + 16];
445 if (key_len > 64)
446 key_len = 64;
448 for (i = 0; i < key_len; i++) {
449 ibuff[i] = key[i] ^ 0x36;
450 obuff[i] = key[i] ^ 0x5c;
452 for (i = key_len; i < 64; i++) {
453 ibuff[i] = 0x36;
454 obuff[i] = 0x5c;
457 memcpy(ibuff+64, data, data_len);
459 MD5 (ibuff, 64 + data_len, obuff+64);
460 MD5 (obuff, 64 + 16, result);
462 #define HMAC_MD5 HMACT64
465 /* out 16 bytes */
466 #define HMAC_MD5(key, key_len, data, data_len, result) \
467 sipe_digest_hmac_md5((key), (key_len), (data), (data_len), (result))
469 /* NTLM Core Methods */
471 static void
472 NONCE(unsigned char *buffer, int num)
474 int i;
475 for (i = 0; i < num; i++) {
476 buffer[i] = (rand() & 0xff);
480 #ifdef _SIPE_COMPILING_TESTS
481 static void
482 Z(unsigned char *buffer, int num)
484 memset(buffer, 0, num);
487 static void
488 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
490 /* "KGS!@#$%" */
491 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
492 unsigned char uppercase_password[14];
493 int i;
495 int len = strlen(password);
496 if (len > 14) {
497 len = 14;
500 // Uppercase password
501 for (i = 0; i < len; i++) {
502 uppercase_password[i] = g_ascii_toupper(password[i]);
505 // Zero the rest
506 for (; i < 14; i++) {
507 uppercase_password[i] = 0;
510 DES (uppercase_password, magic, result);
511 DES (uppercase_password + 7, magic, result + 8);
513 #endif
516 Define NTOWFv1(Passwd, User, UserDom) as
517 MD4(UNICODE(Passwd))
518 EndDefine
520 /* out 16 bytes */
521 static void
522 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
524 int len_u = 2 * strlen(password); // utf16 should not be more
525 unsigned char *unicode_password = g_malloc(len_u);
527 /* well, if allocation failed the rest will crash & burn soon anyway... */
528 if (unicode_password) {
529 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
530 MD4 (unicode_password, len_u, result);
531 g_free(unicode_password);
536 Define NTOWFv2(Passwd, User, UserDom) as
537 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
538 EndDefine
540 /* out 16 bytes */
541 static void
542 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
544 unsigned char response_key_nt_v1 [16];
545 int len_user = user ? strlen(user) : 0;
546 int len_domain = strlen(domain);
547 int len_user_u = 2 * len_user; // utf16 should not be more
548 int len_domain_u = 2 * len_domain; // utf16 should not be more
549 unsigned char *user_upper = g_malloc(len_user + 1);
550 unsigned char *buff = g_malloc((len_user + len_domain)*2);
551 int i;
553 /* Uppercase user */
554 for (i = 0; i < len_user; i++) {
555 user_upper[i] = g_ascii_toupper(user[i]);
557 user_upper[len_user] = 0;
559 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
560 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), (gchar *)domain, len_domain_u);
562 NTOWFv1(password, user, domain, response_key_nt_v1);
564 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
566 g_free(buff);
567 g_free(user_upper);
570 static void
571 compute_response(const guint32 neg_flags,
572 const unsigned char *response_key_nt,
573 const unsigned char *response_key_lm,
574 const guint8 *server_challenge,
575 const guint8 *client_challenge,
576 const guint64 time_val,
577 const guint8 *target_info,
578 int target_info_len,
579 unsigned char *lm_challenge_response,
580 unsigned char *nt_challenge_response,
581 unsigned char *session_base_key)
583 #ifdef _SIPE_COMPILING_TESTS
584 if (use_ntlm_v2)
586 #endif
588 Responserversion - The 1-byte response version. Currently set to 1.
589 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
590 Time - The 8-byte little-endian time in GMT.
591 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
592 ClientChallenge - The 8-byte challenge message generated by the client.
593 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
595 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
596 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
597 Time, //8bytes - 8
598 ClientChallenge, //8bytes - 16
599 Z(4), //4bytes - 24
600 ServerName, //variable - 28
601 Z(4)) //4bytes - 28+target_info_len
602 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
603 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
604 Set LmChallengeResponse to ConcatenationOf(
605 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
606 ClientChallenge )
607 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
608 EndDefine
610 guint8 tmp [16];
611 guint8 nt_proof_str [16];
613 /* client_challenge (8) & temp (temp_len) buff */
614 unsigned int temp_len = 8+8+8+4+target_info_len+4;
615 guint64 *temp2 = g_malloc0(8 + temp_len);
616 ((guint8 *) temp2)[8+0] = 1;
617 ((guint8 *) temp2)[8+1] = 1;
618 temp2[2] = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
619 memcpy(((guint8 *) temp2)+8+16, client_challenge, 8);
620 memcpy(((guint8 *) temp2)+8+28, target_info, target_info_len);
622 /* NTProofStr */
623 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
624 memcpy(temp2, server_challenge, 8);
625 HMAC_MD5(response_key_nt, 16, (guint8*)temp2, 8+temp_len, nt_proof_str);
627 /* NtChallengeResponse */
628 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
629 memcpy(nt_challenge_response, nt_proof_str, 16);
630 memcpy(nt_challenge_response+16, temp2+1, temp_len);
631 g_free(temp2);
633 /* SessionBaseKey */
634 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
635 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
637 /* lm_challenge_response */
638 memcpy(tmp, server_challenge, 8);
639 memcpy(tmp+8, client_challenge, 8);
640 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
641 memcpy(lm_challenge_response+16, client_challenge, 8);
643 #ifndef _SIPE_COMPILING_TESTS
644 /* Not used in NTLMv2 */
645 (void)neg_flags;
646 #else
648 else
650 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
651 // @TODO do not even reference nt_challenge_response
652 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
653 DESL (response_key_lm, server_challenge, lm_challenge_response);
654 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
655 unsigned char prehash [16];
656 unsigned char hash [16];
658 /* nt_challenge_response */
659 memcpy(prehash, server_challenge, 8);
660 memcpy(prehash + 8, client_challenge, 8);
661 MD5 (prehash, 16, hash);
662 DESL (response_key_nt, hash, nt_challenge_response);
664 /* lm_challenge_response */
665 memcpy(lm_challenge_response, client_challenge, 8);
666 Z (lm_challenge_response+8, 16);
667 } else {
668 DESL (response_key_nt, server_challenge, nt_challenge_response);
669 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
670 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
671 } else {
672 DESL (response_key_lm, server_challenge, lm_challenge_response);
676 /* Session Key */
677 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
679 #endif
682 static void
683 KXKEY ( guint32 flags,
684 const unsigned char * session_base_key,
685 const unsigned char * lm_challenge_resonse,
686 const guint8 * server_challenge, /* 8-bytes, nonce */
687 unsigned char * key_exchange_key)
689 #ifdef _SIPE_COMPILING_TESTS
690 if (use_ntlm_v2)
692 #else
693 /* Not used in NTLMv2 */
694 (void)flags;
695 (void)lm_challenge_resonse;
696 (void)server_challenge;
697 #endif
698 memcpy(key_exchange_key, session_base_key, 16);
699 #ifdef _SIPE_COMPILING_TESTS
701 else
703 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
704 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
705 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
706 EndDefine
708 guint8 tmp[16];
709 memcpy(tmp, server_challenge, 8);
710 memcpy(tmp+8, lm_challenge_resonse, 8);
711 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
712 } else {
713 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
714 memcpy(key_exchange_key, session_base_key, 16);
717 #endif
721 If (Mode equals "Client")
722 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
723 "session key to client-to-server signing key magic constant"))
724 Else
725 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
726 "session key to server-to-client signing key magic constant"))
727 Endif
729 static void
730 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
732 char * magic = client
733 ? "session key to client-to-server signing key magic constant"
734 : "session key to server-to-client signing key magic constant";
736 int len = strlen(magic) + 1;
737 unsigned char *md5_input = g_malloc(16 + len);
738 memcpy(md5_input, random_session_key, 16);
739 memcpy(md5_input + 16, magic, len);
741 MD5 (md5_input, len + 16, result);
742 g_free(md5_input);
746 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
747 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
748 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
749 Set SealKey to RandomSessionKey
750 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
751 Set SealKey to RandomSessionKey[0..6]
752 Else
753 Set SealKey to RandomSessionKey[0..4]
754 Endif
756 If (Mode equals "Client")
757 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
758 Else
759 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
760 Endif
762 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
763 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
764 Else
765 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
766 Endif
767 EndDefine
769 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
770 static void
771 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
773 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
775 char * magic = client
776 ? "session key to client-to-server sealing key magic constant"
777 : "session key to server-to-client sealing key magic constant";
779 int len = strlen(magic) + 1;
780 unsigned char *md5_input = g_malloc(16 + len);
781 int key_len;
783 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
784 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
785 key_len = 16;
786 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
787 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
788 key_len = 7;
789 } else {
790 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
791 key_len = 5;
794 memcpy(md5_input, random_session_key, key_len);
795 memcpy(md5_input + key_len, magic, len);
797 MD5 (md5_input, key_len + len, result);
798 g_free(md5_input);
800 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
802 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
803 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
804 memcpy(result, random_session_key, 7);
805 result[7] = 0xA0;
806 } else {
807 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
808 memcpy(result, random_session_key, 5);
809 result[5] = 0xE5;
810 result[6] = 0x38;
811 result[7] = 0xB0;
814 else
816 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
817 memcpy(result, random_session_key, 16);
822 = for Extended Session Security =
823 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
824 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
825 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
827 = if Extended Session Security is NOT negotiated =
828 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
829 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
830 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
831 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
833 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
835 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
836 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
838 /** MAC(Handle, SigningKey, SeqNum, Message) */
839 /* out 16 bytes */
840 static void
841 MAC (guint32 flags,
842 const char *buf,
843 unsigned int buf_len,
844 unsigned char *sign_key,
845 unsigned long sign_key_len,
846 unsigned char *seal_key,
847 unsigned long seal_key_len,
848 guint32 random_pad,
849 guint32 sequence,
850 guint32 *result)
852 guint32 *res_ptr;
854 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
856 Define MAC(Handle, SigningKey, SeqNum, Message) as
857 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
858 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
859 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
860 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
861 Set SeqNum to SeqNum + 1
862 EndDefine
864 /* If a key exchange key is negotiated
865 Define MAC(Handle, SigningKey, SeqNum, Message) as
866 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
867 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
868 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
869 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
870 Set SeqNum to SeqNum + 1
871 EndDefine
874 unsigned char seal_key_ [16];
875 guchar hmac[16];
876 guint32 *tmp = g_malloc(4 + buf_len);
878 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
879 RC4Init(Handle, SealingKey')
881 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
882 guint32 tmp2[4+1];
884 memcpy(tmp2, seal_key, seal_key_len);
885 tmp2[4] = GUINT32_TO_LE(sequence);
886 MD5 ((guchar *)tmp2, sizeof(tmp2), seal_key_);
887 } else {
888 memcpy(seal_key_, seal_key, seal_key_len);
891 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extended Session Security");
893 res_ptr = result;
894 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
895 res_ptr[3] = GUINT32_TO_LE(sequence);
897 res_ptr = tmp;
898 res_ptr[0] = GUINT32_TO_LE(sequence);
899 memcpy(tmp+1, buf, buf_len);
901 HMAC_MD5(sign_key, sign_key_len, (guchar *)tmp, 4 + buf_len, hmac);
902 g_free(tmp);
904 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
905 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
906 RC4K(seal_key_, seal_key_len, hmac, 8, (guchar *)(result+1));
907 } else {
908 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
909 memcpy(result+1, hmac, 8);
911 } else {
912 /* The content of the first 4 bytes is irrelevant */
913 guint32 crc = CRC32(buf, strlen(buf));
914 guint32 plaintext [] = {
915 GUINT32_TO_LE(0),
916 GUINT32_TO_LE(crc),
917 GUINT32_TO_LE(sequence)
918 }; // 4, 4, 4 bytes
920 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extended Session Security");
922 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, (guchar *)(result+1));
924 res_ptr = result;
925 // Highest four bytes are the Version
926 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
928 // Replace the first four bytes of the ciphertext with the random_pad
929 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
933 /* End Core NTLM Methods */
936 * @param flags (out) flags received from server
937 * @param server_challenge must be g_free()'d after use if requested
938 * @param target_info must be g_free()'d after use if requested
940 static void
941 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
942 guint32 *flags,
943 guchar **server_challenge, /* 8 bytes */
944 guint64 *time_val,
945 guchar **target_info,
946 int *target_info_len)
948 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
949 struct challenge_message *cmsg = (void *)in_buff.value;
950 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
952 /* server challenge (nonce) */
953 if (server_challenge) {
954 *server_challenge = g_memdup(cmsg->nonce, 8);
957 /* flags */
958 if (flags) {
959 *flags = host_flags;
962 /* target_info */
963 if (cmsg->target_info.len && cmsg->target_info.offset) {
964 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
965 void *av = content;
966 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
968 ALIGN_AV_LOOP_START
970 /* @since Vista */
971 case MsvAvTimestamp:
972 if (time_val) {
973 guint64 tmp;
975 /* to meet sparc's alignment requirement */
976 memcpy(&tmp, av_value, sizeof(tmp));
977 *time_val = GUINT64_FROM_LE(tmp);
979 break;
981 ALIGN_AV_LOOP_END;
983 if (target_info_len) {
984 *target_info_len = len;
986 if (target_info) {
987 *target_info = g_memdup(content, len);
993 * @param client_sign_key (out) must be g_free()'d after use
994 * @param server_sign_key (out) must be g_free()'d after use
995 * @param client_seal_key (out) must be g_free()'d after use
996 * @param server_seal_key (out) must be g_free()'d after use
997 * @param flags (in, out) negotiated flags
999 static gboolean
1000 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
1001 guchar **server_sign_key,
1002 guchar **client_seal_key,
1003 guchar **server_seal_key,
1004 const gchar *user,
1005 const gchar *password,
1006 const gchar *hostname,
1007 const gchar *domain,
1008 const guint8 *server_challenge, /* nonce */
1009 const guint64 time_val,
1010 const guint8 *target_info,
1011 int target_info_len,
1012 gboolean http,
1013 SipSecBuffer *out_buff,
1014 guint32 *flags)
1016 guint32 orig_flags = http ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
1017 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1018 int ntlmssp_nt_resp_len =
1019 #ifdef _SIPE_COMPILING_TESTS
1020 use_ntlm_v2 ?
1021 #endif
1022 (16 + (32+target_info_len))
1023 #ifdef _SIPE_COMPILING_TESTS
1024 : NTLMSSP_LM_RESP_LEN
1025 #endif
1027 gsize msglen = sizeof(struct authenticate_message)
1028 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1029 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1030 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1031 struct authenticate_message *tmsg;
1032 char *tmp;
1033 guint32 offset;
1034 guint16 len;
1035 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1036 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1037 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1038 unsigned char *nt_challenge_response = g_malloc(ntlmssp_nt_resp_len); /* variable or 24 */
1039 unsigned char session_base_key [16];
1040 unsigned char key_exchange_key [16];
1041 unsigned char exported_session_key[16];
1042 unsigned char encrypted_random_session_key [16];
1043 unsigned char key [16];
1044 unsigned char client_challenge [8];
1045 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1047 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1048 !(http || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)) ||
1049 !nt_challenge_response) /* Coverity thinks ntlmssp_nt_resp_len could be 0 */
1051 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1052 g_free(nt_challenge_response);
1053 return FALSE;
1056 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1057 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1060 tmsg = g_malloc0(msglen);
1062 NONCE (client_challenge, 8);
1064 #ifdef _SIPE_COMPILING_TESTS
1065 memcpy(client_challenge, test_client_challenge, 8);
1066 time_vl = test_time_val ? test_time_val : time_vl;
1068 if (use_ntlm_v2) {
1070 #endif
1071 NTOWFv2 (password, user, domain, response_key_nt);
1072 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1073 #ifdef _SIPE_COMPILING_TESTS
1074 } else {
1075 NTOWFv1 (password, user, domain, response_key_nt);
1076 LMOWFv1 (password, user, domain, response_key_lm);
1078 #endif
1080 compute_response(neg_flags,
1081 response_key_nt,
1082 response_key_lm,
1083 server_challenge,
1084 client_challenge,
1085 time_vl,
1086 target_info,
1087 target_info_len,
1088 lm_challenge_response, /* out */
1089 nt_challenge_response, /* out */
1090 session_base_key); /* out */
1092 /* same as session_base_key for
1093 * - NTLNv1 w/o Ext.Sess.Sec and
1094 * - NTLMv2
1096 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1098 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1099 NONCE (exported_session_key, 16); // random master key
1100 #ifdef _SIPE_COMPILING_TESTS
1101 memcpy(exported_session_key, test_random_session_key, 16);
1102 #endif
1103 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1104 } else {
1105 memcpy(exported_session_key, key_exchange_key, 16);
1108 tmp = buff_to_hex_str(exported_session_key, 16);
1109 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp);
1110 g_free(tmp);
1112 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1113 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1115 /* p.46
1116 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1117 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1119 SIGNKEY(exported_session_key, TRUE, key);
1120 *client_sign_key = g_memdup(key, 16);
1121 SIGNKEY(exported_session_key, FALSE, key);
1122 *server_sign_key = g_memdup(key, 16);
1123 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1124 *client_seal_key = g_memdup(key, 16);
1125 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1126 *server_seal_key = g_memdup(key, 16);
1129 /* @TODO: */
1130 /* @since Vista
1131 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1132 the client SHOULD provide a MIC:
1133 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1134 - then in the Value field, set bit 0x2 to 1.
1135 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1136 and the Value field bit 0x2 to 1.
1137 - Populate the MIC field with the MIC.
1140 /* Connection-oriented:
1141 Set MIC to HMAC_MD5(ExportedSessionKey,
1142 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1143 Connectionless:
1144 Set MIC to HMAC_MD5(ExportedSessionKey,
1145 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1148 /* on the server-side:
1149 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1150 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1151 Set MIC to HMAC_MD5(ExportedSessionKey,
1152 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1153 Else
1154 Set ExportedSessionKey to KeyExchangeKey
1155 Set MIC to HMAC_MD5(KeyExchangeKey,
1156 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1157 =====
1158 @since Vista
1159 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1160 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1161 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1162 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1163 an AV_PAIR structure whose two fields:
1164 - AvId == MsvAvFlags
1165 - Value bit 0x2 == 1
1166 @supported NT, 2000, XP
1167 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1168 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1169 the server time, then the server SHOULD return a failure.
1171 Connectionless:
1172 Set MIC to HMAC_MD5(ResponseKeyNT,
1173 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1176 /* authenticate message initialization */
1177 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1178 tmsg->type = GUINT32_TO_LE(3);
1180 /* Initial offset */
1181 offset = sizeof(struct authenticate_message);
1182 tmp = ((char*) tmsg) + offset;
1184 #define _FILL_SMB_HEADER(header) \
1185 tmsg->header.offset = GUINT32_TO_LE(offset); \
1186 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1187 tmp += len; \
1188 offset += len
1189 #define _APPEND_STRING(header, src) \
1190 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1191 _FILL_SMB_HEADER(header)
1192 #define _APPEND_DATA(header, src, srclen) \
1193 len = (srclen); \
1194 memcpy(tmp, (src), len); \
1195 _FILL_SMB_HEADER(header)
1197 /* Domain */
1198 _APPEND_STRING(domain, domain);
1200 /* User */
1201 _APPEND_STRING(user, user);
1203 /* Host */
1204 _APPEND_STRING(host, hostname);
1206 /* LM */
1207 /* @since Windows 7
1208 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1209 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1210 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1212 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1214 /* NT */
1215 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1217 /* Session Key */
1218 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1220 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1222 else
1224 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1225 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1228 /* Version */
1229 #ifdef _SIPE_COMPILING_TESTS
1230 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1231 #else
1232 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1233 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1234 tmsg->ver.product_minor_version = 1;
1235 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1236 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1238 #endif
1240 /* Set Negotiate Flags */
1241 tmsg->flags = GUINT32_TO_LE(neg_flags);
1242 *flags = neg_flags;
1244 out_buff->value = (guint8 *)tmsg;
1245 out_buff->length = msglen;
1247 g_free(nt_challenge_response);
1249 return TRUE;
1253 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1255 static void
1256 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1258 guint32 offset;
1259 guint16 len;
1260 int msglen = sizeof(struct negotiate_message);
1261 struct negotiate_message *tmsg = g_malloc0(msglen);
1263 /* negotiate message initialization */
1264 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1265 tmsg->type = GUINT32_TO_LE(1);
1267 /* Set Negotiate Flags */
1268 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1270 /* Domain */
1271 offset = sizeof(struct negotiate_message);
1272 tmsg->domain.offset = GUINT32_TO_LE(offset);
1273 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1275 /* Host */
1276 offset += len;
1277 tmsg->host.offset = GUINT32_TO_LE(offset);
1278 tmsg->host.len = tmsg->host.maxlen = len = 0;
1280 /* Version */
1281 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1282 tmsg->ver.product_minor_version = 1;
1283 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1284 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1286 out_buff->value = (guint8 *)tmsg;
1287 out_buff->length = msglen;
1290 static void
1291 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1292 const char *msg,
1293 guint32 random_pad,
1294 unsigned char *sign_key,
1295 unsigned char *seal_key,
1296 guint32 *result)
1298 char *res;
1300 MAC(flags, msg, strlen(msg), sign_key, 16, seal_key, 16, random_pad, 100, result);
1302 res = buff_to_hex_str((guint8 *)result, 16);
1303 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res);
1304 g_free(res);
1307 #endif /* !_SIPE_COMPILING_ANALYZER */
1309 /* Describe NTLM messages functions */
1311 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1312 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1314 static gchar *
1315 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1317 GString* str = g_string_new(NULL);
1319 flags = GUINT32_FROM_LE(flags);
1321 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1322 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1323 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1324 APPEND_NEG_FLAG(str, flags, r9, "r9");
1325 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1326 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1327 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1328 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1329 APPEND_NEG_FLAG(str, flags, r8, "r8");
1330 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1331 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1332 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1333 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1334 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1335 APPEND_NEG_FLAG(str, flags, r7, "r7");
1336 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1337 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1338 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1339 APPEND_NEG_FLAG(str, flags, r6, "r6");
1340 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1341 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1342 APPEND_NEG_FLAG(str, flags, r5, "r5");
1343 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1344 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1345 APPEND_NEG_FLAG(str, flags, r4, "r4");
1346 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1347 APPEND_NEG_FLAG(str, flags, r3, "r3");
1348 APPEND_NEG_FLAG(str, flags, r2, "r2");
1349 APPEND_NEG_FLAG(str, flags, r1, "r1");
1350 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1351 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1352 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1354 return g_string_free(str, FALSE);
1357 static gchar *
1358 sip_sec_ntlm_describe_version(struct version *ver) {
1359 GString* str = g_string_new(NULL);
1360 gchar *ver_desc = "";
1361 gchar *ntlm_revision_desc = "";
1363 if (ver->product_major_version == 6) {
1364 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1365 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1366 ver_desc = "Windows Server 2003";
1367 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1368 ver_desc = "Windows XP SP2";
1371 if (ver->ntlm_revision_current == 0x0F) {
1372 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1373 } else if (ver->ntlm_revision_current == 0x0A) {
1374 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1377 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1378 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1379 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1381 return g_string_free(str, FALSE);
1384 static gchar *
1385 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1386 const char* name)
1388 GString* str = g_string_new(NULL);
1390 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1391 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1392 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1394 return g_string_free(str, FALSE);
1397 static gchar *
1398 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1400 GString* str = g_string_new(NULL);
1401 char *tmp;
1403 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1404 g_free(tmp);
1406 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1407 g_free(tmp);
1409 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1410 g_free(tmp);
1412 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1413 g_string_append(str, tmp);
1414 g_free(tmp);
1416 if (cmsg->domain.len && cmsg->domain.offset) {
1417 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1418 g_string_append_printf(str, "\tdomain: %s\n", domain);
1419 g_free(domain);
1422 if (cmsg->host.len && cmsg->host.offset) {
1423 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1424 g_string_append_printf(str, "\thost: %s\n", host);
1425 g_free(host);
1428 return g_string_free(str, FALSE);
1431 static void
1432 describe_av_pairs(GString* str, const void *av)
1434 #define AV_DESC(av_name) \
1436 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1437 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1438 g_free(tmp); \
1441 ALIGN_AV_LOOP_START
1443 case MsvAvNbComputerName:
1444 AV_DESC("MsvAvNbComputerName");
1445 break;
1446 case MsvAvNbDomainName:
1447 AV_DESC("MsvAvNbDomainName");
1448 break;
1449 case MsvAvDnsComputerName:
1450 AV_DESC("MsvAvDnsComputerName");
1451 break;
1452 case MsvAvDnsDomainName:
1453 AV_DESC("MsvAvDnsDomainName");
1454 break;
1455 case MsvAvDnsTreeName:
1456 AV_DESC("MsvAvDnsTreeName");
1457 break;
1458 case MsvAvFlags:
1460 guint32 flags;
1462 /* to meet sparc's alignment requirement */
1463 memcpy(&flags, av_value, sizeof(guint32));
1464 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1466 break;
1467 case MsvAvTimestamp:
1469 char *tmp;
1470 guint64 time_val;
1471 time_t time_t_val;
1473 /* to meet sparc's alignment requirement */
1474 memcpy(&time_val, av_value, sizeof(time_val));
1475 time_t_val = TIME_VAL_TO_T(time_val);
1477 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1478 asctime(gmtime(&time_t_val)));
1479 g_free(tmp);
1481 break;
1482 case MsAvRestrictions:
1483 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1484 break;
1485 case MsvAvTargetName:
1486 AV_DESC("MsvAvTargetName");
1487 break;
1488 case MsvChannelBindings:
1489 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1490 break;
1492 ALIGN_AV_LOOP_END;
1495 static gchar *
1496 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1498 GString* str = g_string_new(NULL);
1499 char *tmp;
1500 gsize value_len;
1501 guint8 *value;
1503 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1504 g_free(tmp);
1506 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1507 g_free(tmp);
1509 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1510 g_free(tmp);
1512 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1513 g_free(tmp);
1515 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1516 g_free(tmp);
1518 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1519 g_free(tmp);
1521 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1522 g_free(tmp);
1524 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1525 g_string_append(str, tmp);
1526 g_free(tmp);
1528 /* mic */
1529 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1530 //g_free(tmp);
1532 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1533 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1534 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1535 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1536 g_free(tmp);
1539 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1540 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1541 int nt_resp_len = nt_resp_len_full;
1543 value_len = nt_resp_len_full;
1544 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1545 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1546 g_free(tmp);
1548 if (nt_resp_len > 24) { /* NTLMv2 */
1549 nt_resp_len = 16;
1552 value_len = nt_resp_len;
1553 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1554 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1555 g_free(tmp);
1557 if (nt_resp_len_full > 24) { /* NTLMv2 */
1558 /* Work around Debian/x86_64 compiler bug */
1559 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1560 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1561 const guint8 *temp = (guint8 *)cmsg + offset;
1562 const guint response_version = temp[0];
1563 const guint hi_response_version = temp[1];
1564 const guint8 *client_challenge = temp + 16;
1565 const guint8 *target_info = temp + 28;
1566 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1567 guint64 time_val;
1568 time_t time_t_val;
1569 char *tmp;
1571 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1572 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1573 g_free(tmp);
1575 /* This is not int64 aligned on sparc */
1576 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1577 time_t_val = TIME_VAL_TO_T(time_val);
1579 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1580 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1582 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1583 asctime(gmtime(&time_t_val)));
1584 g_free(tmp);
1586 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1587 g_free(tmp);
1589 describe_av_pairs(str, target_info);
1591 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1595 if (cmsg->domain.len && cmsg->domain.offset) {
1596 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1597 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1598 g_free(domain);
1601 if (cmsg->user.len && cmsg->user.offset) {
1602 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1603 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1604 g_free(user);
1607 if (cmsg->host.len && cmsg->host.offset) {
1608 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1609 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1610 g_free(host);
1613 if (cmsg->session_key.len && cmsg->session_key.offset) {
1614 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1615 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1616 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1617 g_free(tmp);
1620 return g_string_free(str, FALSE);
1623 static gchar *
1624 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1626 GString* str = g_string_new(NULL);
1627 char *tmp;
1629 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1630 g_free(tmp);
1632 /* nonce (server_challenge) */
1633 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1634 g_free(tmp);
1636 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1637 g_free(tmp);
1639 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1640 g_free(tmp);
1642 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1643 g_free(tmp);
1645 if (cmsg->target_name.len && cmsg->target_name.offset) {
1646 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1647 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1648 g_free(target_name);
1651 if (cmsg->target_info.len && cmsg->target_info.offset) {
1652 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1653 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1655 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1656 g_free(tmp);
1658 describe_av_pairs(str, target_info);
1661 return g_string_free(str, FALSE);
1664 static void
1665 sip_sec_ntlm_message_describe(SipSecBuffer *buff,
1666 const gchar *type)
1668 struct ntlm_message *msg;
1669 gchar *res = NULL;
1671 if (buff->length == 0 || buff->value == NULL || buff->length < 12) return;
1673 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1674 msg = (void *)buff->value;
1675 if(!sipe_strequal("NTLMSSP", (char*)msg)) return;
1677 switch (GUINT32_FROM_LE(msg->type)) {
1678 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1679 break;
1680 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1681 break;
1682 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1683 break;
1686 SIPE_DEBUG_INFO("sip_sec_ntlm_message_describe: %s message is:\n%s",
1687 type, res);
1688 g_free(res);
1691 /* Analyzer only needs the _describe() functions */
1692 #ifndef _SIPE_COMPILING_ANALYZER
1694 /* sip-sec-mech.h API implementation for NTLM */
1696 /* Security context for NTLM */
1697 typedef struct _context_ntlm {
1698 struct sip_sec_context common;
1699 gchar *domain;
1700 gchar *username;
1701 const gchar *password;
1702 guchar *client_sign_key;
1703 guchar *server_sign_key;
1704 guchar *client_seal_key;
1705 guchar *server_seal_key;
1706 guint32 flags;
1707 } *context_ntlm;
1709 #define SIP_SEC_FLAG_NTLM_INITIAL 0x00010000
1712 static gboolean
1713 sip_sec_acquire_cred__ntlm(SipSecContext context,
1714 const gchar *username,
1715 const gchar *password)
1717 context_ntlm ctx = (context_ntlm)context;
1720 * Our NTLM implementation does not support Single Sign-On.
1721 * Thus username & password are required.
1723 if (is_empty(username) || is_empty(password)) {
1724 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_acquire_cred__ntlm: no valid authentication information provided");
1725 return FALSE;
1728 /* this is the first time we are allowed to set private flags */
1729 context->flags |= SIP_SEC_FLAG_NTLM_INITIAL;
1731 if (SIP_SEC_USERNAME_IS_ENTERPRISE) {
1732 /* use username as-is, just replace enterprise marker with @ */
1733 ctx->username = sipe_utils_str_replace(username,
1734 SIP_SEC_USERNAME_ENTERPRISE_STRING,
1735 "@");
1736 } else {
1737 SIP_SEC_USERNAME_SPLIT_START;
1738 if (SIP_SEC_USERNAME_HAS_DOMAIN) {
1739 ctx->domain = g_strdup(SIP_SEC_USERNAME_DOMAIN);
1740 ctx->username = g_strdup(SIP_SEC_USERNAME_ACCOUNT);
1741 } else {
1742 ctx->username = g_strdup(username);
1744 SIP_SEC_USERNAME_SPLIT_END;
1747 ctx->password = password;
1749 return TRUE;
1752 static gboolean
1753 sip_sec_init_sec_context__ntlm(SipSecContext context,
1754 SipSecBuffer in_buff,
1755 SipSecBuffer *out_buff,
1756 SIPE_UNUSED_PARAMETER const gchar *service_name)
1758 context_ntlm ctx = (context_ntlm) context;
1760 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
1763 * If authentication was already completed, then this mean a new
1764 * authentication handshake has started on the existing connection.
1765 * We must throw away the old context, because we need a new one.
1767 if (context->flags & SIP_SEC_FLAG_COMMON_READY) {
1768 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: dropping old context");
1769 context->flags &= ~SIP_SEC_FLAG_COMMON_READY;
1770 context->flags |= SIP_SEC_FLAG_NTLM_INITIAL;
1773 if (context->flags & SIP_SEC_FLAG_NTLM_INITIAL) {
1774 context->flags &= ~SIP_SEC_FLAG_NTLM_INITIAL;
1776 /* HTTP */
1777 if (context->flags & SIP_SEC_FLAG_COMMON_HTTP) {
1778 sip_sec_ntlm_gen_negotiate(out_buff);
1779 sip_sec_ntlm_message_describe(out_buff, "Negotiate");
1780 /* SIP */
1781 } else {
1782 /* empty initial message for connection-less NTLM */
1783 out_buff->length = 0;
1784 out_buff->value = (guint8 *) g_strdup("");
1786 } else {
1787 gboolean res;
1788 guchar *client_sign_key = NULL;
1789 guchar *server_sign_key = NULL;
1790 guchar *client_seal_key = NULL;
1791 guchar *server_seal_key = NULL;
1792 guchar *server_challenge = NULL;
1793 guint64 time_val = 0;
1794 guchar *target_info = NULL;
1795 int target_info_len = 0;
1796 guint32 flags;
1797 gchar *tmp;
1799 if (!in_buff.value || !in_buff.length) {
1800 return FALSE;
1803 sip_sec_ntlm_message_describe(&in_buff, "Challenge");
1805 sip_sec_ntlm_parse_challenge(in_buff,
1806 &flags,
1807 &server_challenge, /* 8 bytes */
1808 &time_val,
1809 &target_info,
1810 &target_info_len);
1812 res = sip_sec_ntlm_gen_authenticate(
1813 &client_sign_key,
1814 &server_sign_key,
1815 &client_seal_key,
1816 &server_seal_key,
1817 ctx->username,
1818 ctx->password,
1819 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1820 ctx->domain ? ctx->domain : "",
1821 server_challenge,
1822 time_val,
1823 target_info,
1824 target_info_len,
1825 context->flags & SIP_SEC_FLAG_COMMON_HTTP,
1826 out_buff,
1827 &flags);
1828 g_free(server_challenge);
1829 g_free(target_info);
1830 g_free(tmp);
1832 if (!res) {
1833 g_free(client_sign_key);
1834 g_free(server_sign_key);
1835 g_free(client_seal_key);
1836 g_free(server_seal_key);
1837 return res;
1840 sip_sec_ntlm_message_describe(out_buff, "Authenticate");
1842 g_free(ctx->client_sign_key);
1843 ctx->client_sign_key = client_sign_key;
1845 g_free(ctx->server_sign_key);
1846 ctx->server_sign_key = server_sign_key;
1848 g_free(ctx->client_seal_key);
1849 ctx->client_seal_key = client_seal_key;
1851 g_free(ctx->server_seal_key);
1852 ctx->server_seal_key = server_seal_key;
1854 ctx->flags = flags;
1856 /* Authentication is completed */
1857 context->flags |= SIP_SEC_FLAG_COMMON_READY;
1860 return TRUE;
1864 * @param message a NULL terminated string to sign
1867 static gboolean
1868 sip_sec_make_signature__ntlm(SipSecContext context,
1869 const gchar *message,
1870 SipSecBuffer *signature)
1872 signature->length = 16;
1873 signature->value = g_malloc0(16);
1875 /* FIXME? We always use a random_pad of 0 */
1876 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1877 message,
1879 ((context_ntlm) context)->client_sign_key,
1880 ((context_ntlm) context)->client_seal_key,
1881 /* SipSecBuffer.value is g_malloc()'d:
1882 * use (void *) to remove guint8 alignment
1884 (void *)signature->value);
1885 return TRUE;
1889 * @param message a NULL terminated string to check signature of
1890 * @return TRUE on success
1892 static gboolean
1893 sip_sec_verify_signature__ntlm(SipSecContext context,
1894 const gchar *message,
1895 SipSecBuffer signature)
1897 context_ntlm ctx = (context_ntlm) context;
1898 guint32 mac[4];
1899 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1900 guint32 random_pad = GUINT32_FROM_LE(((guint32 *)((void *)signature.value))[1]);
1902 sip_sec_ntlm_sipe_signature_make(ctx->flags,
1903 message,
1904 random_pad,
1905 ctx->server_sign_key,
1906 ctx->server_seal_key,
1907 mac);
1908 return(memcmp(signature.value, mac, 16) == 0);
1911 static void
1912 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1914 context_ntlm ctx = (context_ntlm) context;
1916 g_free(ctx->client_sign_key);
1917 g_free(ctx->server_sign_key);
1918 g_free(ctx->client_seal_key);
1919 g_free(ctx->server_seal_key);
1920 g_free(ctx->domain);
1921 g_free(ctx->username);
1922 g_free(ctx);
1925 static const gchar *
1926 sip_sec_context_name__ntlm(SIPE_UNUSED_PARAMETER SipSecContext context)
1928 return("NTLM");
1931 SipSecContext
1932 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER guint type)
1934 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1935 if (!context) return(NULL);
1937 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1938 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1939 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1940 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1941 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1942 context->common.context_name_func = sip_sec_context_name__ntlm;
1944 return((SipSecContext) context);
1947 gboolean sip_sec_password__ntlm(void)
1949 return(TRUE);
1952 #endif /* !_SIPE_COMPILING_ANALYZER */
1954 void sip_sec_init__ntlm(void)
1956 #ifdef HAVE_LANGINFO_CODESET
1957 const char *sys_cp = nl_langinfo(CODESET);
1958 #else
1959 const char *sys_cp = SIPE_DEFAULT_CODESET;
1960 #endif /* HAVE_LANGINFO_CODESET */
1962 /* fall back to utf-8 */
1963 if (!sys_cp) sys_cp = "UTF-8";
1965 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1966 if (convert_from_utf16le == (GIConv)-1) {
1967 SIPE_DEBUG_ERROR("g_iconv_open from UTF-16LE to %s failed",
1968 sys_cp);
1971 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1972 if (convert_to_utf16le == (GIConv)-1) {
1973 SIPE_DEBUG_ERROR("g_iconv_open from %s to UTF-16LE failed",
1974 sys_cp);
1978 void sip_sec_destroy__ntlm(void)
1980 g_iconv_close(convert_to_utf16le);
1981 g_iconv_close(convert_from_utf16le);
1985 Local Variables:
1986 mode: c
1987 c-file-style: "bsd"
1988 indent-tabs-mode: t
1989 tab-width: 8
1990 End: