media: fix relay-info with Farstream 0.2
[siplcs.git] / src / core / sip-sec-ntlm.c
blobce11cbcc851a126485021f9aaf351d64230b04d3
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2013 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 static void MD4(const guchar *data, gsize length, guchar *digest)
434 * From Firefox's complementing implementation for NSS.
435 * NSS doesn't include MD4, because it is considered weak.
437 md4sum(data, length, digest);
440 /* out 16 bytes */
441 #define MD5(d, len, result) sipe_digest_md5((d), (len), (result))
443 /* out 16 bytes */
445 static void
446 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
448 int i;
449 unsigned char ibuff[64 + data_len];
450 unsigned char obuff[64 + 16];
452 if (key_len > 64)
453 key_len = 64;
455 for (i = 0; i < key_len; i++) {
456 ibuff[i] = key[i] ^ 0x36;
457 obuff[i] = key[i] ^ 0x5c;
459 for (i = key_len; i < 64; i++) {
460 ibuff[i] = 0x36;
461 obuff[i] = 0x5c;
464 memcpy(ibuff+64, data, data_len);
466 MD5 (ibuff, 64 + data_len, obuff+64);
467 MD5 (obuff, 64 + 16, result);
469 #define HMAC_MD5 HMACT64
472 /* out 16 bytes */
473 #define HMAC_MD5(key, key_len, data, data_len, result) \
474 sipe_digest_hmac_md5((key), (key_len), (data), (data_len), (result))
476 /* NTLM Core Methods */
478 static void
479 NONCE(unsigned char *buffer, int num)
481 int i;
482 for (i = 0; i < num; i++) {
483 buffer[i] = (rand() & 0xff);
487 #ifdef _SIPE_COMPILING_TESTS
488 static void
489 Z(unsigned char *buffer, int num)
491 memset(buffer, 0, num);
494 static void
495 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
497 /* "KGS!@#$%" */
498 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
499 unsigned char uppercase_password[14];
500 int i;
502 int len = strlen(password);
503 if (len > 14) {
504 len = 14;
507 // Uppercase password
508 for (i = 0; i < len; i++) {
509 uppercase_password[i] = g_ascii_toupper(password[i]);
512 // Zero the rest
513 for (; i < 14; i++) {
514 uppercase_password[i] = 0;
517 DES (uppercase_password, magic, result);
518 DES (uppercase_password + 7, magic, result + 8);
520 #endif
523 Define NTOWFv1(Passwd, User, UserDom) as
524 MD4(UNICODE(Passwd))
525 EndDefine
527 /* out 16 bytes */
528 static void
529 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
531 int len_u = 2 * strlen(password); // utf16 should not be more
532 unsigned char *unicode_password = g_malloc(len_u);
534 /* well, if allocation failed the rest will crash & burn soon anyway... */
535 if (unicode_password) {
536 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
537 MD4 (unicode_password, len_u, result);
538 g_free(unicode_password);
543 Define NTOWFv2(Passwd, User, UserDom) as
544 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
545 EndDefine
547 /* out 16 bytes */
548 static void
549 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
551 unsigned char response_key_nt_v1 [16];
552 int len_user = user ? strlen(user) : 0;
553 int len_domain = strlen(domain);
554 int len_user_u = 2 * len_user; // utf16 should not be more
555 int len_domain_u = 2 * len_domain; // utf16 should not be more
556 unsigned char *user_upper = g_malloc(len_user + 1);
557 unsigned char *buff = g_malloc((len_user + len_domain)*2);
558 int i;
560 /* Uppercase user */
561 for (i = 0; i < len_user; i++) {
562 user_upper[i] = g_ascii_toupper(user[i]);
564 user_upper[len_user] = 0;
566 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
567 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), (gchar *)domain, len_domain_u);
569 NTOWFv1(password, user, domain, response_key_nt_v1);
571 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
573 g_free(buff);
574 g_free(user_upper);
577 static void
578 compute_response(const guint32 neg_flags,
579 const unsigned char *response_key_nt,
580 const unsigned char *response_key_lm,
581 const guint8 *server_challenge,
582 const guint8 *client_challenge,
583 const guint64 time_val,
584 const guint8 *target_info,
585 int target_info_len,
586 unsigned char *lm_challenge_response,
587 unsigned char *nt_challenge_response,
588 unsigned char *session_base_key)
590 #ifdef _SIPE_COMPILING_TESTS
591 if (use_ntlm_v2)
593 #endif
595 Responserversion - The 1-byte response version. Currently set to 1.
596 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
597 Time - The 8-byte little-endian time in GMT.
598 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
599 ClientChallenge - The 8-byte challenge message generated by the client.
600 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
602 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
603 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
604 Time, //8bytes - 8
605 ClientChallenge, //8bytes - 16
606 Z(4), //4bytes - 24
607 ServerName, //variable - 28
608 Z(4)) //4bytes - 28+target_info_len
609 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
610 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
611 Set LmChallengeResponse to ConcatenationOf(
612 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
613 ClientChallenge )
614 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
615 EndDefine
617 guint8 tmp [16];
618 guint8 nt_proof_str [16];
620 /* client_challenge (8) & temp (temp_len) buff */
621 unsigned int temp_len = 8+8+8+4+target_info_len+4;
622 guint64 *temp2 = g_malloc0(8 + temp_len);
623 ((guint8 *) temp2)[8+0] = 1;
624 ((guint8 *) temp2)[8+1] = 1;
625 temp2[2] = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
626 memcpy(((guint8 *) temp2)+8+16, client_challenge, 8);
627 memcpy(((guint8 *) temp2)+8+28, target_info, target_info_len);
629 /* NTProofStr */
630 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
631 memcpy(temp2, server_challenge, 8);
632 HMAC_MD5(response_key_nt, 16, (guint8*)temp2, 8+temp_len, nt_proof_str);
634 /* NtChallengeResponse */
635 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
636 memcpy(nt_challenge_response, nt_proof_str, 16);
637 memcpy(nt_challenge_response+16, temp2+1, temp_len);
638 g_free(temp2);
640 /* SessionBaseKey */
641 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
642 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
644 /* lm_challenge_response */
645 memcpy(tmp, server_challenge, 8);
646 memcpy(tmp+8, client_challenge, 8);
647 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
648 memcpy(lm_challenge_response+16, client_challenge, 8);
650 #ifndef _SIPE_COMPILING_TESTS
651 /* Not used in NTLMv2 */
652 (void)neg_flags;
653 #else
655 else
657 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
658 // @TODO do not even reference nt_challenge_response
659 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
660 DESL (response_key_lm, server_challenge, lm_challenge_response);
661 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
662 unsigned char prehash [16];
663 unsigned char hash [16];
665 /* nt_challenge_response */
666 memcpy(prehash, server_challenge, 8);
667 memcpy(prehash + 8, client_challenge, 8);
668 MD5 (prehash, 16, hash);
669 DESL (response_key_nt, hash, nt_challenge_response);
671 /* lm_challenge_response */
672 memcpy(lm_challenge_response, client_challenge, 8);
673 Z (lm_challenge_response+8, 16);
674 } else {
675 DESL (response_key_nt, server_challenge, nt_challenge_response);
676 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
677 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
678 } else {
679 DESL (response_key_lm, server_challenge, lm_challenge_response);
683 /* Session Key */
684 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
686 #endif
689 static void
690 KXKEY ( guint32 flags,
691 const unsigned char * session_base_key,
692 const unsigned char * lm_challenge_resonse,
693 const guint8 * server_challenge, /* 8-bytes, nonce */
694 unsigned char * key_exchange_key)
696 #ifdef _SIPE_COMPILING_TESTS
697 if (use_ntlm_v2)
699 #else
700 /* Not used in NTLMv2 */
701 (void)flags;
702 (void)lm_challenge_resonse;
703 (void)server_challenge;
704 #endif
705 memcpy(key_exchange_key, session_base_key, 16);
706 #ifdef _SIPE_COMPILING_TESTS
708 else
710 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
711 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
712 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
713 EndDefine
715 guint8 tmp[16];
716 memcpy(tmp, server_challenge, 8);
717 memcpy(tmp+8, lm_challenge_resonse, 8);
718 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
719 } else {
720 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
721 memcpy(key_exchange_key, session_base_key, 16);
724 #endif
728 If (Mode equals "Client")
729 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
730 "session key to client-to-server signing key magic constant"))
731 Else
732 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
733 "session key to server-to-client signing key magic constant"))
734 Endif
736 static void
737 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
739 char * magic = client
740 ? "session key to client-to-server signing key magic constant"
741 : "session key to server-to-client signing key magic constant";
743 int len = strlen(magic) + 1;
744 unsigned char *md5_input = g_malloc(16 + len);
745 memcpy(md5_input, random_session_key, 16);
746 memcpy(md5_input + 16, magic, len);
748 MD5 (md5_input, len + 16, result);
749 g_free(md5_input);
753 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
754 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
755 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
756 Set SealKey to RandomSessionKey
757 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
758 Set SealKey to RandomSessionKey[0..6]
759 Else
760 Set SealKey to RandomSessionKey[0..4]
761 Endif
763 If (Mode equals "Client")
764 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
765 Else
766 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
767 Endif
769 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
770 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
771 Else
772 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
773 Endif
774 EndDefine
776 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
777 static void
778 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
780 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
782 char * magic = client
783 ? "session key to client-to-server sealing key magic constant"
784 : "session key to server-to-client sealing key magic constant";
786 int len = strlen(magic) + 1;
787 unsigned char *md5_input = g_malloc(16 + len);
788 int key_len;
790 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
791 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
792 key_len = 16;
793 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
794 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
795 key_len = 7;
796 } else {
797 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
798 key_len = 5;
801 memcpy(md5_input, random_session_key, key_len);
802 memcpy(md5_input + key_len, magic, len);
804 MD5 (md5_input, key_len + len, result);
805 g_free(md5_input);
807 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
809 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
810 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
811 memcpy(result, random_session_key, 7);
812 result[7] = 0xA0;
813 } else {
814 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
815 memcpy(result, random_session_key, 5);
816 result[5] = 0xE5;
817 result[6] = 0x38;
818 result[7] = 0xB0;
821 else
823 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
824 memcpy(result, random_session_key, 16);
829 = for Extended Session Security =
830 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
831 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
832 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
834 = if Extended Session Security is NOT negotiated =
835 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
836 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
837 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
838 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
840 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
842 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
843 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
845 /** MAC(Handle, SigningKey, SeqNum, Message) */
846 /* out 16 bytes */
847 static void
848 MAC (guint32 flags,
849 const char *buf,
850 unsigned int buf_len,
851 unsigned char *sign_key,
852 unsigned long sign_key_len,
853 unsigned char *seal_key,
854 unsigned long seal_key_len,
855 guint32 random_pad,
856 guint32 sequence,
857 guint32 *result)
859 guint32 *res_ptr;
861 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
863 Define MAC(Handle, SigningKey, SeqNum, Message) as
864 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
865 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
866 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
867 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
868 Set SeqNum to SeqNum + 1
869 EndDefine
871 /* If a key exchange key is negotiated
872 Define MAC(Handle, SigningKey, SeqNum, Message) as
873 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
874 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
875 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
876 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
877 Set SeqNum to SeqNum + 1
878 EndDefine
881 unsigned char seal_key_ [16];
882 guchar hmac[16];
883 guint32 *tmp = g_malloc(4 + buf_len);
885 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
886 RC4Init(Handle, SealingKey')
888 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
889 guint32 tmp2[4+1];
891 memcpy(tmp2, seal_key, seal_key_len);
892 tmp2[4] = GUINT32_TO_LE(sequence);
893 MD5 ((guchar *)tmp2, sizeof(tmp2), seal_key_);
894 } else {
895 memcpy(seal_key_, seal_key, seal_key_len);
898 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extented Session Security");
900 res_ptr = result;
901 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
902 res_ptr[3] = GUINT32_TO_LE(sequence);
904 res_ptr = tmp;
905 res_ptr[0] = GUINT32_TO_LE(sequence);
906 memcpy(tmp+1, buf, buf_len);
908 HMAC_MD5(sign_key, sign_key_len, (guchar *)tmp, 4 + buf_len, hmac);
909 g_free(tmp);
911 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
912 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
913 RC4K(seal_key_, seal_key_len, hmac, 8, (guchar *)(result+1));
914 } else {
915 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
916 memcpy(result+1, hmac, 8);
918 } else {
919 /* The content of the first 4 bytes is irrelevant */
920 guint32 crc = CRC32(buf, strlen(buf));
921 guint32 plaintext [] = {
922 GUINT32_TO_LE(0),
923 GUINT32_TO_LE(crc),
924 GUINT32_TO_LE(sequence)
925 }; // 4, 4, 4 bytes
927 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extented Session Security");
929 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, (guchar *)(result+1));
931 res_ptr = result;
932 // Highest four bytes are the Version
933 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
935 // Replace the first four bytes of the ciphertext with the random_pad
936 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
940 /* End Core NTLM Methods */
943 * @param flags (out) flags received from server
944 * @param server_challenge must be g_free()'d after use if requested
945 * @param target_info must be g_free()'d after use if requested
947 static void
948 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
949 guint32 *flags,
950 guchar **server_challenge, /* 8 bytes */
951 guint64 *time_val,
952 guchar **target_info,
953 int *target_info_len)
955 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
956 struct challenge_message *cmsg = (void *)in_buff.value;
957 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
959 /* server challenge (nonce) */
960 if (server_challenge) {
961 *server_challenge = g_memdup(cmsg->nonce, 8);
964 /* flags */
965 if (flags) {
966 *flags = host_flags;
969 /* target_info */
970 if (cmsg->target_info.len && cmsg->target_info.offset) {
971 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
972 void *av = content;
973 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
975 ALIGN_AV_LOOP_START
977 /* @since Vista */
978 case MsvAvTimestamp:
979 if (time_val) {
980 guint64 tmp;
982 /* to meet sparc's alignment requirement */
983 memcpy(&tmp, av_value, sizeof(tmp));
984 *time_val = GUINT64_FROM_LE(tmp);
986 break;
988 ALIGN_AV_LOOP_END;
990 if (target_info_len) {
991 *target_info_len = len;
993 if (target_info) {
994 *target_info = g_memdup(content, len);
1000 * @param client_sign_key (out) must be g_free()'d after use
1001 * @param server_sign_key (out) must be g_free()'d after use
1002 * @param client_seal_key (out) must be g_free()'d after use
1003 * @param server_seal_key (out) must be g_free()'d after use
1004 * @param flags (in, out) negotiated flags
1006 static gboolean
1007 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
1008 guchar **server_sign_key,
1009 guchar **client_seal_key,
1010 guchar **server_seal_key,
1011 const gchar *user,
1012 const gchar *password,
1013 const gchar *hostname,
1014 const gchar *domain,
1015 const guint8 *server_challenge, /* nonce */
1016 const guint64 time_val,
1017 const guint8 *target_info,
1018 int target_info_len,
1019 gboolean http,
1020 SipSecBuffer *out_buff,
1021 guint32 *flags)
1023 guint32 orig_flags = http ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
1024 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1025 int ntlmssp_nt_resp_len =
1026 #ifdef _SIPE_COMPILING_TESTS
1027 use_ntlm_v2 ?
1028 #endif
1029 (16 + (32+target_info_len))
1030 #ifdef _SIPE_COMPILING_TESTS
1031 : NTLMSSP_LM_RESP_LEN
1032 #endif
1034 gsize msglen = sizeof(struct authenticate_message)
1035 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1036 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1037 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1038 struct authenticate_message *tmsg;
1039 char *tmp;
1040 guint32 offset;
1041 guint16 len;
1042 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1043 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1044 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1045 unsigned char *nt_challenge_response = g_malloc(ntlmssp_nt_resp_len); /* variable or 24 */
1046 unsigned char session_base_key [16];
1047 unsigned char key_exchange_key [16];
1048 unsigned char exported_session_key[16];
1049 unsigned char encrypted_random_session_key [16];
1050 unsigned char key [16];
1051 unsigned char client_challenge [8];
1052 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1054 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1055 !(http || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)) ||
1056 !nt_challenge_response) /* Coverity thinks ntlmssp_nt_resp_len could be 0 */
1058 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1059 g_free(nt_challenge_response);
1060 return FALSE;
1063 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1064 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1067 tmsg = g_malloc0(msglen);
1069 NONCE (client_challenge, 8);
1071 #ifdef _SIPE_COMPILING_TESTS
1072 memcpy(client_challenge, test_client_challenge, 8);
1073 time_vl = test_time_val ? test_time_val : time_vl;
1075 if (use_ntlm_v2) {
1077 #endif
1078 NTOWFv2 (password, user, domain, response_key_nt);
1079 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1080 #ifdef _SIPE_COMPILING_TESTS
1081 } else {
1082 NTOWFv1 (password, user, domain, response_key_nt);
1083 LMOWFv1 (password, user, domain, response_key_lm);
1085 #endif
1087 compute_response(neg_flags,
1088 response_key_nt,
1089 response_key_lm,
1090 server_challenge,
1091 client_challenge,
1092 time_vl,
1093 target_info,
1094 target_info_len,
1095 lm_challenge_response, /* out */
1096 nt_challenge_response, /* out */
1097 session_base_key); /* out */
1099 /* same as session_base_key for
1100 * - NTLNv1 w/o Ext.Sess.Sec and
1101 * - NTLMv2
1103 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1105 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1106 NONCE (exported_session_key, 16); // random master key
1107 #ifdef _SIPE_COMPILING_TESTS
1108 memcpy(exported_session_key, test_random_session_key, 16);
1109 #endif
1110 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1111 } else {
1112 memcpy(exported_session_key, key_exchange_key, 16);
1115 tmp = buff_to_hex_str(exported_session_key, 16);
1116 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp);
1117 g_free(tmp);
1119 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1120 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1122 /* p.46
1123 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1124 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1126 SIGNKEY(exported_session_key, TRUE, key);
1127 *client_sign_key = g_memdup(key, 16);
1128 SIGNKEY(exported_session_key, FALSE, key);
1129 *server_sign_key = g_memdup(key, 16);
1130 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1131 *client_seal_key = g_memdup(key, 16);
1132 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1133 *server_seal_key = g_memdup(key, 16);
1136 /* @TODO: */
1137 /* @since Vista
1138 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1139 the client SHOULD provide a MIC:
1140 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1141 - then in the Value field, set bit 0x2 to 1.
1142 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1143 and the Value field bit 0x2 to 1.
1144 - Populate the MIC field with the MIC.
1147 /* Connection-oriented:
1148 Set MIC to HMAC_MD5(ExportedSessionKey,
1149 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1150 Connectionless:
1151 Set MIC to HMAC_MD5(ExportedSessionKey,
1152 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1155 /* on the server-side:
1156 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1157 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1158 Set MIC to HMAC_MD5(ExportedSessionKey,
1159 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1160 Else
1161 Set ExportedSessionKey to KeyExchangeKey
1162 Set MIC to HMAC_MD5(KeyExchangeKey,
1163 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1164 =====
1165 @since Vista
1166 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1167 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1168 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1169 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1170 an AV_PAIR structure whose two fields:
1171 - AvId == MsvAvFlags
1172 - Value bit 0x2 == 1
1173 @supported NT, 2000, XP
1174 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1175 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1176 the server time, then the server SHOULD return a failure.
1178 Connectionless:
1179 Set MIC to HMAC_MD5(ResponseKeyNT,
1180 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1183 /* authenticate message initialization */
1184 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1185 tmsg->type = GUINT32_TO_LE(3);
1187 /* Initial offset */
1188 offset = sizeof(struct authenticate_message);
1189 tmp = ((char*) tmsg) + offset;
1191 #define _FILL_SMB_HEADER(header) \
1192 tmsg->header.offset = GUINT32_TO_LE(offset); \
1193 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1194 tmp += len; \
1195 offset += len
1196 #define _APPEND_STRING(header, src) \
1197 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1198 _FILL_SMB_HEADER(header)
1199 #define _APPEND_DATA(header, src, srclen) \
1200 len = (srclen); \
1201 memcpy(tmp, (src), len); \
1202 _FILL_SMB_HEADER(header)
1204 /* Domain */
1205 _APPEND_STRING(domain, domain);
1207 /* User */
1208 _APPEND_STRING(user, user);
1210 /* Host */
1211 _APPEND_STRING(host, hostname);
1213 /* LM */
1214 /* @since Windows 7
1215 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1216 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1217 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1219 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1221 /* NT */
1222 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1224 /* Session Key */
1225 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1227 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1229 else
1231 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1232 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1235 /* Version */
1236 #ifdef _SIPE_COMPILING_TESTS
1237 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1238 #else
1239 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1240 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1241 tmsg->ver.product_minor_version = 1;
1242 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1243 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1245 #endif
1247 /* Set Negotiate Flags */
1248 tmsg->flags = GUINT32_TO_LE(neg_flags);
1249 *flags = neg_flags;
1251 out_buff->value = (guint8 *)tmsg;
1252 out_buff->length = msglen;
1254 g_free(nt_challenge_response);
1256 return TRUE;
1260 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1262 static void
1263 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1265 guint32 offset;
1266 guint16 len;
1267 int msglen = sizeof(struct negotiate_message);
1268 struct negotiate_message *tmsg = g_malloc0(msglen);
1270 /* negotiate message initialization */
1271 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1272 tmsg->type = GUINT32_TO_LE(1);
1274 /* Set Negotiate Flags */
1275 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1277 /* Domain */
1278 offset = sizeof(struct negotiate_message);
1279 tmsg->domain.offset = GUINT32_TO_LE(offset);
1280 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1282 /* Host */
1283 offset += len;
1284 tmsg->host.offset = GUINT32_TO_LE(offset);
1285 tmsg->host.len = tmsg->host.maxlen = len = 0;
1287 /* Version */
1288 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1289 tmsg->ver.product_minor_version = 1;
1290 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1291 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1293 out_buff->value = (guint8 *)tmsg;
1294 out_buff->length = msglen;
1297 static void
1298 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1299 const char *msg,
1300 guint32 random_pad,
1301 unsigned char *sign_key,
1302 unsigned char *seal_key,
1303 guint32 *result)
1305 char *res;
1307 MAC(flags, msg, strlen(msg), sign_key, 16, seal_key, 16, random_pad, 100, result);
1309 res = buff_to_hex_str((guint8 *)result, 16);
1310 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res);
1311 g_free(res);
1314 #endif /* !_SIPE_COMPILING_ANALYZER */
1316 /* Describe NTLM messages functions */
1318 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1319 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1321 static gchar *
1322 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1324 GString* str = g_string_new(NULL);
1326 flags = GUINT32_FROM_LE(flags);
1328 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1329 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1330 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1331 APPEND_NEG_FLAG(str, flags, r9, "r9");
1332 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1333 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1334 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1335 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1336 APPEND_NEG_FLAG(str, flags, r8, "r8");
1337 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1338 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1339 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1340 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1341 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1342 APPEND_NEG_FLAG(str, flags, r7, "r7");
1343 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1344 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1345 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1346 APPEND_NEG_FLAG(str, flags, r6, "r6");
1347 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1348 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1349 APPEND_NEG_FLAG(str, flags, r5, "r5");
1350 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1351 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1352 APPEND_NEG_FLAG(str, flags, r4, "r4");
1353 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1354 APPEND_NEG_FLAG(str, flags, r3, "r3");
1355 APPEND_NEG_FLAG(str, flags, r2, "r2");
1356 APPEND_NEG_FLAG(str, flags, r1, "r1");
1357 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1358 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1359 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1361 return g_string_free(str, FALSE);
1364 static gchar *
1365 sip_sec_ntlm_describe_version(struct version *ver) {
1366 GString* str = g_string_new(NULL);
1367 gchar *ver_desc = "";
1368 gchar *ntlm_revision_desc = "";
1370 if (ver->product_major_version == 6) {
1371 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1372 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1373 ver_desc = "Windows Server 2003";
1374 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1375 ver_desc = "Windows XP SP2";
1378 if (ver->ntlm_revision_current == 0x0F) {
1379 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1380 } else if (ver->ntlm_revision_current == 0x0A) {
1381 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1384 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1385 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1386 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1388 return g_string_free(str, FALSE);
1391 static gchar *
1392 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1393 const char* name)
1395 GString* str = g_string_new(NULL);
1397 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1398 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1399 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1401 return g_string_free(str, FALSE);
1404 static gchar *
1405 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1407 GString* str = g_string_new(NULL);
1408 char *tmp;
1410 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1411 g_free(tmp);
1413 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1414 g_free(tmp);
1416 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1417 g_free(tmp);
1419 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1420 g_string_append(str, tmp);
1421 g_free(tmp);
1423 if (cmsg->domain.len && cmsg->domain.offset) {
1424 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1425 g_string_append_printf(str, "\tdomain: %s\n", domain);
1426 g_free(domain);
1429 if (cmsg->host.len && cmsg->host.offset) {
1430 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1431 g_string_append_printf(str, "\thost: %s\n", host);
1432 g_free(host);
1435 return g_string_free(str, FALSE);
1438 static void
1439 describe_av_pairs(GString* str, const void *av)
1441 #define AV_DESC(av_name) \
1443 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1444 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1445 g_free(tmp); \
1448 ALIGN_AV_LOOP_START
1450 case MsvAvNbComputerName:
1451 AV_DESC("MsvAvNbComputerName");
1452 break;
1453 case MsvAvNbDomainName:
1454 AV_DESC("MsvAvNbDomainName");
1455 break;
1456 case MsvAvDnsComputerName:
1457 AV_DESC("MsvAvDnsComputerName");
1458 break;
1459 case MsvAvDnsDomainName:
1460 AV_DESC("MsvAvDnsDomainName");
1461 break;
1462 case MsvAvDnsTreeName:
1463 AV_DESC("MsvAvDnsTreeName");
1464 break;
1465 case MsvAvFlags:
1467 guint32 flags;
1469 /* to meet sparc's alignment requirement */
1470 memcpy(&flags, av_value, sizeof(guint32));
1471 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1473 break;
1474 case MsvAvTimestamp:
1476 char *tmp;
1477 guint64 time_val;
1478 time_t time_t_val;
1480 /* to meet sparc's alignment requirement */
1481 memcpy(&time_val, av_value, sizeof(time_val));
1482 time_t_val = TIME_VAL_TO_T(time_val);
1484 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1485 asctime(gmtime(&time_t_val)));
1486 g_free(tmp);
1488 break;
1489 case MsAvRestrictions:
1490 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1491 break;
1492 case MsvAvTargetName:
1493 AV_DESC("MsvAvTargetName");
1494 break;
1495 case MsvChannelBindings:
1496 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1497 break;
1499 ALIGN_AV_LOOP_END;
1502 static gchar *
1503 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1505 GString* str = g_string_new(NULL);
1506 char *tmp;
1507 gsize value_len;
1508 guint8 *value;
1510 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1511 g_free(tmp);
1513 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1514 g_free(tmp);
1516 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1517 g_free(tmp);
1519 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1520 g_free(tmp);
1522 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1523 g_free(tmp);
1525 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1526 g_free(tmp);
1528 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1529 g_free(tmp);
1531 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1532 g_string_append(str, tmp);
1533 g_free(tmp);
1535 /* mic */
1536 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1537 //g_free(tmp);
1539 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1540 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1541 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1542 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1543 g_free(tmp);
1546 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1547 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1548 int nt_resp_len = nt_resp_len_full;
1550 value_len = nt_resp_len_full;
1551 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1552 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1553 g_free(tmp);
1555 if (nt_resp_len > 24) { /* NTLMv2 */
1556 nt_resp_len = 16;
1559 value_len = nt_resp_len;
1560 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1561 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1562 g_free(tmp);
1564 if (nt_resp_len_full > 24) { /* NTLMv2 */
1565 /* Work around Debian/x86_64 compiler bug */
1566 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1567 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1568 const guint8 *temp = (guint8 *)cmsg + offset;
1569 const guint response_version = temp[0];
1570 const guint hi_response_version = temp[1];
1571 const guint8 *client_challenge = temp + 16;
1572 const guint8 *target_info = temp + 28;
1573 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1574 guint64 time_val;
1575 time_t time_t_val;
1576 char *tmp;
1578 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1579 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1580 g_free(tmp);
1582 /* This is not int64 aligned on sparc */
1583 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1584 time_t_val = TIME_VAL_TO_T(time_val);
1586 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1587 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1589 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1590 asctime(gmtime(&time_t_val)));
1591 g_free(tmp);
1593 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1594 g_free(tmp);
1596 describe_av_pairs(str, target_info);
1598 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1602 if (cmsg->domain.len && cmsg->domain.offset) {
1603 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1604 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1605 g_free(domain);
1608 if (cmsg->user.len && cmsg->user.offset) {
1609 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1610 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1611 g_free(user);
1614 if (cmsg->host.len && cmsg->host.offset) {
1615 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1616 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1617 g_free(host);
1620 if (cmsg->session_key.len && cmsg->session_key.offset) {
1621 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1622 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1623 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1624 g_free(tmp);
1627 return g_string_free(str, FALSE);
1630 static gchar *
1631 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1633 GString* str = g_string_new(NULL);
1634 char *tmp;
1636 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1637 g_free(tmp);
1639 /* nonce (server_challenge) */
1640 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1641 g_free(tmp);
1643 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1644 g_free(tmp);
1646 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1647 g_free(tmp);
1649 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1650 g_free(tmp);
1652 if (cmsg->target_name.len && cmsg->target_name.offset) {
1653 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1654 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1655 g_free(target_name);
1658 if (cmsg->target_info.len && cmsg->target_info.offset) {
1659 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1660 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1662 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1663 g_free(tmp);
1665 describe_av_pairs(str, target_info);
1668 return g_string_free(str, FALSE);
1671 static void
1672 sip_sec_ntlm_message_describe(SipSecBuffer *buff,
1673 const gchar *type)
1675 struct ntlm_message *msg;
1676 gchar *res = NULL;
1678 if (buff->length == 0 || buff->value == NULL || buff->length < 12) return;
1680 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1681 msg = (void *)buff->value;
1682 if(!sipe_strequal("NTLMSSP", (char*)msg)) return;
1684 switch (GUINT32_FROM_LE(msg->type)) {
1685 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1686 break;
1687 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1688 break;
1689 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1690 break;
1693 SIPE_DEBUG_INFO("sip_sec_ntlm_message_describe: %s message is:\n%s",
1694 type, res);
1695 g_free(res);
1698 /* Analyzer only needs the _describe() functions */
1699 #ifndef _SIPE_COMPILING_ANALYZER
1701 /* sip-sec-mech.h API implementation for NTLM */
1703 /* Security context for NTLM */
1704 typedef struct _context_ntlm {
1705 struct sip_sec_context common;
1706 const gchar *domain;
1707 const gchar *username;
1708 const gchar *password;
1709 guchar *client_sign_key;
1710 guchar *server_sign_key;
1711 guchar *client_seal_key;
1712 guchar *server_seal_key;
1713 guint32 flags;
1714 } *context_ntlm;
1716 #define SIP_SEC_FLAG_NTLM_INITIAL 0x00010000
1719 static gboolean
1720 sip_sec_acquire_cred__ntlm(SipSecContext context,
1721 const gchar *domain,
1722 const gchar *username,
1723 const gchar *password)
1725 context_ntlm ctx = (context_ntlm)context;
1728 * Our NTLM implementation does not support Single Sign-On.
1729 * Thus username & password are required.
1730 * NULL or empty domain is OK.
1732 if (is_empty(username) || is_empty(password))
1733 return FALSE;
1735 /* this is the first time we are allowed to set private flags */
1736 context->flags |= SIP_SEC_FLAG_NTLM_INITIAL;
1738 ctx->domain = domain ? domain : "";
1739 ctx->username = username;
1740 ctx->password = password;
1742 return TRUE;
1745 static gboolean
1746 sip_sec_init_sec_context__ntlm(SipSecContext context,
1747 SipSecBuffer in_buff,
1748 SipSecBuffer *out_buff,
1749 SIPE_UNUSED_PARAMETER const gchar *service_name)
1751 context_ntlm ctx = (context_ntlm) context;
1753 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
1756 * If authentication was already completed, then this mean a new
1757 * authentication handshake has started on the existing connection.
1758 * We must throw away the old context, because we need a new one.
1760 if (context->flags & SIP_SEC_FLAG_COMMON_READY) {
1761 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: dropping old context");
1762 context->flags &= ~SIP_SEC_FLAG_COMMON_READY;
1763 context->flags |= SIP_SEC_FLAG_NTLM_INITIAL;
1766 if (context->flags & SIP_SEC_FLAG_NTLM_INITIAL) {
1767 context->flags &= ~SIP_SEC_FLAG_NTLM_INITIAL;
1769 /* HTTP */
1770 if (context->flags & SIP_SEC_FLAG_COMMON_HTTP) {
1771 sip_sec_ntlm_gen_negotiate(out_buff);
1772 sip_sec_ntlm_message_describe(out_buff, "Negotiate");
1773 /* SIP */
1774 } else {
1775 /* empty initial message for connection-less NTLM */
1776 out_buff->length = 0;
1777 out_buff->value = (guint8 *) g_strdup("");
1779 } else {
1780 gboolean res;
1781 guchar *client_sign_key = NULL;
1782 guchar *server_sign_key = NULL;
1783 guchar *client_seal_key = NULL;
1784 guchar *server_seal_key = NULL;
1785 guchar *server_challenge = NULL;
1786 guint64 time_val = 0;
1787 guchar *target_info = NULL;
1788 int target_info_len = 0;
1789 guint32 flags;
1790 gchar *tmp;
1792 if (!in_buff.value || !in_buff.length) {
1793 return FALSE;
1796 sip_sec_ntlm_message_describe(&in_buff, "Challenge");
1798 sip_sec_ntlm_parse_challenge(in_buff,
1799 &flags,
1800 &server_challenge, /* 8 bytes */
1801 &time_val,
1802 &target_info,
1803 &target_info_len);
1805 res = sip_sec_ntlm_gen_authenticate(
1806 &client_sign_key,
1807 &server_sign_key,
1808 &client_seal_key,
1809 &server_seal_key,
1810 ctx->username,
1811 ctx->password,
1812 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1813 ctx->domain,
1814 server_challenge,
1815 time_val,
1816 target_info,
1817 target_info_len,
1818 context->flags & SIP_SEC_FLAG_COMMON_HTTP,
1819 out_buff,
1820 &flags);
1821 g_free(server_challenge);
1822 g_free(target_info);
1823 g_free(tmp);
1825 if (!res) {
1826 g_free(client_sign_key);
1827 g_free(server_sign_key);
1828 g_free(client_seal_key);
1829 g_free(server_seal_key);
1830 return res;
1833 sip_sec_ntlm_message_describe(out_buff, "Authenticate");
1835 g_free(ctx->client_sign_key);
1836 ctx->client_sign_key = client_sign_key;
1838 g_free(ctx->server_sign_key);
1839 ctx->server_sign_key = server_sign_key;
1841 g_free(ctx->client_seal_key);
1842 ctx->client_seal_key = client_seal_key;
1844 g_free(ctx->server_seal_key);
1845 ctx->server_seal_key = server_seal_key;
1847 ctx->flags = flags;
1849 /* Authentication is completed */
1850 context->flags |= SIP_SEC_FLAG_COMMON_READY;
1853 return TRUE;
1857 * @param message a NULL terminated string to sign
1860 static gboolean
1861 sip_sec_make_signature__ntlm(SipSecContext context,
1862 const gchar *message,
1863 SipSecBuffer *signature)
1865 signature->length = 16;
1866 signature->value = g_malloc0(16);
1868 /* FIXME? We always use a random_pad of 0 */
1869 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1870 message,
1872 ((context_ntlm) context)->client_sign_key,
1873 ((context_ntlm) context)->client_seal_key,
1874 /* SipSecBuffer.value is g_malloc()'d:
1875 * use (void *) to remove guint8 alignment
1877 (void *)signature->value);
1878 return TRUE;
1882 * @param message a NULL terminated string to check signature of
1883 * @return TRUE on success
1885 static gboolean
1886 sip_sec_verify_signature__ntlm(SipSecContext context,
1887 const gchar *message,
1888 SipSecBuffer signature)
1890 context_ntlm ctx = (context_ntlm) context;
1891 guint32 mac[4];
1892 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1893 guint32 random_pad = GUINT32_FROM_LE(((guint32 *)((void *)signature.value))[1]);
1895 sip_sec_ntlm_sipe_signature_make(ctx->flags,
1896 message,
1897 random_pad,
1898 ctx->server_sign_key,
1899 ctx->server_seal_key,
1900 mac);
1901 return(memcmp(signature.value, mac, 16) == 0);
1904 static void
1905 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1907 context_ntlm ctx = (context_ntlm) context;
1909 g_free(ctx->client_sign_key);
1910 g_free(ctx->server_sign_key);
1911 g_free(ctx->client_seal_key);
1912 g_free(ctx->server_seal_key);
1913 g_free(ctx);
1916 static const gchar *
1917 sip_sec_context_name__ntlm(SIPE_UNUSED_PARAMETER SipSecContext context)
1919 return("NTLM");
1922 SipSecContext
1923 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER guint type)
1925 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1926 if (!context) return(NULL);
1928 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1929 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1930 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1931 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1932 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1933 context->common.context_name_func = sip_sec_context_name__ntlm;
1935 return((SipSecContext) context);
1938 gboolean sip_sec_password__ntlm(void)
1940 return(TRUE);
1943 #endif /* !_SIPE_COMPILING_ANALYZER */
1945 void sip_sec_init__ntlm(void)
1947 #ifdef HAVE_LANGINFO_CODESET
1948 const char *sys_cp = nl_langinfo(CODESET);
1949 #else
1950 const char *sys_cp = SIPE_DEFAULT_CODESET;
1951 #endif /* HAVE_LANGINFO_CODESET */
1953 /* fall back to utf-8 */
1954 if (!sys_cp) sys_cp = "UTF-8";
1956 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1957 if (convert_from_utf16le == (GIConv)-1) {
1958 SIPE_DEBUG_ERROR("g_iconv_open from UTF-16LE to %s failed",
1959 sys_cp);
1962 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1963 if (convert_to_utf16le == (GIConv)-1) {
1964 SIPE_DEBUG_ERROR("g_iconv_open from %s to UTF-16LE failed",
1965 sys_cp);
1969 void sip_sec_destroy__ntlm(void)
1971 g_iconv_close(convert_to_utf16le);
1972 g_iconv_close(convert_from_utf16le);
1976 Local Variables:
1977 mode: c
1978 c-file-style: "bsd"
1979 indent-tabs-mode: t
1980 tab-width: 8
1981 End: