core cleanup: debug replacement
[siplcs.git] / src / core / sip-sec-ntlm.c
blobed2ba4f67d68c6ff1b5c73774cf785bab81ba98a
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2009, 2010 pier11 <pier11@operamail.com>
7 * Copyright (C) 2008 Novell, Inc.
8 * Modify 2007, Anibal Avelar <avelar@gmail.com>
9 * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
11 * Implemented with reference to the follow documentation:
12 * - http://davenport.sourceforge.net/ntlm.html
13 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
14 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * Byte order policy:
34 * - NTLM messages (byte streams) should be in LE (Little-Endian) byte order.
35 * - internal int16, int32, int64 should contain proper values.
36 * For example: 01 00 00 00 LE should be translated to (int32)1
37 * - When reading/writing from/to NTLM message appropriate conversion should
38 * be taken to properly present integer values. glib's "Byte Order Macros"
39 * should be used for that, for example GUINT32_FROM_LE
41 * NOTE: The Byte Order Macros can have side effects!
42 * Do *NOT* make any calculations inside the macros!
44 * - All calculations should be made in dedicated local variables (system-endian),
45 * not in NTLM (LE) structures.
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
52 #include <glib.h>
54 #ifdef HAVE_LANGINFO_CODESET
55 #include <langinfo.h>
56 #endif /* HAVE_LANGINFO_CODESET */
58 #include "cipher.h"
60 #include "sipe-common.h"
61 #include "sip-sec.h"
62 #include "sip-sec-mech.h"
63 #include "sip-sec-ntlm.h"
64 #include "sipe-backend.h"
65 #include "sipe-utils.h"
67 /* [MS-NLMP] */
68 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
69 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
70 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
71 #define r9 0x00000008 /* r9 */
72 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
73 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
74 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
75 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
76 #define r8 0x00000100 /* r8 */
77 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
78 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
79 #define anonymous 0x00000800 /* J */
80 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
81 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
82 #define r7 0x00004000 /* r7 */
83 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
84 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
85 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
86 #define r6 0x00040000 /* r6 */
87 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
88 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
89 #define r5 0x00200000 /* r5 */
90 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
91 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
92 #define r4 0x01000000 /* r4 */
93 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
94 #define r3 0x04000000 /* r3 */
95 #define r2 0x08000000 /* r2 */
96 #define r1 0x10000000 /* r1 */
97 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
98 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
99 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
101 /* AvId */
102 #define MsvAvEOL 0
103 #define MsvAvNbComputerName 1
104 #define MsvAvNbDomainName 2
105 #define MsvAvDnsComputerName 3
106 #define MsvAvDnsDomainName 4
107 /** @since Windows XP */
108 #define MsvAvDnsTreeName 5
109 /** @since Windows XP */
110 #define MsvAvFlags 6
111 /** @since Windows Vista */
112 #define MsvAvTimestamp 7
113 /** @since Windows Vista */
114 #define MsAvRestrictions 8
115 /** @since Windows 7 */
116 #define MsvAvTargetName 9
117 /** @since Windows 7 */
118 #define MsvChannelBindings 10
120 /* time_t <-> (guint64) time_val conversion */
121 #define TIME_VAL_FACTOR 10000000
122 #define TIME_VAL_OFFSET 116444736000000000LL
123 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
124 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
126 /* 8 bytes */
127 /* LE (Little Endian) byte order */
128 struct version {
129 guint8 product_major_version;
130 guint8 product_minor_version;
131 guint16 product_build;
132 guint8 zero2[3];
133 guint8 ntlm_revision_current;
137 * NTLMv1 is no longer used except in tests. R.I.P.
139 * It remains in this file only for documentary purposes
141 #ifdef _SIPE_COMPILING_TESTS
142 static gboolean use_ntlm_v2 = FALSE;
144 guint64 test_time_val = 0; /* actual time in implementation */
145 guchar test_client_challenge [8]; /* random in implementation */
146 guchar test_random_session_key[16]; /* random in implementation */
147 struct version test_version; /* hard-coded in implementation */
148 #endif
150 /* Minimum set of common features we need to work. */
151 /* we operate in NTLMv2 mode */
152 #define NEGOTIATE_FLAGS_COMMON_MIN \
153 ( NTLMSSP_NEGOTIATE_UNICODE | \
154 NTLMSSP_NEGOTIATE_NTLM | \
155 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
156 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
157 NTLMSSP_NEGOTIATE_TARGET_INFO \
160 /* Negotiate flags for connection-based mode. Nice to have but optional. */
161 #define NEGOTIATE_FLAGS_CONN \
162 ( NEGOTIATE_FLAGS_COMMON_MIN | \
163 NTLMSSP_NEGOTIATE_VERSION | \
164 NTLMSSP_NEGOTIATE_128 | \
165 NTLMSSP_NEGOTIATE_56 | \
166 NTLMSSP_REQUEST_TARGET \
169 /* Extra negotiate flags required in connectionless NTLM */
170 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
171 ( NTLMSSP_NEGOTIATE_SIGN | \
172 NTLMSSP_NEGOTIATE_DATAGRAM | \
173 NTLMSSP_NEGOTIATE_IDENTIFY | \
174 NTLMSSP_NEGOTIATE_KEY_EXCH \
177 /* Negotiate flags required in connectionless NTLM */
178 #define NEGOTIATE_FLAGS_CONNLESS \
179 ( NEGOTIATE_FLAGS_CONN | \
180 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
183 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
184 #define NTLMSSP_LM_RESP_LEN 24
185 #define NTLMSSP_SESSION_KEY_LEN 16
186 #define MD4_DIGEST_LEN 16
187 #define MD5_DIGEST_LEN 16
189 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
191 /* 4 bytes */
192 /* LE (Little Endian) byte order */
193 struct av_pair {
194 guint16 av_id;
195 guint16 av_len;
196 /* value */
199 /* to meet sparc's alignment requirement */
200 #define ALIGN_AV \
201 memcpy(&av_aligned, av, sizeof(av_aligned)); \
202 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
203 av_len = GUINT16_FROM_LE(av_aligned.av_len)
204 #define ALIGN_AV_LOOP_START \
205 struct av_pair av_aligned; \
206 guint16 av_id; \
207 guint16 av_len; \
208 ALIGN_AV; \
209 while (av_id != MsvAvEOL) { \
210 gchar *av_value = ((gchar *)av) + \
211 sizeof(struct av_pair); \
212 switch (av_id)
213 #define ALIGN_AV_LOOP_END \
214 av = av_value + av_len; \
215 ALIGN_AV; \
218 /* 8 bytes */
219 /* LE (Little Endian) byte order */
220 struct smb_header {
221 guint16 len;
222 guint16 maxlen;
223 guint32 offset;
226 /* LE (Little Endian) byte order */
227 struct ntlm_message {
228 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
229 guint32 type; /* 0x00000003 */
232 /* LE (Little Endian) byte order */
233 struct negotiate_message {
234 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
235 guint32 type; /* 0x00000001 */
236 guint32 flags; /* 0xb203 */
237 struct smb_header domain;
238 struct smb_header host;
239 struct version ver;
240 /* payload
241 * - DomainName (always ASCII)
242 * - WorkstationName (always ASCII)
246 /* LE (Little Endian) byte order */
247 struct challenge_message {
248 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
249 guint32 type; /* 0x00000002 */
250 struct smb_header target_name;
251 guint32 flags; /* 0x8201 */
252 guint8 nonce[8];
253 guint8 zero1[8];
254 struct smb_header target_info;
255 struct version ver;
256 /* payload
257 * - TargetName (negotiated encoding)
258 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
262 /* LE (Little Endian) byte order */
263 struct authenticate_message {
264 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
265 guint32 type; /* 0x00000003 */
266 /** LmChallengeResponseFields */
267 struct smb_header lm_resp;
268 /** NtChallengeResponseFields */
269 struct smb_header nt_resp;
270 /** DomainNameFields */
271 struct smb_header domain;
272 /** UserNameFields */
273 struct smb_header user;
274 /** WorkstationFields */
275 struct smb_header host;
276 /** EncryptedRandomSessionKeyFields */
277 struct smb_header session_key;
278 guint32 flags;
279 struct version ver;
280 //guint8 mic[16];
281 /* payload
282 * - LmChallengeResponse
283 * - NtChallengeResponse
284 * - DomainName (negotiated encoding)
285 * - UserName (negotiated encoding)
286 * - Workstation (negotiated encoding)
287 * - EncryptedRandomSessionKey
291 #ifndef HAVE_LANGINFO_CODESET
292 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
293 #endif
295 /* Private Methods */
297 /* Utility Functions */
298 static GIConv convert_from_utf16le = (GIConv)-1;
299 static GIConv convert_to_utf16le = (GIConv)-1;
301 static gsize
302 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
304 gsize inbytes = strlen(source);
305 gsize outbytes = remlen;
306 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
307 return(remlen - outbytes);
310 /* UTF-16LE to native encoding
311 * Must be g_free'd after use */
312 static gchar *
313 unicode_strconvcopy_back(const gchar *source, gsize len)
315 gsize outbytes = 2 * len;
316 gchar *dest = g_new0(gchar, outbytes + 1);
317 gchar *outbuf = dest;
318 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
319 return dest;
322 /* crc32 source copy from gg's common.c */
323 static guint32 crc32_table[256];
324 static int crc32_initialized = 0;
326 static void crc32_make_table()
328 guint32 h = 1;
329 unsigned int i, j;
331 memset(crc32_table, 0, sizeof(crc32_table));
333 for (i = 128; i; i >>= 1) {
334 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
336 for (j = 0; j < 256; j += 2 * i)
337 crc32_table[i + j] = crc32_table[j] ^ h;
340 crc32_initialized = 1;
343 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
345 if (!crc32_initialized)
346 crc32_make_table();
348 if (!buf || len < 0)
349 return crc;
351 crc ^= 0xffffffffL;
353 while (len--)
354 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
356 return crc ^ 0xffffffffL;
359 static guint32
360 CRC32 (const char *msg, int len)
362 guint32 crc = 0L;
363 crc = crc32(crc, (guint8 *) msg, len);
364 return crc;
367 /* Cyphers */
369 #ifdef _SIPE_COMPILING_TESTS
370 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
372 key[0] = key_56[0];
373 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
374 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
375 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
376 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
377 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
378 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
379 key[7] = (key_56[6] << 1) & 0xFF;
382 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
384 PurpleCipherContext *context;
385 size_t outlen;
387 context = purple_cipher_context_new_by_name("des", NULL);
388 purple_cipher_context_set_key(context, (guchar*)key);
389 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
390 purple_cipher_context_destroy(context);
393 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
394 static void
395 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
397 unsigned char key[8];
398 setup_des_key(k, key);
399 des_ecb_encrypt(d, results, key);
402 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
403 static void
404 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
406 unsigned char keys[21];
408 /* Copy the first 16 bytes */
409 memcpy(keys, k, 16);
411 /* Zero out the last 5 bytes of the key */
412 memset(keys + 16, 0, 5);
414 DES(keys, d, results);
415 DES(keys + 7, d, results + 8);
416 DES(keys + 14, d, results + 16);
418 #endif
420 static void
421 RC4K (const unsigned char * k, unsigned long key_len, const unsigned char * d, int len, unsigned char * result)
423 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
424 purple_cipher_context_set_option(context, "key_len", (gpointer)key_len);
425 purple_cipher_context_set_key(context, k);
426 purple_cipher_context_encrypt(context, (const guchar *)d, len, result, NULL);
427 purple_cipher_context_destroy(context);
430 /* out 16 bytes */
431 static void
432 MD4 (const unsigned char * d, int len, unsigned char * result)
434 PurpleCipherContext * context = purple_cipher_context_new_by_name("md4", NULL);
435 purple_cipher_context_append(context, (guchar*)d, len);
436 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
437 purple_cipher_context_destroy(context);
440 /* out 16 bytes */
441 static void
442 MD5 (const unsigned char * d, int len, unsigned char * result)
444 PurpleCipherContext * context = purple_cipher_context_new_by_name("md5", NULL);
445 purple_cipher_context_append(context, (guchar*)d, len);
446 purple_cipher_context_digest(context, MD5_DIGEST_LEN, (guchar*)result, NULL);
447 purple_cipher_context_destroy(context);
450 /* out 16 bytes */
452 static void
453 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
455 int i;
456 unsigned char ibuff[64 + data_len];
457 unsigned char obuff[64 + 16];
459 if (key_len > 64)
460 key_len = 64;
462 for (i = 0; i < key_len; i++) {
463 ibuff[i] = key[i] ^ 0x36;
464 obuff[i] = key[i] ^ 0x5c;
466 for (i = key_len; i < 64; i++) {
467 ibuff[i] = 0x36;
468 obuff[i] = 0x5c;
471 memcpy(ibuff+64, data, data_len);
473 MD5 (ibuff, 64 + data_len, obuff+64);
474 MD5 (obuff, 64 + 16, result);
476 #define HMAC_MD5 HMACT64
479 /* out 16 bytes */
480 static void
481 HMAC_MD5 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
483 PurpleCipherContext *context = purple_cipher_context_new_by_name("hmac", NULL);
485 purple_cipher_context_set_option(context, "hash", "md5");
486 purple_cipher_context_set_key_with_len(context, (guchar *)key, (key_len));
488 purple_cipher_context_append(context, (guchar *)data, data_len);
489 purple_cipher_context_digest(context, 16, (guchar*)result, NULL);
490 purple_cipher_context_destroy(context);
493 /* NTLM Core Methods */
495 static void
496 NONCE(unsigned char *buffer, int num)
498 int i;
499 for (i = 0; i < num; i++) {
500 buffer[i] = (rand() & 0xff);
504 #ifdef _SIPE_COMPILING_TESTS
505 static void
506 Z(unsigned char *buffer, int num)
508 memset(buffer, 0, num);
511 static void
512 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
514 /* "KGS!@#$%" */
515 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
516 unsigned char uppercase_password[14];
517 int i;
519 int len = strlen(password);
520 if (len > 14) {
521 len = 14;
524 // Uppercase password
525 for (i = 0; i < len; i++) {
526 uppercase_password[i] = g_ascii_toupper(password[i]);
529 // Zero the rest
530 for (; i < 14; i++) {
531 uppercase_password[i] = 0;
534 DES (uppercase_password, magic, result);
535 DES (uppercase_password + 7, magic, result + 8);
537 #endif
540 Define NTOWFv1(Passwd, User, UserDom) as
541 MD4(UNICODE(Passwd))
542 EndDefine
544 /* out 16 bytes */
545 static void
546 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
548 int len_u = 2 * strlen(password); // utf16 should not be more
549 unsigned char unicode_password[len_u];
551 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
552 MD4 (unicode_password, len_u, result);
556 Define NTOWFv2(Passwd, User, UserDom) as
557 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
558 EndDefine
560 /* out 16 bytes */
561 void
562 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
564 unsigned char response_key_nt_v1 [16];
565 int len_user = user ? strlen(user) : 0;
566 int len_domain = domain ? strlen(domain) : 0;
567 unsigned char user_upper[len_user + 1];
568 int len_user_u = 2 * len_user; // utf16 should not be more
569 int len_domain_u = 2 * len_domain; // utf16 should not be more
570 unsigned char buff[(len_user + len_domain)*2];
571 int i;
573 /* Uppercase user */
574 for (i = 0; i < len_user; i++) {
575 user_upper[i] = g_ascii_toupper(user[i]);
577 user_upper[len_user] = 0;
579 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
580 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
582 NTOWFv1(password, user, domain, response_key_nt_v1);
584 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
587 static void
588 compute_response(const guint32 neg_flags,
589 const unsigned char *response_key_nt,
590 const unsigned char *response_key_lm,
591 const guint8 *server_challenge,
592 const guint8 *client_challenge,
593 const guint64 time_val,
594 const guint8 *target_info,
595 int target_info_len,
596 unsigned char *lm_challenge_response,
597 unsigned char *nt_challenge_response,
598 unsigned char *session_base_key)
600 #ifdef _SIPE_COMPILING_TESTS
601 if (use_ntlm_v2)
603 #endif
605 Responserversion - The 1-byte response version. Currently set to 1.
606 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
607 Time - The 8-byte little-endian time in GMT.
608 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
609 ClientChallenge - The 8-byte challenge message generated by the client.
610 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
612 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
613 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
614 Time, //8bytes - 8
615 ClientChallenge, //8bytes - 16
616 Z(4), //4bytes - 24
617 ServerName, //variable - 28
618 Z(4)) //4bytes - 28+target_info_len
619 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
620 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
621 Set LmChallengeResponse to ConcatenationOf(
622 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
623 ClientChallenge )
624 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
625 EndDefine
627 guint8 tmp [16];
628 guint8 nt_proof_str [16];
630 /* client_challenge (8) & temp (temp_len) buff */
631 int temp_len = 8+8+8+4+target_info_len+4;
632 guint8 temp2 [8 + temp_len];
633 memset(temp2, 0, 8 + temp_len); /* init to 0 */
634 temp2[8+0] = 1;
635 temp2[8+1] = 1;
636 *((guint64 *)(temp2+8+8)) = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
637 memcpy(temp2+8+16, client_challenge, 8);
638 memcpy(temp2+8+28, target_info, target_info_len);
640 /* NTProofStr */
641 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
642 memcpy(temp2, server_challenge, 8);
643 HMAC_MD5(response_key_nt, 16, temp2, 8+temp_len, nt_proof_str);
645 /* NtChallengeResponse */
646 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
647 memcpy(nt_challenge_response, nt_proof_str, 16);
648 memcpy(nt_challenge_response+16, temp2+8, temp_len);
650 /* SessionBaseKey */
651 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
652 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
654 /* lm_challenge_response */
655 memcpy(tmp, server_challenge, 8);
656 memcpy(tmp+8, client_challenge, 8);
657 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
658 memcpy(lm_challenge_response+16, client_challenge, 8);
660 #ifndef _SIPE_COMPILING_TESTS
661 /* Not used in NTLMv2 */
662 (void)neg_flags;
663 #else
665 else
667 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
668 // @TODO do not even reference nt_challenge_response
669 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
670 DESL (response_key_lm, server_challenge, lm_challenge_response);
671 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
672 unsigned char prehash [16];
673 unsigned char hash [16];
675 /* nt_challenge_response */
676 memcpy(prehash, server_challenge, 8);
677 memcpy(prehash + 8, client_challenge, 8);
678 MD5 (prehash, 16, hash);
679 DESL (response_key_nt, hash, nt_challenge_response);
681 /* lm_challenge_response */
682 memcpy(lm_challenge_response, client_challenge, 8);
683 Z (lm_challenge_response+8, 16);
684 } else {
685 DESL (response_key_nt, server_challenge, nt_challenge_response);
686 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
687 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
688 } else {
689 DESL (response_key_lm, server_challenge, lm_challenge_response);
693 /* Session Key */
694 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
696 #endif
699 static void
700 KXKEY ( guint32 flags,
701 const unsigned char * session_base_key,
702 const unsigned char * lm_challenge_resonse,
703 const guint8 * server_challenge, /* 8-bytes, nonce */
704 unsigned char * key_exchange_key)
706 #ifdef _SIPE_COMPILING_TESTS
707 if (use_ntlm_v2)
709 #else
710 /* Not used in NTLMv2 */
711 (void)flags;
712 (void)lm_challenge_resonse;
713 (void)server_challenge;
714 #endif
715 memcpy(key_exchange_key, session_base_key, 16);
716 #ifdef _SIPE_COMPILING_TESTS
718 else
720 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
721 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
722 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
723 EndDefine
725 guint8 tmp[16];
726 memcpy(tmp, server_challenge, 8);
727 memcpy(tmp+8, lm_challenge_resonse, 8);
728 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
729 } else {
730 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
731 memcpy(key_exchange_key, session_base_key, 16);
734 #endif
738 If (Mode equals "Client")
739 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
740 "session key to client-to-server signing key magic constant"))
741 Else
742 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
743 "session key to server-to-client signing key magic constant"))
744 Endif
746 static void
747 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
749 char * magic = client
750 ? "session key to client-to-server signing key magic constant"
751 : "session key to server-to-client signing key magic constant";
753 int len = strlen(magic) + 1;
754 unsigned char md5_input [16 + len];
755 memcpy(md5_input, random_session_key, 16);
756 memcpy(md5_input + 16, magic, len);
758 MD5 (md5_input, len + 16, result);
762 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
763 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
764 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
765 Set SealKey to RandomSessionKey
766 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
767 Set SealKey to RandomSessionKey[0..6]
768 Else
769 Set SealKey to RandomSessionKey[0..4]
770 Endif
772 If (Mode equals "Client")
773 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
774 Else
775 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
776 Endif
778 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
779 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
780 Else
781 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
782 Endif
783 EndDefine
785 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
786 static void
787 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
789 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
791 char * magic = client
792 ? "session key to client-to-server sealing key magic constant"
793 : "session key to server-to-client sealing key magic constant";
795 int len = strlen(magic) + 1;
796 unsigned char md5_input [16 + len];
797 int key_len;
799 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
800 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
801 key_len = 16;
802 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
803 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
804 key_len = 7;
805 } else {
806 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
807 key_len = 5;
810 memcpy(md5_input, random_session_key, key_len);
811 memcpy(md5_input + key_len, magic, len);
813 MD5 (md5_input, key_len + len, result);
815 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
817 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
818 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
819 memcpy(result, random_session_key, 7);
820 result[7] = 0xA0;
821 } else {
822 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
823 memcpy(result, random_session_key, 5);
824 result[5] = 0xE5;
825 result[6] = 0x38;
826 result[7] = 0xB0;
829 else
831 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
832 memcpy(result, random_session_key, 16);
837 = for Extended Session Security =
838 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
839 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
840 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
842 = if Extended Session Security is NOT negotiated =
843 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
844 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
845 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
846 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
848 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
850 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
851 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
853 /** MAC(Handle, SigningKey, SeqNum, Message) */
854 /* out 16 bytes */
855 static void
856 MAC (guint32 flags,
857 const char *buf,
858 int buf_len,
859 unsigned char *sign_key,
860 unsigned long sign_key_len,
861 unsigned char *seal_key,
862 unsigned long seal_key_len,
863 guint32 random_pad,
864 guint32 sequence,
865 unsigned char *result)
867 guint32 *res_ptr;
869 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
871 Define MAC(Handle, SigningKey, SeqNum, Message) as
872 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
873 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
874 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
875 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
876 Set SeqNum to SeqNum + 1
877 EndDefine
879 /* If a key exchange key is negotiated
880 Define MAC(Handle, SigningKey, SeqNum, Message) as
881 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
882 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
883 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
884 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
885 Set SeqNum to SeqNum + 1
886 EndDefine
889 unsigned char seal_key_ [16];
890 guchar hmac[16];
891 guchar tmp[4 + buf_len];
893 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
894 RC4Init(Handle, SealingKey')
896 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
897 unsigned char tmp2 [16+4];
899 memcpy(tmp2, seal_key, seal_key_len);
900 *((guint32 *)(tmp2+16)) = GUINT32_TO_LE(sequence);
901 MD5 (tmp2, 16+4, seal_key_);
902 } else {
903 memcpy(seal_key_, seal_key, seal_key_len);
906 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extented Session Security");
908 res_ptr = (guint32 *)result;
909 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
910 res_ptr[3] = GUINT32_TO_LE(sequence);
912 res_ptr = (guint32 *)tmp;
913 res_ptr[0] = GUINT32_TO_LE(sequence);
914 memcpy(tmp+4, buf, buf_len);
916 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
918 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
919 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
920 RC4K(seal_key_, seal_key_len, hmac, 8, result+4);
921 } else {
922 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
923 memcpy(result+4, hmac, 8);
925 } else {
926 /* The content of the first 4 bytes is irrelevant */
927 guint32 crc = CRC32(buf, strlen(buf));
928 guint32 plaintext [] = {
929 GUINT32_TO_LE(0),
930 GUINT32_TO_LE(crc),
931 GUINT32_TO_LE(sequence)
932 }; // 4, 4, 4 bytes
934 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extented Session Security");
936 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, result+4);
938 res_ptr = (guint32 *)result;
939 // Highest four bytes are the Version
940 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
942 // Replace the first four bytes of the ciphertext with the random_pad
943 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
947 /* End Core NTLM Methods */
950 * @param flags (out) flags received from server
951 * @param server_challenge must be g_free()'d after use if requested
952 * @param target_info must be g_free()'d after use if requested
954 static void
955 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
956 guint32 *flags,
957 guchar **server_challenge, /* 8 bytes */
958 guint64 *time_val,
959 guchar **target_info,
960 int *target_info_len)
962 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
963 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
965 /* server challenge (nonce) */
966 if (server_challenge) {
967 *server_challenge = g_memdup(cmsg->nonce, 8);
970 /* flags */
971 if (flags) {
972 *flags = host_flags;
975 /* target_info */
976 if (cmsg->target_info.len && cmsg->target_info.offset) {
977 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
978 void *av = content;
979 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
981 ALIGN_AV_LOOP_START
983 /* @since Vista */
984 case MsvAvTimestamp:
985 if (time_val) {
986 guint64 tmp;
988 /* to meet sparc's alignment requirement */
989 memcpy(&tmp, av_value, sizeof(tmp));
990 *time_val = GUINT64_FROM_LE(tmp);
992 break;
994 ALIGN_AV_LOOP_END;
996 if (target_info_len) {
997 *target_info_len = len;
999 if (target_info) {
1000 *target_info = g_memdup(content, len);
1006 * @param client_sign_key (out) must be g_free()'d after use
1007 * @param server_sign_key (out) must be g_free()'d after use
1008 * @param client_seal_key (out) must be g_free()'d after use
1009 * @param server_seal_key (out) must be g_free()'d after use
1010 * @param flags (in, out) negotiated flags
1012 static sip_uint32
1013 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
1014 guchar **server_sign_key,
1015 guchar **client_seal_key,
1016 guchar **server_seal_key,
1017 const gchar *user,
1018 const gchar *password,
1019 const gchar *hostname,
1020 const gchar *domain,
1021 const guint8 *server_challenge, /* nonce */
1022 const guint64 time_val,
1023 const guint8 *target_info,
1024 int target_info_len,
1025 gboolean is_connection_based,
1026 SipSecBuffer *out_buff,
1027 guint32 *flags)
1029 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
1030 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1031 int ntlmssp_nt_resp_len =
1032 #ifdef _SIPE_COMPILING_TESTS
1033 use_ntlm_v2 ?
1034 #endif
1035 (16 + (32+target_info_len))
1036 #ifdef _SIPE_COMPILING_TESTS
1037 : NTLMSSP_LM_RESP_LEN
1038 #endif
1040 gsize msglen = sizeof(struct authenticate_message)
1041 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1042 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1043 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1044 struct authenticate_message *tmsg;
1045 char *tmp;
1046 guint32 offset;
1047 guint16 len;
1048 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1049 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1050 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1051 unsigned char nt_challenge_response [ntlmssp_nt_resp_len]; /* variable or 24 */
1052 unsigned char session_base_key [16];
1053 unsigned char key_exchange_key [16];
1054 unsigned char exported_session_key[16];
1055 unsigned char encrypted_random_session_key [16];
1056 unsigned char key [16];
1057 unsigned char client_challenge [8];
1058 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1060 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1061 !(is_connection_based || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)))
1063 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1064 return SIP_SEC_E_INTERNAL_ERROR;
1067 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1068 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1071 tmsg = g_malloc0(msglen);
1073 NONCE (client_challenge, 8);
1075 #ifdef _SIPE_COMPILING_TESTS
1076 memcpy(client_challenge, test_client_challenge, 8);
1077 time_vl = test_time_val ? test_time_val : time_vl;
1079 if (use_ntlm_v2) {
1081 #endif
1082 NTOWFv2 (password, user, domain, response_key_nt);
1083 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1084 #ifdef _SIPE_COMPILING_TESTS
1085 } else {
1086 NTOWFv1 (password, user, domain, response_key_nt);
1087 LMOWFv1 (password, user, domain, response_key_lm);
1089 #endif
1091 compute_response(neg_flags,
1092 response_key_nt,
1093 response_key_lm,
1094 server_challenge,
1095 client_challenge,
1096 time_vl,
1097 target_info,
1098 target_info_len,
1099 lm_challenge_response, /* out */
1100 nt_challenge_response, /* out */
1101 session_base_key); /* out */
1103 /* same as session_base_key for
1104 * - NTLNv1 w/o Ext.Sess.Sec and
1105 * - NTLMv2
1107 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1109 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1110 NONCE (exported_session_key, 16); // random master key
1111 #ifdef _SIPE_COMPILING_TESTS
1112 memcpy(exported_session_key, test_random_session_key, 16);
1113 #endif
1114 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1115 } else {
1116 memcpy(exported_session_key, key_exchange_key, 16);
1119 tmp = buff_to_hex_str(exported_session_key, 16);
1120 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp);
1121 g_free(tmp);
1123 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1124 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1126 /* p.46
1127 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1128 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1130 SIGNKEY(exported_session_key, TRUE, key);
1131 *client_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1132 SIGNKEY(exported_session_key, FALSE, key);
1133 *server_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1134 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1135 *client_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1136 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1137 *server_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1140 /* @TODO: */
1141 /* @since Vista
1142 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1143 the client SHOULD provide a MIC:
1144 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1145 - then in the Value field, set bit 0x2 to 1.
1146 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1147 and the Value field bit 0x2 to 1.
1148 - Populate the MIC field with the MIC.
1151 /* Connection-oriented:
1152 Set MIC to HMAC_MD5(ExportedSessionKey,
1153 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1154 Connectionless:
1155 Set MIC to HMAC_MD5(ExportedSessionKey,
1156 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1159 /* on the server-side:
1160 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1161 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1162 Set MIC to HMAC_MD5(ExportedSessionKey,
1163 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1164 Else
1165 Set ExportedSessionKey to KeyExchangeKey
1166 Set MIC to HMAC_MD5(KeyExchangeKey,
1167 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1168 =====
1169 @since Vista
1170 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1171 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1172 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1173 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1174 an AV_PAIR structure whose two fields:
1175 - AvId == MsvAvFlags
1176 - Value bit 0x2 == 1
1177 @supported NT, 2000, XP
1178 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1179 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1180 the server time, then the server SHOULD return a failure.
1182 Connectionless:
1183 Set MIC to HMAC_MD5(ResponseKeyNT,
1184 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1187 /* authenticate message initialization */
1188 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1189 tmsg->type = GUINT32_TO_LE(3);
1191 /* Initial offset */
1192 offset = sizeof(struct authenticate_message);
1193 tmp = ((char*) tmsg) + offset;
1195 #define _FILL_SMB_HEADER(header) \
1196 tmsg->header.offset = GUINT32_TO_LE(offset); \
1197 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1198 tmp += len; \
1199 offset += len
1200 #define _APPEND_STRING(header, src) \
1201 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1202 _FILL_SMB_HEADER(header)
1203 #define _APPEND_DATA(header, src, srclen) \
1204 len = (srclen); \
1205 memcpy(tmp, (src), len); \
1206 _FILL_SMB_HEADER(header)
1208 /* Domain */
1209 _APPEND_STRING(domain, domain);
1211 /* User */
1212 _APPEND_STRING(user, user);
1214 /* Host */
1215 _APPEND_STRING(host, hostname);
1217 /* LM */
1218 /* @since Windows 7
1219 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1220 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1221 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1223 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1225 /* NT */
1226 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1228 /* Session Key */
1229 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1231 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1233 else
1235 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1236 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1239 /* Version */
1240 #ifdef _SIPE_COMPILING_TESTS
1241 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1242 #else
1243 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1244 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1245 tmsg->ver.product_minor_version = 1;
1246 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1247 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1249 #endif
1251 /* Set Negotiate Flags */
1252 tmsg->flags = GUINT32_TO_LE(neg_flags);
1253 *flags = neg_flags;
1255 out_buff->value = (guint8 *)tmsg;
1256 out_buff->length = msglen;
1258 return SIP_SEC_E_OK;
1262 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1264 static void
1265 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1267 guint32 offset;
1268 guint16 len;
1269 int msglen = sizeof(struct negotiate_message);
1270 struct negotiate_message *tmsg = g_malloc0(msglen);
1272 /* negotiate message initialization */
1273 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1274 tmsg->type = GUINT32_TO_LE(1);
1276 /* Set Negotiate Flags */
1277 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1279 /* Domain */
1280 offset = sizeof(struct negotiate_message);
1281 tmsg->domain.offset = GUINT32_TO_LE(offset);
1282 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1284 /* Host */
1285 offset += len;
1286 tmsg->host.offset = GUINT32_TO_LE(offset);
1287 tmsg->host.len = tmsg->host.maxlen = len = 0;
1289 /* Version */
1290 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1291 tmsg->ver.product_minor_version = 1;
1292 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1293 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1295 out_buff->value = (guint8 *)tmsg;
1296 out_buff->length = msglen;
1299 static void
1300 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1301 const char *msg,
1302 guint32 random_pad,
1303 unsigned char *sign_key,
1304 unsigned char *seal_key,
1305 unsigned char *result)
1307 char *res;
1309 MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100, result);
1311 res = buff_to_hex_str(result, 16);
1312 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res);
1313 g_free(res);
1317 /* Describe NTLM messages functions */
1319 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1320 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1322 static gchar *
1323 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1325 GString* str = g_string_new(NULL);
1327 flags = GUINT32_FROM_LE(flags);
1329 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1330 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1331 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1332 APPEND_NEG_FLAG(str, flags, r9, "r9");
1333 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1334 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1335 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1336 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1337 APPEND_NEG_FLAG(str, flags, r8, "r8");
1338 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1339 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1340 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1341 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1342 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1343 APPEND_NEG_FLAG(str, flags, r7, "r7");
1344 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1345 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1346 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1347 APPEND_NEG_FLAG(str, flags, r6, "r6");
1348 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1349 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1350 APPEND_NEG_FLAG(str, flags, r5, "r5");
1351 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1352 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1353 APPEND_NEG_FLAG(str, flags, r4, "r4");
1354 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1355 APPEND_NEG_FLAG(str, flags, r3, "r3");
1356 APPEND_NEG_FLAG(str, flags, r2, "r2");
1357 APPEND_NEG_FLAG(str, flags, r1, "r1");
1358 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1359 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1360 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1362 return g_string_free(str, FALSE);
1365 static gchar *
1366 sip_sec_ntlm_describe_version(struct version *ver) {
1367 GString* str = g_string_new(NULL);
1368 gchar *ver_desc = "";
1369 gchar *ntlm_revision_desc = "";
1371 if (ver->product_major_version == 6) {
1372 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1373 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1374 ver_desc = "Windows Server 2003";
1375 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1376 ver_desc = "Windows XP SP2";
1379 if (ver->ntlm_revision_current == 0x0F) {
1380 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1381 } else if (ver->ntlm_revision_current == 0x0A) {
1382 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1385 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1386 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1387 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1389 return g_string_free(str, FALSE);
1392 static gchar *
1393 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1394 const char* name)
1396 GString* str = g_string_new(NULL);
1398 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1399 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1400 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1402 return g_string_free(str, FALSE);
1405 static gchar *
1406 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1408 GString* str = g_string_new(NULL);
1409 char *tmp;
1411 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1412 g_free(tmp);
1414 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1415 g_free(tmp);
1417 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1418 g_free(tmp);
1420 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1421 g_string_append(str, tmp);
1422 g_free(tmp);
1424 if (cmsg->domain.len && cmsg->domain.offset) {
1425 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1426 g_string_append_printf(str, "\tdomain: %s\n", domain);
1427 g_free(domain);
1430 if (cmsg->host.len && cmsg->host.offset) {
1431 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1432 g_string_append_printf(str, "\thost: %s\n", host);
1433 g_free(host);
1436 return g_string_free(str, FALSE);
1439 static void
1440 describe_av_pairs(GString* str, const void *av)
1442 #define AV_DESC(av_name) \
1444 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1445 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1446 g_free(tmp); \
1449 ALIGN_AV_LOOP_START
1451 case MsvAvNbComputerName:
1452 AV_DESC("MsvAvNbComputerName");
1453 break;
1454 case MsvAvNbDomainName:
1455 AV_DESC("MsvAvNbDomainName");
1456 break;
1457 case MsvAvDnsComputerName:
1458 AV_DESC("MsvAvDnsComputerName");
1459 break;
1460 case MsvAvDnsDomainName:
1461 AV_DESC("MsvAvDnsDomainName");
1462 break;
1463 case MsvAvDnsTreeName:
1464 AV_DESC("MsvAvDnsTreeName");
1465 break;
1466 case MsvAvFlags:
1468 guint32 flags;
1470 /* to meet sparc's alignment requirement */
1471 memcpy(&flags, av_value, sizeof(guint32));
1472 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1474 break;
1475 case MsvAvTimestamp:
1477 char *tmp;
1478 guint64 time_val;
1479 time_t time_t_val;
1481 /* to meet sparc's alignment requirement */
1482 memcpy(&time_val, av_value, sizeof(time_val));
1483 time_t_val = TIME_VAL_TO_T(time_val);
1485 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1486 asctime(gmtime(&time_t_val)));
1487 g_free(tmp);
1489 break;
1490 case MsAvRestrictions:
1491 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1492 break;
1493 case MsvAvTargetName:
1494 AV_DESC("MsvAvTargetName");
1495 break;
1496 case MsvChannelBindings:
1497 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1498 break;
1500 ALIGN_AV_LOOP_END;
1503 static gchar *
1504 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1506 GString* str = g_string_new(NULL);
1507 char *tmp;
1508 gsize value_len;
1509 guint8 *value;
1511 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1512 g_free(tmp);
1514 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1515 g_free(tmp);
1517 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1518 g_free(tmp);
1520 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1521 g_free(tmp);
1523 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1524 g_free(tmp);
1526 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1527 g_free(tmp);
1529 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1530 g_free(tmp);
1532 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1533 g_string_append(str, tmp);
1534 g_free(tmp);
1536 /* mic */
1537 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1538 //g_free(tmp);
1540 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1541 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1542 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1543 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1544 g_free(tmp);
1547 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1548 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1549 int nt_resp_len = nt_resp_len_full;
1551 value_len = nt_resp_len_full;
1552 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1553 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1554 g_free(tmp);
1556 if (nt_resp_len > 24) { /* NTLMv2 */
1557 nt_resp_len = 16;
1560 value_len = nt_resp_len;
1561 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1562 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1563 g_free(tmp);
1565 if (nt_resp_len_full > 24) { /* NTLMv2 */
1566 /* Work around Debian/x86_64 compiler bug */
1567 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1568 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1569 const guint8 *temp = (guint8 *)cmsg + offset;
1570 const guint response_version = temp[0];
1571 const guint hi_response_version = temp[1];
1572 const guint8 *client_challenge = temp + 16;
1573 const guint8 *target_info = temp + 28;
1574 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1575 guint64 time_val;
1576 time_t time_t_val;
1577 char *tmp;
1579 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1580 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1581 g_free(tmp);
1583 /* This is not int64 aligned on sparc */
1584 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1585 time_t_val = TIME_VAL_TO_T(time_val);
1587 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1588 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1590 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1591 asctime(gmtime(&time_t_val)));
1592 g_free(tmp);
1594 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1595 g_free(tmp);
1597 describe_av_pairs(str, target_info);
1599 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1603 if (cmsg->domain.len && cmsg->domain.offset) {
1604 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1605 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1606 g_free(domain);
1609 if (cmsg->user.len && cmsg->user.offset) {
1610 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1611 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1612 g_free(user);
1615 if (cmsg->host.len && cmsg->host.offset) {
1616 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1617 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1618 g_free(host);
1621 if (cmsg->session_key.len && cmsg->session_key.offset) {
1622 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1623 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1624 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1625 g_free(tmp);
1628 return g_string_free(str, FALSE);
1631 static gchar *
1632 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1634 GString* str = g_string_new(NULL);
1635 char *tmp;
1637 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1638 g_free(tmp);
1640 /* nonce (server_challenge) */
1641 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1642 g_free(tmp);
1644 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1645 g_free(tmp);
1647 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1648 g_free(tmp);
1650 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1651 g_free(tmp);
1653 if (cmsg->target_name.len && cmsg->target_name.offset) {
1654 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1655 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1656 g_free(target_name);
1659 if (cmsg->target_info.len && cmsg->target_info.offset) {
1660 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1661 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1663 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1664 g_free(tmp);
1666 describe_av_pairs(str, target_info);
1669 return g_string_free(str, FALSE);
1672 gchar *
1673 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1675 struct ntlm_message *msg;
1676 gchar *res = NULL;
1678 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1680 msg = (struct ntlm_message *)buff.value;
1681 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1683 switch (GUINT32_FROM_LE(msg->type)) {
1684 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1685 break;
1686 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1687 break;
1688 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1689 break;
1692 return res;
1695 /* sip-sec-mech.h API implementation for NTLM */
1697 /* Security context for NTLM */
1698 typedef struct _context_ntlm {
1699 struct sip_sec_context common;
1700 char* domain;
1701 char *username;
1702 char *password;
1703 int step;
1704 guchar *client_sign_key;
1705 guchar *server_sign_key;
1706 guchar *client_seal_key;
1707 guchar *server_seal_key;
1708 guint32 flags;
1709 } *context_ntlm;
1712 static sip_uint32
1713 sip_sec_acquire_cred__ntlm(SipSecContext context,
1714 const char *domain,
1715 const char *username,
1716 const char *password)
1718 context_ntlm ctx = (context_ntlm)context;
1720 /* NTLM requires a domain, username & password */
1721 if (!domain || !username || !password)
1722 return SIP_SEC_E_INTERNAL_ERROR;
1724 ctx->domain = g_strdup(domain);
1725 ctx->username = g_strdup(username);
1726 ctx->password = g_strdup(password);
1728 return SIP_SEC_E_OK;
1731 static sip_uint32
1732 sip_sec_init_sec_context__ntlm(SipSecContext context,
1733 SipSecBuffer in_buff,
1734 SipSecBuffer *out_buff,
1735 SIPE_UNUSED_PARAMETER const char *service_name)
1737 context_ntlm ctx = (context_ntlm) context;
1739 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
1741 ctx->step++;
1742 if (ctx->step == 1) {
1743 if (!context->is_connection_based) {
1744 out_buff->length = 0;
1745 out_buff->value = NULL;
1746 } else {
1747 sip_sec_ntlm_gen_negotiate(out_buff);
1749 return SIP_SEC_I_CONTINUE_NEEDED;
1751 } else {
1752 sip_uint32 res;
1753 guchar *client_sign_key = NULL;
1754 guchar *server_sign_key = NULL;
1755 guchar *client_seal_key = NULL;
1756 guchar *server_seal_key = NULL;
1757 guchar *server_challenge = NULL;
1758 guint64 time_val = 0;
1759 guchar *target_info = NULL;
1760 int target_info_len = 0;
1761 guint32 flags;
1762 gchar *tmp;
1764 if (!in_buff.value || !in_buff.length) {
1765 return SIP_SEC_E_INTERNAL_ERROR;
1768 sip_sec_ntlm_parse_challenge(in_buff,
1769 &flags,
1770 &server_challenge, /* 8 bytes */
1771 &time_val,
1772 &target_info,
1773 &target_info_len);
1775 res = sip_sec_ntlm_gen_authenticate(
1776 &client_sign_key,
1777 &server_sign_key,
1778 &client_seal_key,
1779 &server_seal_key,
1780 ctx->username,
1781 ctx->password,
1782 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1783 ctx->domain,
1784 server_challenge,
1785 time_val,
1786 target_info,
1787 target_info_len,
1788 context->is_connection_based,
1789 out_buff,
1790 &flags);
1791 g_free(server_challenge);
1792 g_free(target_info);
1793 g_free(tmp);
1795 if (res != SIP_SEC_E_OK) {
1796 g_free(client_sign_key);
1797 g_free(server_sign_key);
1798 g_free(client_seal_key);
1799 g_free(server_seal_key);
1800 return res;
1803 g_free(ctx->client_sign_key);
1804 ctx->client_sign_key = client_sign_key;
1806 g_free(ctx->server_sign_key);
1807 ctx->server_sign_key = server_sign_key;
1809 g_free(ctx->client_seal_key);
1810 ctx->client_seal_key = client_seal_key;
1812 g_free(ctx->server_seal_key);
1813 ctx->server_seal_key = server_seal_key;
1815 ctx->flags = flags;
1816 return SIP_SEC_E_OK;
1821 * @param message a NULL terminated string to sign
1824 static sip_uint32
1825 sip_sec_make_signature__ntlm(SipSecContext context,
1826 const char *message,
1827 SipSecBuffer *signature)
1829 signature->length = 16;
1830 signature->value = g_malloc0(16);
1832 /* FIXME? We always use a random_pad of 0 */
1833 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1834 message,
1836 ((context_ntlm) context)->client_sign_key,
1837 ((context_ntlm) context)->client_seal_key,
1838 signature->value);
1839 return SIP_SEC_E_OK;
1843 * @param message a NULL terminated string to check signature of
1844 * @return SIP_SEC_E_OK on success
1846 static sip_uint32
1847 sip_sec_verify_signature__ntlm(SipSecContext context,
1848 const char *message,
1849 SipSecBuffer signature)
1851 guint8 mac[16];
1852 guint32 random_pad = GUINT32_FROM_LE(((guint32 *) signature.value)[1]);
1854 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1855 message,
1856 random_pad,
1857 ((context_ntlm) context)->server_sign_key,
1858 ((context_ntlm) context)->server_seal_key,
1859 mac);
1860 return(memcmp(signature.value, mac, 16) ?
1861 SIP_SEC_E_INTERNAL_ERROR :
1862 SIP_SEC_E_OK);
1865 static void
1866 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1868 context_ntlm ctx = (context_ntlm) context;
1870 g_free(ctx->domain);
1871 g_free(ctx->username);
1872 g_free(ctx->password);
1873 g_free(ctx->client_sign_key);
1874 g_free(ctx->server_sign_key);
1875 g_free(ctx->client_seal_key);
1876 g_free(ctx->server_seal_key);
1877 g_free(ctx);
1880 SipSecContext
1881 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1883 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1884 if (!context) return(NULL);
1886 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1887 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1888 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1889 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1890 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1892 return((SipSecContext) context);
1895 void sip_sec_init__ntlm(void)
1897 #ifdef HAVE_LANGINFO_CODESET
1898 const char *sys_cp = nl_langinfo(CODESET);
1899 #else
1900 const char *sys_cp = SIPE_DEFAULT_CODESET;
1901 #endif /* HAVE_LANGINFO_CODESET */
1903 /* fall back to utf-8 */
1904 if (!sys_cp) sys_cp = "UTF-8";
1906 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1907 if (convert_from_utf16le == (GIConv)-1) {
1908 SIPE_DEBUG_ERROR("g_iconv_open from UTF-16LE to %s failed",
1909 sys_cp);
1912 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1913 if (convert_from_utf16le == (GIConv)-1) {
1914 SIPE_DEBUG_ERROR("g_iconv_open from %s to UTF-16LE failed",
1915 sys_cp);
1919 void sip_sec_destroy__ntlm(void)
1921 g_iconv_close(convert_to_utf16le);
1922 g_iconv_close(convert_from_utf16le);
1926 Local Variables:
1927 mode: c
1928 c-file-style: "bsd"
1929 indent-tabs-mode: t
1930 tab-width: 8
1931 End: