coverity: fix various warnings
[siplcs.git] / src / core / sip-sec-ntlm.c
blob8158c36027b20b5778113273ab5f0701a3900a39
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2010-11 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 static gsize
311 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
313 gsize inbytes = strlen(source);
314 gsize outbytes = remlen;
315 if (remlen)
316 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
317 return(remlen - outbytes);
320 /* UTF-16LE to native encoding
321 * Must be g_free'd after use */
322 static gchar *
323 unicode_strconvcopy_back(const gchar *source, gsize len)
325 gsize outbytes = 2 * len;
326 gchar *dest = g_new0(gchar, outbytes + 1);
327 gchar *outbuf = dest;
328 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
329 return dest;
332 /* crc32 source copy from gg's common.c */
333 static guint32 crc32_table[256];
334 static int crc32_initialized = 0;
336 static void crc32_make_table()
338 guint32 h = 1;
339 unsigned int i, j;
341 memset(crc32_table, 0, sizeof(crc32_table));
343 for (i = 128; i; i >>= 1) {
344 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
346 for (j = 0; j < 256; j += 2 * i)
347 crc32_table[i + j] = crc32_table[j] ^ h;
350 crc32_initialized = 1;
353 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
355 if (!crc32_initialized)
356 crc32_make_table();
358 if (!buf || len < 0)
359 return crc;
361 crc ^= 0xffffffffL;
363 while (len--)
364 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
366 return crc ^ 0xffffffffL;
369 static guint32
370 CRC32 (const char *msg, int len)
372 guint32 crc = 0L;
373 crc = crc32(crc, (guint8 *) msg, len);
374 return crc;
377 /* Cyphers */
379 #ifdef _SIPE_COMPILING_TESTS
380 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
382 key[0] = key_56[0];
383 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
384 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
385 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
386 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
387 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
388 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
389 key[7] = (key_56[6] << 1) & 0xFF;
392 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
393 static void
394 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
396 unsigned char key[8];
397 setup_des_key(k, key);
398 sipe_crypt_des(key, d, 8, results);
401 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
402 static void
403 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
405 unsigned char keys[21];
407 /* Copy the first 16 bytes */
408 memcpy(keys, k, 16);
410 /* Zero out the last 5 bytes of the key */
411 memset(keys + 16, 0, 5);
413 DES(keys, d, results);
414 DES(keys + 7, d, results + 8);
415 DES(keys + 14, d, results + 16);
417 #endif
419 #define RC4K(key, key_len, plain, plain_len, encrypted) \
420 sipe_crypt_rc4((key), (key_len), (plain), (plain_len), (encrypted))
422 /* out 16 bytes */
423 static void MD4(const guchar *data, gsize length, guchar *digest)
426 * From Firefox's complementing implementation for NSS.
427 * NSS doesn't include MD4, because it is considered weak.
429 md4sum(data, length, digest);
432 /* out 16 bytes */
433 #define MD5(d, len, result) sipe_digest_md5((d), (len), (result))
435 /* out 16 bytes */
437 static void
438 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
440 int i;
441 unsigned char ibuff[64 + data_len];
442 unsigned char obuff[64 + 16];
444 if (key_len > 64)
445 key_len = 64;
447 for (i = 0; i < key_len; i++) {
448 ibuff[i] = key[i] ^ 0x36;
449 obuff[i] = key[i] ^ 0x5c;
451 for (i = key_len; i < 64; i++) {
452 ibuff[i] = 0x36;
453 obuff[i] = 0x5c;
456 memcpy(ibuff+64, data, data_len);
458 MD5 (ibuff, 64 + data_len, obuff+64);
459 MD5 (obuff, 64 + 16, result);
461 #define HMAC_MD5 HMACT64
464 /* out 16 bytes */
465 #define HMAC_MD5(key, key_len, data, data_len, result) \
466 sipe_digest_hmac_md5((key), (key_len), (data), (data_len), (result))
468 /* NTLM Core Methods */
470 static void
471 NONCE(unsigned char *buffer, int num)
473 int i;
474 for (i = 0; i < num; i++) {
475 buffer[i] = (rand() & 0xff);
479 #ifdef _SIPE_COMPILING_TESTS
480 static void
481 Z(unsigned char *buffer, int num)
483 memset(buffer, 0, num);
486 static void
487 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
489 /* "KGS!@#$%" */
490 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
491 unsigned char uppercase_password[14];
492 int i;
494 int len = strlen(password);
495 if (len > 14) {
496 len = 14;
499 // Uppercase password
500 for (i = 0; i < len; i++) {
501 uppercase_password[i] = g_ascii_toupper(password[i]);
504 // Zero the rest
505 for (; i < 14; i++) {
506 uppercase_password[i] = 0;
509 DES (uppercase_password, magic, result);
510 DES (uppercase_password + 7, magic, result + 8);
512 #endif
515 Define NTOWFv1(Passwd, User, UserDom) as
516 MD4(UNICODE(Passwd))
517 EndDefine
519 /* out 16 bytes */
520 static void
521 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
523 int len_u = 2 * strlen(password); // utf16 should not be more
524 unsigned char *unicode_password = g_malloc(len_u);
526 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
527 MD4 (unicode_password, len_u, result);
528 g_free(unicode_password);
532 Define NTOWFv2(Passwd, User, UserDom) as
533 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
534 EndDefine
536 /* out 16 bytes */
537 static void
538 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
540 unsigned char response_key_nt_v1 [16];
541 int len_user = user ? strlen(user) : 0;
542 int len_domain = domain ? strlen(domain) : 0;
543 int len_user_u = 2 * len_user; // utf16 should not be more
544 int len_domain_u = 2 * len_domain; // utf16 should not be more
545 unsigned char *user_upper = g_malloc(len_user + 1);
546 unsigned char *buff = g_malloc((len_user + len_domain)*2);
547 int i;
549 /* Uppercase user */
550 for (i = 0; i < len_user; i++) {
551 user_upper[i] = g_ascii_toupper(user[i]);
553 user_upper[len_user] = 0;
555 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
556 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
558 NTOWFv1(password, user, domain, response_key_nt_v1);
560 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
562 g_free(buff);
563 g_free(user_upper);
566 static void
567 compute_response(const guint32 neg_flags,
568 const unsigned char *response_key_nt,
569 const unsigned char *response_key_lm,
570 const guint8 *server_challenge,
571 const guint8 *client_challenge,
572 const guint64 time_val,
573 const guint8 *target_info,
574 int target_info_len,
575 unsigned char *lm_challenge_response,
576 unsigned char *nt_challenge_response,
577 unsigned char *session_base_key)
579 #ifdef _SIPE_COMPILING_TESTS
580 if (use_ntlm_v2)
582 #endif
584 Responserversion - The 1-byte response version. Currently set to 1.
585 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
586 Time - The 8-byte little-endian time in GMT.
587 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
588 ClientChallenge - The 8-byte challenge message generated by the client.
589 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
591 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
592 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
593 Time, //8bytes - 8
594 ClientChallenge, //8bytes - 16
595 Z(4), //4bytes - 24
596 ServerName, //variable - 28
597 Z(4)) //4bytes - 28+target_info_len
598 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
599 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
600 Set LmChallengeResponse to ConcatenationOf(
601 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
602 ClientChallenge )
603 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
604 EndDefine
606 guint8 tmp [16];
607 guint8 nt_proof_str [16];
609 /* client_challenge (8) & temp (temp_len) buff */
610 unsigned int temp_len = 8+8+8+4+target_info_len+4;
611 guint64 *temp2 = g_malloc0(8 + temp_len);
612 ((guint8 *) temp2)[8+0] = 1;
613 ((guint8 *) temp2)[8+1] = 1;
614 temp2[2] = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
615 memcpy(((guint8 *) temp2)+8+16, client_challenge, 8);
616 memcpy(((guint8 *) temp2)+8+28, target_info, target_info_len);
618 /* NTProofStr */
619 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
620 memcpy(temp2, server_challenge, 8);
621 HMAC_MD5(response_key_nt, 16, (guint8*)temp2, 8+temp_len, nt_proof_str);
623 /* NtChallengeResponse */
624 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
625 memcpy(nt_challenge_response, nt_proof_str, 16);
626 memcpy(nt_challenge_response+16, temp2+1, temp_len);
627 g_free(temp2);
629 /* SessionBaseKey */
630 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
631 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
633 /* lm_challenge_response */
634 memcpy(tmp, server_challenge, 8);
635 memcpy(tmp+8, client_challenge, 8);
636 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
637 memcpy(lm_challenge_response+16, client_challenge, 8);
639 #ifndef _SIPE_COMPILING_TESTS
640 /* Not used in NTLMv2 */
641 (void)neg_flags;
642 #else
644 else
646 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
647 // @TODO do not even reference nt_challenge_response
648 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
649 DESL (response_key_lm, server_challenge, lm_challenge_response);
650 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
651 unsigned char prehash [16];
652 unsigned char hash [16];
654 /* nt_challenge_response */
655 memcpy(prehash, server_challenge, 8);
656 memcpy(prehash + 8, client_challenge, 8);
657 MD5 (prehash, 16, hash);
658 DESL (response_key_nt, hash, nt_challenge_response);
660 /* lm_challenge_response */
661 memcpy(lm_challenge_response, client_challenge, 8);
662 Z (lm_challenge_response+8, 16);
663 } else {
664 DESL (response_key_nt, server_challenge, nt_challenge_response);
665 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
666 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
667 } else {
668 DESL (response_key_lm, server_challenge, lm_challenge_response);
672 /* Session Key */
673 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
675 #endif
678 static void
679 KXKEY ( guint32 flags,
680 const unsigned char * session_base_key,
681 const unsigned char * lm_challenge_resonse,
682 const guint8 * server_challenge, /* 8-bytes, nonce */
683 unsigned char * key_exchange_key)
685 #ifdef _SIPE_COMPILING_TESTS
686 if (use_ntlm_v2)
688 #else
689 /* Not used in NTLMv2 */
690 (void)flags;
691 (void)lm_challenge_resonse;
692 (void)server_challenge;
693 #endif
694 memcpy(key_exchange_key, session_base_key, 16);
695 #ifdef _SIPE_COMPILING_TESTS
697 else
699 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
700 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
701 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
702 EndDefine
704 guint8 tmp[16];
705 memcpy(tmp, server_challenge, 8);
706 memcpy(tmp+8, lm_challenge_resonse, 8);
707 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
708 } else {
709 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
710 memcpy(key_exchange_key, session_base_key, 16);
713 #endif
717 If (Mode equals "Client")
718 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
719 "session key to client-to-server signing key magic constant"))
720 Else
721 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
722 "session key to server-to-client signing key magic constant"))
723 Endif
725 static void
726 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
728 char * magic = client
729 ? "session key to client-to-server signing key magic constant"
730 : "session key to server-to-client signing key magic constant";
732 int len = strlen(magic) + 1;
733 unsigned char *md5_input = g_malloc(16 + len);
734 memcpy(md5_input, random_session_key, 16);
735 memcpy(md5_input + 16, magic, len);
737 MD5 (md5_input, len + 16, result);
738 g_free(md5_input);
742 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
743 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
744 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
745 Set SealKey to RandomSessionKey
746 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
747 Set SealKey to RandomSessionKey[0..6]
748 Else
749 Set SealKey to RandomSessionKey[0..4]
750 Endif
752 If (Mode equals "Client")
753 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
754 Else
755 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
756 Endif
758 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
759 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
760 Else
761 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
762 Endif
763 EndDefine
765 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
766 static void
767 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
769 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
771 char * magic = client
772 ? "session key to client-to-server sealing key magic constant"
773 : "session key to server-to-client sealing key magic constant";
775 int len = strlen(magic) + 1;
776 unsigned char *md5_input = g_malloc(16 + len);
777 int key_len;
779 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
780 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
781 key_len = 16;
782 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
783 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
784 key_len = 7;
785 } else {
786 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
787 key_len = 5;
790 memcpy(md5_input, random_session_key, key_len);
791 memcpy(md5_input + key_len, magic, len);
793 MD5 (md5_input, key_len + len, result);
794 g_free(md5_input);
796 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
798 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
799 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
800 memcpy(result, random_session_key, 7);
801 result[7] = 0xA0;
802 } else {
803 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
804 memcpy(result, random_session_key, 5);
805 result[5] = 0xE5;
806 result[6] = 0x38;
807 result[7] = 0xB0;
810 else
812 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
813 memcpy(result, random_session_key, 16);
818 = for Extended Session Security =
819 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
820 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
821 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
823 = if Extended Session Security is NOT negotiated =
824 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
825 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
826 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
827 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
829 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
831 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
832 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
834 /** MAC(Handle, SigningKey, SeqNum, Message) */
835 /* out 16 bytes */
836 static void
837 MAC (guint32 flags,
838 const char *buf,
839 unsigned int buf_len,
840 unsigned char *sign_key,
841 unsigned long sign_key_len,
842 unsigned char *seal_key,
843 unsigned long seal_key_len,
844 guint32 random_pad,
845 guint32 sequence,
846 guint32 *result)
848 guint32 *res_ptr;
850 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
852 Define MAC(Handle, SigningKey, SeqNum, Message) as
853 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
854 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
855 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
856 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
857 Set SeqNum to SeqNum + 1
858 EndDefine
860 /* If a key exchange key is negotiated
861 Define MAC(Handle, SigningKey, SeqNum, Message) as
862 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
863 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
864 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
865 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
866 Set SeqNum to SeqNum + 1
867 EndDefine
870 unsigned char seal_key_ [16];
871 guchar hmac[16];
872 guint32 *tmp = g_malloc(4 + buf_len);
874 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
875 RC4Init(Handle, SealingKey')
877 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
878 guint32 tmp2[4+1];
880 memcpy(tmp2, seal_key, seal_key_len);
881 tmp2[4] = GUINT32_TO_LE(sequence);
882 MD5 ((guchar *)tmp2, sizeof(tmp2), seal_key_);
883 } else {
884 memcpy(seal_key_, seal_key, seal_key_len);
887 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extented Session Security");
889 res_ptr = result;
890 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
891 res_ptr[3] = GUINT32_TO_LE(sequence);
893 res_ptr = tmp;
894 res_ptr[0] = GUINT32_TO_LE(sequence);
895 memcpy(tmp+1, buf, buf_len);
897 HMAC_MD5(sign_key, sign_key_len, (guchar *)tmp, 4 + buf_len, hmac);
898 g_free(tmp);
900 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
901 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
902 RC4K(seal_key_, seal_key_len, hmac, 8, (guchar *)(result+1));
903 } else {
904 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
905 memcpy(result+1, hmac, 8);
907 } else {
908 /* The content of the first 4 bytes is irrelevant */
909 guint32 crc = CRC32(buf, strlen(buf));
910 guint32 plaintext [] = {
911 GUINT32_TO_LE(0),
912 GUINT32_TO_LE(crc),
913 GUINT32_TO_LE(sequence)
914 }; // 4, 4, 4 bytes
916 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extented Session Security");
918 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, (guchar *)(result+1));
920 res_ptr = result;
921 // Highest four bytes are the Version
922 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
924 // Replace the first four bytes of the ciphertext with the random_pad
925 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
929 /* End Core NTLM Methods */
932 * @param flags (out) flags received from server
933 * @param server_challenge must be g_free()'d after use if requested
934 * @param target_info must be g_free()'d after use if requested
936 static void
937 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
938 guint32 *flags,
939 guchar **server_challenge, /* 8 bytes */
940 guint64 *time_val,
941 guchar **target_info,
942 int *target_info_len)
944 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
945 struct challenge_message *cmsg = (void *)in_buff.value;
946 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
948 /* server challenge (nonce) */
949 if (server_challenge) {
950 *server_challenge = g_memdup(cmsg->nonce, 8);
953 /* flags */
954 if (flags) {
955 *flags = host_flags;
958 /* target_info */
959 if (cmsg->target_info.len && cmsg->target_info.offset) {
960 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
961 void *av = content;
962 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
964 ALIGN_AV_LOOP_START
966 /* @since Vista */
967 case MsvAvTimestamp:
968 if (time_val) {
969 guint64 tmp;
971 /* to meet sparc's alignment requirement */
972 memcpy(&tmp, av_value, sizeof(tmp));
973 *time_val = GUINT64_FROM_LE(tmp);
975 break;
977 ALIGN_AV_LOOP_END;
979 if (target_info_len) {
980 *target_info_len = len;
982 if (target_info) {
983 *target_info = g_memdup(content, len);
989 * @param client_sign_key (out) must be g_free()'d after use
990 * @param server_sign_key (out) must be g_free()'d after use
991 * @param client_seal_key (out) must be g_free()'d after use
992 * @param server_seal_key (out) must be g_free()'d after use
993 * @param flags (in, out) negotiated flags
995 static sip_uint32
996 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
997 guchar **server_sign_key,
998 guchar **client_seal_key,
999 guchar **server_seal_key,
1000 const gchar *user,
1001 const gchar *password,
1002 const gchar *hostname,
1003 const gchar *domain,
1004 const guint8 *server_challenge, /* nonce */
1005 const guint64 time_val,
1006 const guint8 *target_info,
1007 int target_info_len,
1008 gboolean is_connection_based,
1009 SipSecBuffer *out_buff,
1010 guint32 *flags)
1012 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
1013 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1014 int ntlmssp_nt_resp_len =
1015 #ifdef _SIPE_COMPILING_TESTS
1016 use_ntlm_v2 ?
1017 #endif
1018 (16 + (32+target_info_len))
1019 #ifdef _SIPE_COMPILING_TESTS
1020 : NTLMSSP_LM_RESP_LEN
1021 #endif
1023 gsize msglen = sizeof(struct authenticate_message)
1024 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1025 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1026 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1027 struct authenticate_message *tmsg;
1028 char *tmp;
1029 guint32 offset;
1030 guint16 len;
1031 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1032 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1033 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1034 unsigned char *nt_challenge_response = g_malloc(ntlmssp_nt_resp_len); /* variable or 24 */
1035 unsigned char session_base_key [16];
1036 unsigned char key_exchange_key [16];
1037 unsigned char exported_session_key[16];
1038 unsigned char encrypted_random_session_key [16];
1039 unsigned char key [16];
1040 unsigned char client_challenge [8];
1041 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1043 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1044 !(is_connection_based || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)) ||
1045 !nt_challenge_response) /* Coverity thinks ntlmssp_nt_resp_len could be 0 */
1047 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1048 g_free(nt_challenge_response);
1049 return SIP_SEC_E_INTERNAL_ERROR;
1052 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1053 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1056 tmsg = g_malloc0(msglen);
1058 NONCE (client_challenge, 8);
1060 #ifdef _SIPE_COMPILING_TESTS
1061 memcpy(client_challenge, test_client_challenge, 8);
1062 time_vl = test_time_val ? test_time_val : time_vl;
1064 if (use_ntlm_v2) {
1066 #endif
1067 NTOWFv2 (password, user, domain, response_key_nt);
1068 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1069 #ifdef _SIPE_COMPILING_TESTS
1070 } else {
1071 NTOWFv1 (password, user, domain, response_key_nt);
1072 LMOWFv1 (password, user, domain, response_key_lm);
1074 #endif
1076 compute_response(neg_flags,
1077 response_key_nt,
1078 response_key_lm,
1079 server_challenge,
1080 client_challenge,
1081 time_vl,
1082 target_info,
1083 target_info_len,
1084 lm_challenge_response, /* out */
1085 nt_challenge_response, /* out */
1086 session_base_key); /* out */
1088 /* same as session_base_key for
1089 * - NTLNv1 w/o Ext.Sess.Sec and
1090 * - NTLMv2
1092 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1094 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1095 NONCE (exported_session_key, 16); // random master key
1096 #ifdef _SIPE_COMPILING_TESTS
1097 memcpy(exported_session_key, test_random_session_key, 16);
1098 #endif
1099 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1100 } else {
1101 memcpy(exported_session_key, key_exchange_key, 16);
1104 tmp = buff_to_hex_str(exported_session_key, 16);
1105 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp);
1106 g_free(tmp);
1108 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1109 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1111 /* p.46
1112 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1113 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1115 SIGNKEY(exported_session_key, TRUE, key);
1116 *client_sign_key = g_memdup(key, 16);
1117 SIGNKEY(exported_session_key, FALSE, key);
1118 *server_sign_key = g_memdup(key, 16);
1119 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1120 *client_seal_key = g_memdup(key, 16);
1121 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1122 *server_seal_key = g_memdup(key, 16);
1125 /* @TODO: */
1126 /* @since Vista
1127 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1128 the client SHOULD provide a MIC:
1129 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1130 - then in the Value field, set bit 0x2 to 1.
1131 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1132 and the Value field bit 0x2 to 1.
1133 - Populate the MIC field with the MIC.
1136 /* Connection-oriented:
1137 Set MIC to HMAC_MD5(ExportedSessionKey,
1138 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1139 Connectionless:
1140 Set MIC to HMAC_MD5(ExportedSessionKey,
1141 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1144 /* on the server-side:
1145 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1146 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1147 Set MIC to HMAC_MD5(ExportedSessionKey,
1148 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1149 Else
1150 Set ExportedSessionKey to KeyExchangeKey
1151 Set MIC to HMAC_MD5(KeyExchangeKey,
1152 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1153 =====
1154 @since Vista
1155 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1156 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1157 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1158 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1159 an AV_PAIR structure whose two fields:
1160 - AvId == MsvAvFlags
1161 - Value bit 0x2 == 1
1162 @supported NT, 2000, XP
1163 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1164 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1165 the server time, then the server SHOULD return a failure.
1167 Connectionless:
1168 Set MIC to HMAC_MD5(ResponseKeyNT,
1169 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1172 /* authenticate message initialization */
1173 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1174 tmsg->type = GUINT32_TO_LE(3);
1176 /* Initial offset */
1177 offset = sizeof(struct authenticate_message);
1178 tmp = ((char*) tmsg) + offset;
1180 #define _FILL_SMB_HEADER(header) \
1181 tmsg->header.offset = GUINT32_TO_LE(offset); \
1182 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1183 tmp += len; \
1184 offset += len
1185 #define _APPEND_STRING(header, src) \
1186 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1187 _FILL_SMB_HEADER(header)
1188 #define _APPEND_DATA(header, src, srclen) \
1189 len = (srclen); \
1190 memcpy(tmp, (src), len); \
1191 _FILL_SMB_HEADER(header)
1193 /* Domain */
1194 _APPEND_STRING(domain, domain);
1196 /* User */
1197 _APPEND_STRING(user, user);
1199 /* Host */
1200 _APPEND_STRING(host, hostname);
1202 /* LM */
1203 /* @since Windows 7
1204 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1205 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1206 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1208 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1210 /* NT */
1211 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1213 /* Session Key */
1214 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1216 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1218 else
1220 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1221 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1224 /* Version */
1225 #ifdef _SIPE_COMPILING_TESTS
1226 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1227 #else
1228 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1229 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1230 tmsg->ver.product_minor_version = 1;
1231 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1232 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1234 #endif
1236 /* Set Negotiate Flags */
1237 tmsg->flags = GUINT32_TO_LE(neg_flags);
1238 *flags = neg_flags;
1240 out_buff->value = (guint8 *)tmsg;
1241 out_buff->length = msglen;
1243 g_free(nt_challenge_response);
1245 return SIP_SEC_E_OK;
1249 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1251 static void
1252 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1254 guint32 offset;
1255 guint16 len;
1256 int msglen = sizeof(struct negotiate_message);
1257 struct negotiate_message *tmsg = g_malloc0(msglen);
1259 /* negotiate message initialization */
1260 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1261 tmsg->type = GUINT32_TO_LE(1);
1263 /* Set Negotiate Flags */
1264 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1266 /* Domain */
1267 offset = sizeof(struct negotiate_message);
1268 tmsg->domain.offset = GUINT32_TO_LE(offset);
1269 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1271 /* Host */
1272 offset += len;
1273 tmsg->host.offset = GUINT32_TO_LE(offset);
1274 tmsg->host.len = tmsg->host.maxlen = len = 0;
1276 /* Version */
1277 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1278 tmsg->ver.product_minor_version = 1;
1279 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1280 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1282 out_buff->value = (guint8 *)tmsg;
1283 out_buff->length = msglen;
1286 static void
1287 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1288 const char *msg,
1289 guint32 random_pad,
1290 unsigned char *sign_key,
1291 unsigned char *seal_key,
1292 guint32 *result)
1294 char *res;
1296 MAC(flags, msg, strlen(msg), sign_key, 16, seal_key, 16, random_pad, 100, result);
1298 res = buff_to_hex_str((guint8 *)result, 16);
1299 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res);
1300 g_free(res);
1304 /* Describe NTLM messages functions */
1306 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1307 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1309 static gchar *
1310 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1312 GString* str = g_string_new(NULL);
1314 flags = GUINT32_FROM_LE(flags);
1316 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1317 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1318 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1319 APPEND_NEG_FLAG(str, flags, r9, "r9");
1320 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1321 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1322 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1323 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1324 APPEND_NEG_FLAG(str, flags, r8, "r8");
1325 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1326 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1327 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1328 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1329 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1330 APPEND_NEG_FLAG(str, flags, r7, "r7");
1331 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1332 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1333 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1334 APPEND_NEG_FLAG(str, flags, r6, "r6");
1335 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1336 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1337 APPEND_NEG_FLAG(str, flags, r5, "r5");
1338 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1339 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1340 APPEND_NEG_FLAG(str, flags, r4, "r4");
1341 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1342 APPEND_NEG_FLAG(str, flags, r3, "r3");
1343 APPEND_NEG_FLAG(str, flags, r2, "r2");
1344 APPEND_NEG_FLAG(str, flags, r1, "r1");
1345 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1346 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1347 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1349 return g_string_free(str, FALSE);
1352 static gchar *
1353 sip_sec_ntlm_describe_version(struct version *ver) {
1354 GString* str = g_string_new(NULL);
1355 gchar *ver_desc = "";
1356 gchar *ntlm_revision_desc = "";
1358 if (ver->product_major_version == 6) {
1359 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1360 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1361 ver_desc = "Windows Server 2003";
1362 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1363 ver_desc = "Windows XP SP2";
1366 if (ver->ntlm_revision_current == 0x0F) {
1367 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1368 } else if (ver->ntlm_revision_current == 0x0A) {
1369 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1372 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1373 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1374 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1376 return g_string_free(str, FALSE);
1379 static gchar *
1380 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1381 const char* name)
1383 GString* str = g_string_new(NULL);
1385 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1386 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1387 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1389 return g_string_free(str, FALSE);
1392 static gchar *
1393 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1395 GString* str = g_string_new(NULL);
1396 char *tmp;
1398 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1399 g_free(tmp);
1401 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1402 g_free(tmp);
1404 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1405 g_free(tmp);
1407 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1408 g_string_append(str, tmp);
1409 g_free(tmp);
1411 if (cmsg->domain.len && cmsg->domain.offset) {
1412 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1413 g_string_append_printf(str, "\tdomain: %s\n", domain);
1414 g_free(domain);
1417 if (cmsg->host.len && cmsg->host.offset) {
1418 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1419 g_string_append_printf(str, "\thost: %s\n", host);
1420 g_free(host);
1423 return g_string_free(str, FALSE);
1426 static void
1427 describe_av_pairs(GString* str, const void *av)
1429 #define AV_DESC(av_name) \
1431 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1432 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1433 g_free(tmp); \
1436 ALIGN_AV_LOOP_START
1438 case MsvAvNbComputerName:
1439 AV_DESC("MsvAvNbComputerName");
1440 break;
1441 case MsvAvNbDomainName:
1442 AV_DESC("MsvAvNbDomainName");
1443 break;
1444 case MsvAvDnsComputerName:
1445 AV_DESC("MsvAvDnsComputerName");
1446 break;
1447 case MsvAvDnsDomainName:
1448 AV_DESC("MsvAvDnsDomainName");
1449 break;
1450 case MsvAvDnsTreeName:
1451 AV_DESC("MsvAvDnsTreeName");
1452 break;
1453 case MsvAvFlags:
1455 guint32 flags;
1457 /* to meet sparc's alignment requirement */
1458 memcpy(&flags, av_value, sizeof(guint32));
1459 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1461 break;
1462 case MsvAvTimestamp:
1464 char *tmp;
1465 guint64 time_val;
1466 time_t time_t_val;
1468 /* to meet sparc's alignment requirement */
1469 memcpy(&time_val, av_value, sizeof(time_val));
1470 time_t_val = TIME_VAL_TO_T(time_val);
1472 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1473 asctime(gmtime(&time_t_val)));
1474 g_free(tmp);
1476 break;
1477 case MsAvRestrictions:
1478 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1479 break;
1480 case MsvAvTargetName:
1481 AV_DESC("MsvAvTargetName");
1482 break;
1483 case MsvChannelBindings:
1484 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1485 break;
1487 ALIGN_AV_LOOP_END;
1490 static gchar *
1491 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1493 GString* str = g_string_new(NULL);
1494 char *tmp;
1495 gsize value_len;
1496 guint8 *value;
1498 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1499 g_free(tmp);
1501 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1502 g_free(tmp);
1504 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1505 g_free(tmp);
1507 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1508 g_free(tmp);
1510 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1511 g_free(tmp);
1513 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1514 g_free(tmp);
1516 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1517 g_free(tmp);
1519 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1520 g_string_append(str, tmp);
1521 g_free(tmp);
1523 /* mic */
1524 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1525 //g_free(tmp);
1527 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1528 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1529 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1530 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1531 g_free(tmp);
1534 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1535 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1536 int nt_resp_len = nt_resp_len_full;
1538 value_len = nt_resp_len_full;
1539 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1540 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1541 g_free(tmp);
1543 if (nt_resp_len > 24) { /* NTLMv2 */
1544 nt_resp_len = 16;
1547 value_len = nt_resp_len;
1548 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1549 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1550 g_free(tmp);
1552 if (nt_resp_len_full > 24) { /* NTLMv2 */
1553 /* Work around Debian/x86_64 compiler bug */
1554 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1555 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1556 const guint8 *temp = (guint8 *)cmsg + offset;
1557 const guint response_version = temp[0];
1558 const guint hi_response_version = temp[1];
1559 const guint8 *client_challenge = temp + 16;
1560 const guint8 *target_info = temp + 28;
1561 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1562 guint64 time_val;
1563 time_t time_t_val;
1564 char *tmp;
1566 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1567 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1568 g_free(tmp);
1570 /* This is not int64 aligned on sparc */
1571 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1572 time_t_val = TIME_VAL_TO_T(time_val);
1574 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1575 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1577 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1578 asctime(gmtime(&time_t_val)));
1579 g_free(tmp);
1581 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1582 g_free(tmp);
1584 describe_av_pairs(str, target_info);
1586 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1590 if (cmsg->domain.len && cmsg->domain.offset) {
1591 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1592 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1593 g_free(domain);
1596 if (cmsg->user.len && cmsg->user.offset) {
1597 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1598 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1599 g_free(user);
1602 if (cmsg->host.len && cmsg->host.offset) {
1603 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1604 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1605 g_free(host);
1608 if (cmsg->session_key.len && cmsg->session_key.offset) {
1609 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1610 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1611 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1612 g_free(tmp);
1615 return g_string_free(str, FALSE);
1618 static gchar *
1619 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1621 GString* str = g_string_new(NULL);
1622 char *tmp;
1624 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1625 g_free(tmp);
1627 /* nonce (server_challenge) */
1628 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1629 g_free(tmp);
1631 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1632 g_free(tmp);
1634 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1635 g_free(tmp);
1637 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1638 g_free(tmp);
1640 if (cmsg->target_name.len && cmsg->target_name.offset) {
1641 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1642 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1643 g_free(target_name);
1646 if (cmsg->target_info.len && cmsg->target_info.offset) {
1647 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1648 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1650 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1651 g_free(tmp);
1653 describe_av_pairs(str, target_info);
1656 return g_string_free(str, FALSE);
1659 static void
1660 sip_sec_ntlm_message_describe(SipSecBuffer *buff,
1661 const gchar *type)
1663 struct ntlm_message *msg;
1664 gchar *res = NULL;
1666 if (buff->length == 0 || buff->value == NULL || buff->length < 12) return;
1668 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1669 msg = (void *)buff->value;
1670 if(!sipe_strequal("NTLMSSP", (char*)msg)) return;
1672 switch (GUINT32_FROM_LE(msg->type)) {
1673 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1674 break;
1675 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1676 break;
1677 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1678 break;
1681 SIPE_DEBUG_INFO("sip_sec_ntlm_message_describe: %s message is:\n%s",
1682 type, res);
1683 g_free(res);
1686 /* sip-sec-mech.h API implementation for NTLM */
1688 /* Security context for NTLM */
1689 typedef struct _context_ntlm {
1690 struct sip_sec_context common;
1691 char* domain;
1692 char *username;
1693 char *password;
1694 int step;
1695 guchar *client_sign_key;
1696 guchar *server_sign_key;
1697 guchar *client_seal_key;
1698 guchar *server_seal_key;
1699 guint32 flags;
1700 } *context_ntlm;
1703 static sip_uint32
1704 sip_sec_acquire_cred__ntlm(SipSecContext context,
1705 const char *domain,
1706 const char *username,
1707 const char *password)
1709 context_ntlm ctx = (context_ntlm)context;
1711 /* NTLM requires a username & password. Domain may be empty */
1712 if (!domain || is_empty(username) || is_empty(password))
1713 return SIP_SEC_E_INTERNAL_ERROR;
1715 ctx->domain = g_strdup(domain);
1716 ctx->username = g_strdup(username);
1717 ctx->password = g_strdup(password);
1719 return SIP_SEC_E_OK;
1722 static sip_uint32
1723 sip_sec_init_sec_context__ntlm(SipSecContext context,
1724 SipSecBuffer in_buff,
1725 SipSecBuffer *out_buff,
1726 SIPE_UNUSED_PARAMETER const char *service_name)
1728 context_ntlm ctx = (context_ntlm) context;
1730 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
1732 ctx->step++;
1733 if (ctx->step == 1) {
1734 if (!context->is_connection_based) {
1735 out_buff->length = 0;
1736 out_buff->value = NULL;
1737 } else {
1738 sip_sec_ntlm_gen_negotiate(out_buff);
1739 sip_sec_ntlm_message_describe(out_buff, "Negotiate");
1741 return SIP_SEC_I_CONTINUE_NEEDED;
1743 } else {
1744 sip_uint32 res;
1745 guchar *client_sign_key = NULL;
1746 guchar *server_sign_key = NULL;
1747 guchar *client_seal_key = NULL;
1748 guchar *server_seal_key = NULL;
1749 guchar *server_challenge = NULL;
1750 guint64 time_val = 0;
1751 guchar *target_info = NULL;
1752 int target_info_len = 0;
1753 guint32 flags;
1754 gchar *tmp;
1756 if (!in_buff.value || !in_buff.length) {
1757 return SIP_SEC_E_INTERNAL_ERROR;
1760 sip_sec_ntlm_message_describe(&in_buff, "Challenge");
1762 sip_sec_ntlm_parse_challenge(in_buff,
1763 &flags,
1764 &server_challenge, /* 8 bytes */
1765 &time_val,
1766 &target_info,
1767 &target_info_len);
1769 res = sip_sec_ntlm_gen_authenticate(
1770 &client_sign_key,
1771 &server_sign_key,
1772 &client_seal_key,
1773 &server_seal_key,
1774 ctx->username,
1775 ctx->password,
1776 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1777 ctx->domain,
1778 server_challenge,
1779 time_val,
1780 target_info,
1781 target_info_len,
1782 context->is_connection_based,
1783 out_buff,
1784 &flags);
1785 g_free(server_challenge);
1786 g_free(target_info);
1787 g_free(tmp);
1789 if (res != SIP_SEC_E_OK) {
1790 g_free(client_sign_key);
1791 g_free(server_sign_key);
1792 g_free(client_seal_key);
1793 g_free(server_seal_key);
1794 return res;
1797 sip_sec_ntlm_message_describe(out_buff, "Authenticate");
1799 g_free(ctx->client_sign_key);
1800 ctx->client_sign_key = client_sign_key;
1802 g_free(ctx->server_sign_key);
1803 ctx->server_sign_key = server_sign_key;
1805 g_free(ctx->client_seal_key);
1806 ctx->client_seal_key = client_seal_key;
1808 g_free(ctx->server_seal_key);
1809 ctx->server_seal_key = server_seal_key;
1811 ctx->flags = flags;
1812 return SIP_SEC_E_OK;
1817 * @param message a NULL terminated string to sign
1820 static sip_uint32
1821 sip_sec_make_signature__ntlm(SipSecContext context,
1822 const char *message,
1823 SipSecBuffer *signature)
1825 signature->length = 16;
1826 signature->value = g_malloc0(16);
1828 /* FIXME? We always use a random_pad of 0 */
1829 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1830 message,
1832 ((context_ntlm) context)->client_sign_key,
1833 ((context_ntlm) context)->client_seal_key,
1834 /* SipSecBuffer.value is g_malloc()'d:
1835 * use (void *) to remove guint8 alignment
1837 (void *)signature->value);
1838 return SIP_SEC_E_OK;
1842 * @param message a NULL terminated string to check signature of
1843 * @return SIP_SEC_E_OK on success
1845 static sip_uint32
1846 sip_sec_verify_signature__ntlm(SipSecContext context,
1847 const char *message,
1848 SipSecBuffer signature)
1850 guint32 mac[4];
1851 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1852 guint32 random_pad = GUINT32_FROM_LE(((guint32 *)((void *)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 guint 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_to_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: