core cleanup: 6 more modules are purple free
[siplcs.git] / src / core / sip-sec-ntlm.c
blob0aa4b5d3cd30b017bd53e0b11266085a18152b6a
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2009, 2010 pier11 <pier11@operamail.com>
7 * Copyright (C) 2008 Novell, Inc.
8 * Modify 2007, Anibal Avelar <avelar@gmail.com>
9 * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
11 * Implemented with reference to the follow documentation:
12 * - http://davenport.sourceforge.net/ntlm.html
13 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
14 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * Byte order policy:
34 * - NTLM messages (byte streams) should be in LE (Little-Endian) byte order.
35 * - internal int16, int32, int64 should contain proper values.
36 * For example: 01 00 00 00 LE should be translated to (int32)1
37 * - When reading/writing from/to NTLM message appropriate conversion should
38 * be taken to properly present integer values. glib's "Byte Order Macros"
39 * should be used for that, for example GUINT32_FROM_LE
41 * NOTE: The Byte Order Macros can have side effects!
42 * Do *NOT* make any calculations inside the macros!
44 * - All calculations should be made in dedicated local variables (system-endian),
45 * not in NTLM (LE) structures.
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
52 #include <glib.h>
54 #ifdef HAVE_LANGINFO_CODESET
55 #include <langinfo.h>
56 #endif /* HAVE_LANGINFO_CODESET */
58 #include "cipher.h"
59 #include "debug.h"
61 #include "sipe-common.h"
62 #include "sip-sec.h"
63 #include "sip-sec-mech.h"
64 #include "sip-sec-ntlm.h"
65 #include "sipe-utils.h"
67 /* [MS-NLMP] */
68 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
69 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
70 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
71 #define r9 0x00000008 /* r9 */
72 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
73 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
74 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
75 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
76 #define r8 0x00000100 /* r8 */
77 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
78 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
79 #define anonymous 0x00000800 /* J */
80 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
81 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
82 #define r7 0x00004000 /* r7 */
83 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
84 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
85 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
86 #define r6 0x00040000 /* r6 */
87 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
88 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
89 #define r5 0x00200000 /* r5 */
90 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
91 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
92 #define r4 0x01000000 /* r4 */
93 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
94 #define r3 0x04000000 /* r3 */
95 #define r2 0x08000000 /* r2 */
96 #define r1 0x10000000 /* r1 */
97 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
98 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
99 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
101 /* AvId */
102 #define MsvAvEOL 0
103 #define MsvAvNbComputerName 1
104 #define MsvAvNbDomainName 2
105 #define MsvAvDnsComputerName 3
106 #define MsvAvDnsDomainName 4
107 /** @since Windows XP */
108 #define MsvAvDnsTreeName 5
109 /** @since Windows XP */
110 #define MsvAvFlags 6
111 /** @since Windows Vista */
112 #define MsvAvTimestamp 7
113 /** @since Windows Vista */
114 #define MsAvRestrictions 8
115 /** @since Windows 7 */
116 #define MsvAvTargetName 9
117 /** @since Windows 7 */
118 #define MsvChannelBindings 10
120 /* time_t <-> (guint64) time_val conversion */
121 #define TIME_VAL_FACTOR 10000000
122 #define TIME_VAL_OFFSET 116444736000000000LL
123 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
124 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
126 /* 8 bytes */
127 /* LE (Little Endian) byte order */
128 struct version {
129 guint8 product_major_version;
130 guint8 product_minor_version;
131 guint16 product_build;
132 guint8 zero2[3];
133 guint8 ntlm_revision_current;
137 * NTLMv1 is no longer used except in tests. R.I.P.
139 * It remains in this file only for documentary purposes
141 #ifdef _SIPE_COMPILING_TESTS
142 static gboolean use_ntlm_v2 = FALSE;
144 guint64 test_time_val = 0; /* actual time in implementation */
145 guchar test_client_challenge [8]; /* random in implementation */
146 guchar test_random_session_key[16]; /* random in implementation */
147 struct version test_version; /* hard-coded in implementation */
148 #endif
150 /* Minimum set of common features we need to work. */
151 /* we operate in NTLMv2 mode */
152 #define NEGOTIATE_FLAGS_COMMON_MIN \
153 ( NTLMSSP_NEGOTIATE_UNICODE | \
154 NTLMSSP_NEGOTIATE_NTLM | \
155 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
156 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
157 NTLMSSP_NEGOTIATE_TARGET_INFO \
160 /* Negotiate flags for connection-based mode. Nice to have but optional. */
161 #define NEGOTIATE_FLAGS_CONN \
162 ( NEGOTIATE_FLAGS_COMMON_MIN | \
163 NTLMSSP_NEGOTIATE_VERSION | \
164 NTLMSSP_NEGOTIATE_128 | \
165 NTLMSSP_NEGOTIATE_56 | \
166 NTLMSSP_REQUEST_TARGET \
169 /* Extra negotiate flags required in connectionless NTLM */
170 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
171 ( NTLMSSP_NEGOTIATE_SIGN | \
172 NTLMSSP_NEGOTIATE_DATAGRAM | \
173 NTLMSSP_NEGOTIATE_IDENTIFY | \
174 NTLMSSP_NEGOTIATE_KEY_EXCH \
177 /* Negotiate flags required in connectionless NTLM */
178 #define NEGOTIATE_FLAGS_CONNLESS \
179 ( NEGOTIATE_FLAGS_CONN | \
180 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
183 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
184 #define NTLMSSP_LM_RESP_LEN 24
185 #define NTLMSSP_SESSION_KEY_LEN 16
186 #define MD4_DIGEST_LEN 16
187 #define MD5_DIGEST_LEN 16
189 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
191 /* 4 bytes */
192 /* LE (Little Endian) byte order */
193 struct av_pair {
194 guint16 av_id;
195 guint16 av_len;
196 /* value */
199 /* to meet sparc's alignment requirement */
200 #define ALIGN_AV \
201 memcpy(&av_aligned, av, sizeof(av_aligned)); \
202 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
203 av_len = GUINT16_FROM_LE(av_aligned.av_len)
204 #define ALIGN_AV_LOOP_START \
205 struct av_pair av_aligned; \
206 guint16 av_id; \
207 guint16 av_len; \
208 ALIGN_AV; \
209 while (av_id != MsvAvEOL) { \
210 gchar *av_value = ((gchar *)av) + \
211 sizeof(struct av_pair); \
212 switch (av_id)
213 #define ALIGN_AV_LOOP_END \
214 av = av_value + av_len; \
215 ALIGN_AV; \
218 /* 8 bytes */
219 /* LE (Little Endian) byte order */
220 struct smb_header {
221 guint16 len;
222 guint16 maxlen;
223 guint32 offset;
226 /* LE (Little Endian) byte order */
227 struct ntlm_message {
228 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
229 guint32 type; /* 0x00000003 */
232 /* LE (Little Endian) byte order */
233 struct negotiate_message {
234 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
235 guint32 type; /* 0x00000001 */
236 guint32 flags; /* 0xb203 */
237 struct smb_header domain;
238 struct smb_header host;
239 struct version ver;
240 /* payload
241 * - DomainName (always ASCII)
242 * - WorkstationName (always ASCII)
246 /* LE (Little Endian) byte order */
247 struct challenge_message {
248 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
249 guint32 type; /* 0x00000002 */
250 struct smb_header target_name;
251 guint32 flags; /* 0x8201 */
252 guint8 nonce[8];
253 guint8 zero1[8];
254 struct smb_header target_info;
255 struct version ver;
256 /* payload
257 * - TargetName (negotiated encoding)
258 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
262 /* LE (Little Endian) byte order */
263 struct authenticate_message {
264 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
265 guint32 type; /* 0x00000003 */
266 /** LmChallengeResponseFields */
267 struct smb_header lm_resp;
268 /** NtChallengeResponseFields */
269 struct smb_header nt_resp;
270 /** DomainNameFields */
271 struct smb_header domain;
272 /** UserNameFields */
273 struct smb_header user;
274 /** WorkstationFields */
275 struct smb_header host;
276 /** EncryptedRandomSessionKeyFields */
277 struct smb_header session_key;
278 guint32 flags;
279 struct version ver;
280 //guint8 mic[16];
281 /* payload
282 * - LmChallengeResponse
283 * - NtChallengeResponse
284 * - DomainName (negotiated encoding)
285 * - UserName (negotiated encoding)
286 * - Workstation (negotiated encoding)
287 * - EncryptedRandomSessionKey
291 #ifndef HAVE_LANGINFO_CODESET
292 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
293 #endif
295 /* Private Methods */
297 /* Utility Functions */
298 static GIConv convert_from_utf16le = (GIConv)-1;
299 static GIConv convert_to_utf16le = (GIConv)-1;
301 static gsize
302 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
304 gsize inbytes = strlen(source);
305 gsize outbytes = remlen;
306 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
307 return(remlen - outbytes);
310 /* UTF-16LE to native encoding
311 * Must be g_free'd after use */
312 static gchar *
313 unicode_strconvcopy_back(const gchar *source, gsize len)
315 gsize outbytes = 2 * len;
316 gchar *dest = g_new0(gchar, outbytes + 1);
317 gchar *outbuf = dest;
318 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
319 return dest;
322 /* crc32 source copy from gg's common.c */
323 static guint32 crc32_table[256];
324 static int crc32_initialized = 0;
326 static void crc32_make_table()
328 guint32 h = 1;
329 unsigned int i, j;
331 memset(crc32_table, 0, sizeof(crc32_table));
333 for (i = 128; i; i >>= 1) {
334 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
336 for (j = 0; j < 256; j += 2 * i)
337 crc32_table[i + j] = crc32_table[j] ^ h;
340 crc32_initialized = 1;
343 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
345 if (!crc32_initialized)
346 crc32_make_table();
348 if (!buf || len < 0)
349 return crc;
351 crc ^= 0xffffffffL;
353 while (len--)
354 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
356 return crc ^ 0xffffffffL;
359 static guint32
360 CRC32 (const char *msg, int len)
362 guint32 crc = 0L;
363 crc = crc32(crc, (guint8 *) msg, len);
364 return crc;
367 /* Cyphers */
369 #ifdef _SIPE_COMPILING_TESTS
370 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
372 key[0] = key_56[0];
373 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
374 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
375 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
376 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
377 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
378 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
379 key[7] = (key_56[6] << 1) & 0xFF;
382 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
384 PurpleCipher *cipher;
385 PurpleCipherContext *context;
386 size_t outlen;
388 cipher = purple_ciphers_find_cipher("des");
389 context = purple_cipher_context_new(cipher, NULL);
390 purple_cipher_context_set_key(context, (guchar*)key);
391 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
392 purple_cipher_context_destroy(context);
395 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
396 static void
397 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
399 unsigned char key[8];
400 setup_des_key(k, key);
401 des_ecb_encrypt(d, results, key);
404 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
405 static void
406 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
408 unsigned char keys[21];
410 /* Copy the first 16 bytes */
411 memcpy(keys, k, 16);
413 /* Zero out the last 5 bytes of the key */
414 memset(keys + 16, 0, 5);
416 DES(keys, d, results);
417 DES(keys + 7, d, results + 8);
418 DES(keys + 14, d, results + 16);
420 #endif
422 static void
423 RC4K (const unsigned char * k, unsigned long key_len, const unsigned char * d, int len, unsigned char * result)
425 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
426 purple_cipher_context_set_option(context, "key_len", (gpointer)key_len);
427 purple_cipher_context_set_key(context, k);
428 purple_cipher_context_encrypt(context, (const guchar *)d, len, result, NULL);
429 purple_cipher_context_destroy(context);
432 /* out 16 bytes */
433 static void
434 MD4 (const unsigned char * d, int len, unsigned char * result)
436 PurpleCipher * cipher = purple_ciphers_find_cipher("md4");
437 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
438 purple_cipher_context_append(context, (guchar*)d, len);
439 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
440 purple_cipher_context_destroy(context);
443 /* out 16 bytes */
444 static void
445 MD5 (const unsigned char * d, int len, unsigned char * result)
447 PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
448 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
449 purple_cipher_context_append(context, (guchar*)d, len);
450 purple_cipher_context_digest(context, MD5_DIGEST_LEN, (guchar*)result, NULL);
451 purple_cipher_context_destroy(context);
454 /* out 16 bytes */
456 static void
457 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
459 int i;
460 unsigned char ibuff[64 + data_len];
461 unsigned char obuff[64 + 16];
463 if (key_len > 64)
464 key_len = 64;
466 for (i = 0; i < key_len; i++) {
467 ibuff[i] = key[i] ^ 0x36;
468 obuff[i] = key[i] ^ 0x5c;
470 for (i = key_len; i < 64; i++) {
471 ibuff[i] = 0x36;
472 obuff[i] = 0x5c;
475 memcpy(ibuff+64, data, data_len);
477 MD5 (ibuff, 64 + data_len, obuff+64);
478 MD5 (obuff, 64 + 16, result);
480 #define HMAC_MD5 HMACT64
483 /* out 16 bytes */
484 static void
485 HMAC_MD5 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
487 PurpleCipher *cipher = purple_ciphers_find_cipher("hmac");
488 PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL);
490 purple_cipher_context_set_option(context, "hash", "md5");
491 purple_cipher_context_set_key_with_len(context, (guchar *)key, (key_len));
493 purple_cipher_context_append(context, (guchar *)data, data_len);
494 purple_cipher_context_digest(context, 16, (guchar*)result, NULL);
495 purple_cipher_context_destroy(context);
498 /* NTLM Core Methods */
500 static void
501 NONCE(unsigned char *buffer, int num)
503 int i;
504 for (i = 0; i < num; i++) {
505 buffer[i] = (rand() & 0xff);
509 #ifdef _SIPE_COMPILING_TESTS
510 static void
511 Z(unsigned char *buffer, int num)
513 memset(buffer, 0, num);
516 static void
517 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
519 /* "KGS!@#$%" */
520 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
521 unsigned char uppercase_password[14];
522 int i;
524 int len = strlen(password);
525 if (len > 14) {
526 len = 14;
529 // Uppercase password
530 for (i = 0; i < len; i++) {
531 uppercase_password[i] = g_ascii_toupper(password[i]);
534 // Zero the rest
535 for (; i < 14; i++) {
536 uppercase_password[i] = 0;
539 DES (uppercase_password, magic, result);
540 DES (uppercase_password + 7, magic, result + 8);
542 #endif
545 Define NTOWFv1(Passwd, User, UserDom) as
546 MD4(UNICODE(Passwd))
547 EndDefine
549 /* out 16 bytes */
550 static void
551 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
553 int len_u = 2 * strlen(password); // utf16 should not be more
554 unsigned char unicode_password[len_u];
556 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
557 MD4 (unicode_password, len_u, result);
561 Define NTOWFv2(Passwd, User, UserDom) as
562 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
563 EndDefine
565 /* out 16 bytes */
566 void
567 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
569 unsigned char response_key_nt_v1 [16];
570 int len_user = user ? strlen(user) : 0;
571 int len_domain = domain ? strlen(domain) : 0;
572 unsigned char user_upper[len_user + 1];
573 int len_user_u = 2 * len_user; // utf16 should not be more
574 int len_domain_u = 2 * len_domain; // utf16 should not be more
575 unsigned char buff[(len_user + len_domain)*2];
576 int i;
578 /* Uppercase user */
579 for (i = 0; i < len_user; i++) {
580 user_upper[i] = g_ascii_toupper(user[i]);
582 user_upper[len_user] = 0;
584 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
585 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
587 NTOWFv1(password, user, domain, response_key_nt_v1);
589 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
592 static void
593 compute_response(const guint32 neg_flags,
594 const unsigned char *response_key_nt,
595 const unsigned char *response_key_lm,
596 const guint8 *server_challenge,
597 const guint8 *client_challenge,
598 const guint64 time_val,
599 const guint8 *target_info,
600 int target_info_len,
601 unsigned char *lm_challenge_response,
602 unsigned char *nt_challenge_response,
603 unsigned char *session_base_key)
605 #ifdef _SIPE_COMPILING_TESTS
606 if (use_ntlm_v2)
608 #endif
610 Responserversion - The 1-byte response version. Currently set to 1.
611 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
612 Time - The 8-byte little-endian time in GMT.
613 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
614 ClientChallenge - The 8-byte challenge message generated by the client.
615 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
617 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
618 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
619 Time, //8bytes - 8
620 ClientChallenge, //8bytes - 16
621 Z(4), //4bytes - 24
622 ServerName, //variable - 28
623 Z(4)) //4bytes - 28+target_info_len
624 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
625 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
626 Set LmChallengeResponse to ConcatenationOf(
627 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
628 ClientChallenge )
629 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
630 EndDefine
632 guint8 tmp [16];
633 guint8 nt_proof_str [16];
635 /* client_challenge (8) & temp (temp_len) buff */
636 int temp_len = 8+8+8+4+target_info_len+4;
637 guint8 temp2 [8 + temp_len];
638 memset(temp2, 0, 8 + temp_len); /* init to 0 */
639 temp2[8+0] = 1;
640 temp2[8+1] = 1;
641 *((guint64 *)(temp2+8+8)) = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
642 memcpy(temp2+8+16, client_challenge, 8);
643 memcpy(temp2+8+28, target_info, target_info_len);
645 /* NTProofStr */
646 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
647 memcpy(temp2, server_challenge, 8);
648 HMAC_MD5(response_key_nt, 16, temp2, 8+temp_len, nt_proof_str);
650 /* NtChallengeResponse */
651 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
652 memcpy(nt_challenge_response, nt_proof_str, 16);
653 memcpy(nt_challenge_response+16, temp2+8, temp_len);
655 /* SessionBaseKey */
656 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
657 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
659 /* lm_challenge_response */
660 memcpy(tmp, server_challenge, 8);
661 memcpy(tmp+8, client_challenge, 8);
662 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
663 memcpy(lm_challenge_response+16, client_challenge, 8);
665 #ifndef _SIPE_COMPILING_TESTS
666 /* Not used in NTLMv2 */
667 (void)neg_flags;
668 #else
670 else
672 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
673 // @TODO do not even reference nt_challenge_response
674 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
675 DESL (response_key_lm, server_challenge, lm_challenge_response);
676 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
677 unsigned char prehash [16];
678 unsigned char hash [16];
680 /* nt_challenge_response */
681 memcpy(prehash, server_challenge, 8);
682 memcpy(prehash + 8, client_challenge, 8);
683 MD5 (prehash, 16, hash);
684 DESL (response_key_nt, hash, nt_challenge_response);
686 /* lm_challenge_response */
687 memcpy(lm_challenge_response, client_challenge, 8);
688 Z (lm_challenge_response+8, 16);
689 } else {
690 DESL (response_key_nt, server_challenge, nt_challenge_response);
691 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
692 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
693 } else {
694 DESL (response_key_lm, server_challenge, lm_challenge_response);
698 /* Session Key */
699 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
701 #endif
704 static void
705 KXKEY ( guint32 flags,
706 const unsigned char * session_base_key,
707 const unsigned char * lm_challenge_resonse,
708 const guint8 * server_challenge, /* 8-bytes, nonce */
709 unsigned char * key_exchange_key)
711 #ifdef _SIPE_COMPILING_TESTS
712 if (use_ntlm_v2)
714 #else
715 /* Not used in NTLMv2 */
716 (void)flags;
717 (void)lm_challenge_resonse;
718 (void)server_challenge;
719 #endif
720 memcpy(key_exchange_key, session_base_key, 16);
721 #ifdef _SIPE_COMPILING_TESTS
723 else
725 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
726 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
727 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
728 EndDefine
730 guint8 tmp[16];
731 memcpy(tmp, server_challenge, 8);
732 memcpy(tmp+8, lm_challenge_resonse, 8);
733 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
734 } else {
735 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
736 memcpy(key_exchange_key, session_base_key, 16);
739 #endif
743 If (Mode equals "Client")
744 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
745 "session key to client-to-server signing key magic constant"))
746 Else
747 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
748 "session key to server-to-client signing key magic constant"))
749 Endif
751 static void
752 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
754 char * magic = client
755 ? "session key to client-to-server signing key magic constant"
756 : "session key to server-to-client signing key magic constant";
758 int len = strlen(magic) + 1;
759 unsigned char md5_input [16 + len];
760 memcpy(md5_input, random_session_key, 16);
761 memcpy(md5_input + 16, magic, len);
763 MD5 (md5_input, len + 16, result);
767 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
768 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
769 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
770 Set SealKey to RandomSessionKey
771 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
772 Set SealKey to RandomSessionKey[0..6]
773 Else
774 Set SealKey to RandomSessionKey[0..4]
775 Endif
777 If (Mode equals "Client")
778 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
779 Else
780 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
781 Endif
783 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
784 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
785 Else
786 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
787 Endif
788 EndDefine
790 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
791 static void
792 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
794 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
796 char * magic = client
797 ? "session key to client-to-server sealing key magic constant"
798 : "session key to server-to-client sealing key magic constant";
800 int len = strlen(magic) + 1;
801 unsigned char md5_input [16 + len];
802 int key_len;
804 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
805 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key (Extended session security)\n");
806 key_len = 16;
807 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
808 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key (Extended session security)\n");
809 key_len = 7;
810 } else {
811 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key (Extended session security)\n");
812 key_len = 5;
815 memcpy(md5_input, random_session_key, key_len);
816 memcpy(md5_input + key_len, magic, len);
818 MD5 (md5_input, key_len + len, result);
820 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
822 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
823 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key\n");
824 memcpy(result, random_session_key, 7);
825 result[7] = 0xA0;
826 } else {
827 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key\n");
828 memcpy(result, random_session_key, 5);
829 result[5] = 0xE5;
830 result[6] = 0x38;
831 result[7] = 0xB0;
834 else
836 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key\n");
837 memcpy(result, random_session_key, 16);
842 = for Extended Session Security =
843 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
844 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
845 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
847 = if Extended Session Security is NOT negotiated =
848 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
849 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
850 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
851 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
853 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
855 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
856 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
858 /** MAC(Handle, SigningKey, SeqNum, Message) */
859 /* out 16 bytes */
860 static void
861 MAC (guint32 flags,
862 const char *buf,
863 int buf_len,
864 unsigned char *sign_key,
865 unsigned long sign_key_len,
866 unsigned char *seal_key,
867 unsigned long seal_key_len,
868 guint32 random_pad,
869 guint32 sequence,
870 unsigned char *result)
872 guint32 *res_ptr;
874 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
876 Define MAC(Handle, SigningKey, SeqNum, Message) as
877 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
878 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
879 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
880 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
881 Set SeqNum to SeqNum + 1
882 EndDefine
884 /* If a key exchange key is negotiated
885 Define MAC(Handle, SigningKey, SeqNum, Message) as
886 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
887 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
888 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
889 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
890 Set SeqNum to SeqNum + 1
891 EndDefine
894 unsigned char seal_key_ [16];
895 guchar hmac[16];
896 guchar tmp[4 + buf_len];
898 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
899 RC4Init(Handle, SealingKey')
901 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
902 unsigned char tmp2 [16+4];
904 memcpy(tmp2, seal_key, seal_key_len);
905 *((guint32 *)(tmp2+16)) = GUINT32_TO_LE(sequence);
906 MD5 (tmp2, 16+4, seal_key_);
907 } else {
908 memcpy(seal_key_, seal_key, seal_key_len);
911 purple_debug_info("sipe", "NTLM MAC(): Extented Session Security\n");
913 res_ptr = (guint32 *)result;
914 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
915 res_ptr[3] = GUINT32_TO_LE(sequence);
917 res_ptr = (guint32 *)tmp;
918 res_ptr[0] = GUINT32_TO_LE(sequence);
919 memcpy(tmp+4, buf, buf_len);
921 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
923 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
924 purple_debug_info("sipe", "NTLM MAC(): Key Exchange\n");
925 RC4K(seal_key_, seal_key_len, hmac, 8, result+4);
926 } else {
927 purple_debug_info("sipe", "NTLM MAC(): *NO* Key Exchange\n");
928 memcpy(result+4, hmac, 8);
930 } else {
931 /* The content of the first 4 bytes is irrelevant */
932 guint32 crc = CRC32(buf, strlen(buf));
933 guint32 plaintext [] = {
934 GUINT32_TO_LE(0),
935 GUINT32_TO_LE(crc),
936 GUINT32_TO_LE(sequence)
937 }; // 4, 4, 4 bytes
939 purple_debug_info("sipe", "NTLM MAC(): *NO* Extented Session Security\n");
941 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, result+4);
943 res_ptr = (guint32 *)result;
944 // Highest four bytes are the Version
945 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
947 // Replace the first four bytes of the ciphertext with the random_pad
948 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
952 /* End Core NTLM Methods */
955 * @param flags (out) flags received from server
956 * @param server_challenge must be g_free()'d after use if requested
957 * @param target_info must be g_free()'d after use if requested
959 static void
960 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
961 guint32 *flags,
962 guchar **server_challenge, /* 8 bytes */
963 guint64 *time_val,
964 guchar **target_info,
965 int *target_info_len)
967 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
968 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
970 /* server challenge (nonce) */
971 if (server_challenge) {
972 *server_challenge = g_memdup(cmsg->nonce, 8);
975 /* flags */
976 if (flags) {
977 *flags = host_flags;
980 /* target_info */
981 if (cmsg->target_info.len && cmsg->target_info.offset) {
982 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
983 void *av = content;
984 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
986 ALIGN_AV_LOOP_START
988 /* @since Vista */
989 case MsvAvTimestamp:
990 if (time_val) {
991 guint64 tmp;
993 /* to meet sparc's alignment requirement */
994 memcpy(&tmp, av_value, sizeof(tmp));
995 *time_val = GUINT64_FROM_LE(tmp);
997 break;
999 ALIGN_AV_LOOP_END;
1001 if (target_info_len) {
1002 *target_info_len = len;
1004 if (target_info) {
1005 *target_info = g_memdup(content, len);
1011 * @param client_sign_key (out) must be g_free()'d after use
1012 * @param server_sign_key (out) must be g_free()'d after use
1013 * @param client_seal_key (out) must be g_free()'d after use
1014 * @param server_seal_key (out) must be g_free()'d after use
1015 * @param flags (in, out) negotiated flags
1017 static sip_uint32
1018 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
1019 guchar **server_sign_key,
1020 guchar **client_seal_key,
1021 guchar **server_seal_key,
1022 const gchar *user,
1023 const gchar *password,
1024 const gchar *hostname,
1025 const gchar *domain,
1026 const guint8 *server_challenge, /* nonce */
1027 const guint64 time_val,
1028 const guint8 *target_info,
1029 int target_info_len,
1030 gboolean is_connection_based,
1031 SipSecBuffer *out_buff,
1032 guint32 *flags)
1034 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
1035 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1036 int ntlmssp_nt_resp_len =
1037 #ifdef _SIPE_COMPILING_TESTS
1038 use_ntlm_v2 ?
1039 #endif
1040 (16 + (32+target_info_len))
1041 #ifdef _SIPE_COMPILING_TESTS
1042 : NTLMSSP_LM_RESP_LEN
1043 #endif
1045 gsize msglen = sizeof(struct authenticate_message)
1046 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1047 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1048 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1049 struct authenticate_message *tmsg;
1050 char *tmp;
1051 guint32 offset;
1052 guint16 len;
1053 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1054 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1055 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1056 unsigned char nt_challenge_response [ntlmssp_nt_resp_len]; /* variable or 24 */
1057 unsigned char session_base_key [16];
1058 unsigned char key_exchange_key [16];
1059 unsigned char exported_session_key[16];
1060 unsigned char encrypted_random_session_key [16];
1061 unsigned char key [16];
1062 unsigned char client_challenge [8];
1063 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1065 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1066 !(is_connection_based || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)))
1068 purple_debug_info("sipe", "sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1069 return SIP_SEC_E_INTERNAL_ERROR;
1072 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1073 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1076 tmsg = g_malloc0(msglen);
1078 NONCE (client_challenge, 8);
1080 #ifdef _SIPE_COMPILING_TESTS
1081 memcpy(client_challenge, test_client_challenge, 8);
1082 time_vl = test_time_val ? test_time_val : time_vl;
1084 if (use_ntlm_v2) {
1086 #endif
1087 NTOWFv2 (password, user, domain, response_key_nt);
1088 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1089 #ifdef _SIPE_COMPILING_TESTS
1090 } else {
1091 NTOWFv1 (password, user, domain, response_key_nt);
1092 LMOWFv1 (password, user, domain, response_key_lm);
1094 #endif
1096 compute_response(neg_flags,
1097 response_key_nt,
1098 response_key_lm,
1099 server_challenge,
1100 client_challenge,
1101 time_vl,
1102 target_info,
1103 target_info_len,
1104 lm_challenge_response, /* out */
1105 nt_challenge_response, /* out */
1106 session_base_key); /* out */
1108 /* same as session_base_key for
1109 * - NTLNv1 w/o Ext.Sess.Sec and
1110 * - NTLMv2
1112 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1114 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1115 NONCE (exported_session_key, 16); // random master key
1116 #ifdef _SIPE_COMPILING_TESTS
1117 memcpy(exported_session_key, test_random_session_key, 16);
1118 #endif
1119 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1120 } else {
1121 memcpy(exported_session_key, key_exchange_key, 16);
1124 tmp = buff_to_hex_str(exported_session_key, 16);
1125 purple_debug_info("sipe", "NTLM AUTHENTICATE: exported session key (not encrypted): %s\n", tmp);
1126 g_free(tmp);
1128 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1129 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1131 /* p.46
1132 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1133 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1135 SIGNKEY(exported_session_key, TRUE, key);
1136 *client_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1137 SIGNKEY(exported_session_key, FALSE, key);
1138 *server_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1139 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1140 *client_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1141 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1142 *server_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1145 /* @TODO: */
1146 /* @since Vista
1147 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1148 the client SHOULD provide a MIC:
1149 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1150 - then in the Value field, set bit 0x2 to 1.
1151 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1152 and the Value field bit 0x2 to 1.
1153 - Populate the MIC field with the MIC.
1156 /* Connection-oriented:
1157 Set MIC to HMAC_MD5(ExportedSessionKey,
1158 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1159 Connectionless:
1160 Set MIC to HMAC_MD5(ExportedSessionKey,
1161 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1164 /* on the server-side:
1165 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1166 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1167 Set MIC to HMAC_MD5(ExportedSessionKey,
1168 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1169 Else
1170 Set ExportedSessionKey to KeyExchangeKey
1171 Set MIC to HMAC_MD5(KeyExchangeKey,
1172 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1173 =====
1174 @since Vista
1175 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1176 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1177 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1178 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1179 an AV_PAIR structure whose two fields:
1180 - AvId == MsvAvFlags
1181 - Value bit 0x2 == 1
1182 @supported NT, 2000, XP
1183 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1184 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1185 the server time, then the server SHOULD return a failure.
1187 Connectionless:
1188 Set MIC to HMAC_MD5(ResponseKeyNT,
1189 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1192 /* authenticate message initialization */
1193 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1194 tmsg->type = GUINT32_TO_LE(3);
1196 /* Initial offset */
1197 offset = sizeof(struct authenticate_message);
1198 tmp = ((char*) tmsg) + offset;
1200 #define _FILL_SMB_HEADER(header) \
1201 tmsg->header.offset = GUINT32_TO_LE(offset); \
1202 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1203 tmp += len; \
1204 offset += len
1205 #define _APPEND_STRING(header, src) \
1206 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1207 _FILL_SMB_HEADER(header)
1208 #define _APPEND_DATA(header, src, srclen) \
1209 len = (srclen); \
1210 memcpy(tmp, (src), len); \
1211 _FILL_SMB_HEADER(header)
1213 /* Domain */
1214 _APPEND_STRING(domain, domain);
1216 /* User */
1217 _APPEND_STRING(user, user);
1219 /* Host */
1220 _APPEND_STRING(host, hostname);
1222 /* LM */
1223 /* @since Windows 7
1224 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1225 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1226 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1228 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1230 /* NT */
1231 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1233 /* Session Key */
1234 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1236 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1238 else
1240 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1241 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1244 /* Version */
1245 #ifdef _SIPE_COMPILING_TESTS
1246 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1247 #else
1248 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1249 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1250 tmsg->ver.product_minor_version = 1;
1251 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1252 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1254 #endif
1256 /* Set Negotiate Flags */
1257 tmsg->flags = GUINT32_TO_LE(neg_flags);
1258 *flags = neg_flags;
1260 out_buff->value = (guint8 *)tmsg;
1261 out_buff->length = msglen;
1263 return SIP_SEC_E_OK;
1267 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1269 static void
1270 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1272 guint32 offset;
1273 guint16 len;
1274 int msglen = sizeof(struct negotiate_message);
1275 struct negotiate_message *tmsg = g_malloc0(msglen);
1277 /* negotiate message initialization */
1278 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1279 tmsg->type = GUINT32_TO_LE(1);
1281 /* Set Negotiate Flags */
1282 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1284 /* Domain */
1285 offset = sizeof(struct negotiate_message);
1286 tmsg->domain.offset = GUINT32_TO_LE(offset);
1287 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1289 /* Host */
1290 offset += len;
1291 tmsg->host.offset = GUINT32_TO_LE(offset);
1292 tmsg->host.len = tmsg->host.maxlen = len = 0;
1294 /* Version */
1295 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1296 tmsg->ver.product_minor_version = 1;
1297 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1298 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1300 out_buff->value = (guint8 *)tmsg;
1301 out_buff->length = msglen;
1304 static void
1305 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1306 const char *msg,
1307 guint32 random_pad,
1308 unsigned char *sign_key,
1309 unsigned char *seal_key,
1310 unsigned char *result)
1312 char *res;
1314 MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100, result);
1316 res = buff_to_hex_str(result, 16);
1317 purple_debug_info("sipe", "NTLM calculated MAC: %s\n", res);
1318 g_free(res);
1322 /* Describe NTLM messages functions */
1324 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1325 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1327 static gchar *
1328 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1330 GString* str = g_string_new(NULL);
1332 flags = GUINT32_FROM_LE(flags);
1334 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1335 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1336 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1337 APPEND_NEG_FLAG(str, flags, r9, "r9");
1338 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1339 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1340 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1341 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1342 APPEND_NEG_FLAG(str, flags, r8, "r8");
1343 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1344 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1345 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1346 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1347 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1348 APPEND_NEG_FLAG(str, flags, r7, "r7");
1349 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1350 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1351 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1352 APPEND_NEG_FLAG(str, flags, r6, "r6");
1353 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1354 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1355 APPEND_NEG_FLAG(str, flags, r5, "r5");
1356 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1357 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1358 APPEND_NEG_FLAG(str, flags, r4, "r4");
1359 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1360 APPEND_NEG_FLAG(str, flags, r3, "r3");
1361 APPEND_NEG_FLAG(str, flags, r2, "r2");
1362 APPEND_NEG_FLAG(str, flags, r1, "r1");
1363 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1364 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1365 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1367 return g_string_free(str, FALSE);
1370 static gchar *
1371 sip_sec_ntlm_describe_version(struct version *ver) {
1372 GString* str = g_string_new(NULL);
1373 gchar *ver_desc = "";
1374 gchar *ntlm_revision_desc = "";
1376 if (ver->product_major_version == 6) {
1377 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1378 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1379 ver_desc = "Windows Server 2003";
1380 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1381 ver_desc = "Windows XP SP2";
1384 if (ver->ntlm_revision_current == 0x0F) {
1385 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1386 } else if (ver->ntlm_revision_current == 0x0A) {
1387 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1390 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1391 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1392 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1394 return g_string_free(str, FALSE);
1397 static gchar *
1398 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1399 const char* name)
1401 GString* str = g_string_new(NULL);
1403 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1404 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1405 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1407 return g_string_free(str, FALSE);
1410 static gchar *
1411 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1413 GString* str = g_string_new(NULL);
1414 char *tmp;
1416 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1417 g_free(tmp);
1419 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1420 g_free(tmp);
1422 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1423 g_free(tmp);
1425 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1426 g_string_append(str, tmp);
1427 g_free(tmp);
1429 if (cmsg->domain.len && cmsg->domain.offset) {
1430 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1431 g_string_append_printf(str, "\tdomain: %s\n", domain);
1432 g_free(domain);
1435 if (cmsg->host.len && cmsg->host.offset) {
1436 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1437 g_string_append_printf(str, "\thost: %s\n", host);
1438 g_free(host);
1441 return g_string_free(str, FALSE);
1444 static void
1445 describe_av_pairs(GString* str, const void *av)
1447 #define AV_DESC(av_name) \
1449 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1450 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1451 g_free(tmp); \
1454 ALIGN_AV_LOOP_START
1456 case MsvAvNbComputerName:
1457 AV_DESC("MsvAvNbComputerName");
1458 break;
1459 case MsvAvNbDomainName:
1460 AV_DESC("MsvAvNbDomainName");
1461 break;
1462 case MsvAvDnsComputerName:
1463 AV_DESC("MsvAvDnsComputerName");
1464 break;
1465 case MsvAvDnsDomainName:
1466 AV_DESC("MsvAvDnsDomainName");
1467 break;
1468 case MsvAvDnsTreeName:
1469 AV_DESC("MsvAvDnsTreeName");
1470 break;
1471 case MsvAvFlags:
1473 guint32 flags;
1475 /* to meet sparc's alignment requirement */
1476 memcpy(&flags, av_value, sizeof(guint32));
1477 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1479 break;
1480 case MsvAvTimestamp:
1482 char *tmp;
1483 guint64 time_val;
1484 time_t time_t_val;
1486 /* to meet sparc's alignment requirement */
1487 memcpy(&time_val, av_value, sizeof(time_val));
1488 time_t_val = TIME_VAL_TO_T(time_val);
1490 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1491 asctime(gmtime(&time_t_val)));
1492 g_free(tmp);
1494 break;
1495 case MsAvRestrictions:
1496 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1497 break;
1498 case MsvAvTargetName:
1499 AV_DESC("MsvAvTargetName");
1500 break;
1501 case MsvChannelBindings:
1502 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1503 break;
1505 ALIGN_AV_LOOP_END;
1508 static gchar *
1509 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1511 GString* str = g_string_new(NULL);
1512 char *tmp;
1513 gsize value_len;
1514 guint8 *value;
1516 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1517 g_free(tmp);
1519 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1520 g_free(tmp);
1522 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1523 g_free(tmp);
1525 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1526 g_free(tmp);
1528 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1529 g_free(tmp);
1531 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1532 g_free(tmp);
1534 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1535 g_free(tmp);
1537 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1538 g_string_append(str, tmp);
1539 g_free(tmp);
1541 /* mic */
1542 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1543 //g_free(tmp);
1545 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1546 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1547 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1548 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1549 g_free(tmp);
1552 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1553 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1554 int nt_resp_len = nt_resp_len_full;
1556 value_len = nt_resp_len_full;
1557 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1558 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1559 g_free(tmp);
1561 if (nt_resp_len > 24) { /* NTLMv2 */
1562 nt_resp_len = 16;
1565 value_len = nt_resp_len;
1566 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1567 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1568 g_free(tmp);
1570 if (nt_resp_len_full > 24) { /* NTLMv2 */
1571 /* Work around Debian/x86_64 compiler bug */
1572 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1573 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1574 const guint8 *temp = (guint8 *)cmsg + offset;
1575 const guint response_version = temp[0];
1576 const guint hi_response_version = temp[1];
1577 const guint8 *client_challenge = temp + 16;
1578 const guint8 *target_info = temp + 28;
1579 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1580 guint64 time_val;
1581 time_t time_t_val;
1582 char *tmp;
1584 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1585 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1586 g_free(tmp);
1588 /* This is not int64 aligned on sparc */
1589 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1590 time_t_val = TIME_VAL_TO_T(time_val);
1592 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1593 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1595 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1596 asctime(gmtime(&time_t_val)));
1597 g_free(tmp);
1599 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1600 g_free(tmp);
1602 describe_av_pairs(str, target_info);
1604 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1608 if (cmsg->domain.len && cmsg->domain.offset) {
1609 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1610 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1611 g_free(domain);
1614 if (cmsg->user.len && cmsg->user.offset) {
1615 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1616 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1617 g_free(user);
1620 if (cmsg->host.len && cmsg->host.offset) {
1621 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1622 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1623 g_free(host);
1626 if (cmsg->session_key.len && cmsg->session_key.offset) {
1627 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1628 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1629 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1630 g_free(tmp);
1633 return g_string_free(str, FALSE);
1636 static gchar *
1637 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1639 GString* str = g_string_new(NULL);
1640 char *tmp;
1642 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1643 g_free(tmp);
1645 /* nonce (server_challenge) */
1646 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1647 g_free(tmp);
1649 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1650 g_free(tmp);
1652 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1653 g_free(tmp);
1655 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1656 g_free(tmp);
1658 if (cmsg->target_name.len && cmsg->target_name.offset) {
1659 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1660 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1661 g_free(target_name);
1664 if (cmsg->target_info.len && cmsg->target_info.offset) {
1665 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1666 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1668 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1669 g_free(tmp);
1671 describe_av_pairs(str, target_info);
1674 return g_string_free(str, FALSE);
1677 gchar *
1678 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1680 struct ntlm_message *msg;
1681 gchar *res = NULL;
1683 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1685 msg = (struct ntlm_message *)buff.value;
1686 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1688 switch (GUINT32_FROM_LE(msg->type)) {
1689 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1690 break;
1691 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1692 break;
1693 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1694 break;
1697 return res;
1700 /* sip-sec-mech.h API implementation for NTLM */
1702 /* Security context for NTLM */
1703 typedef struct _context_ntlm {
1704 struct sip_sec_context common;
1705 char* domain;
1706 char *username;
1707 char *password;
1708 int step;
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;
1717 static sip_uint32
1718 sip_sec_acquire_cred__ntlm(SipSecContext context,
1719 const char *domain,
1720 const char *username,
1721 const char *password)
1723 context_ntlm ctx = (context_ntlm)context;
1725 /* NTLM requires a domain, username & password */
1726 if (!domain || !username || !password)
1727 return SIP_SEC_E_INTERNAL_ERROR;
1729 ctx->domain = g_strdup(domain);
1730 ctx->username = g_strdup(username);
1731 ctx->password = g_strdup(password);
1733 return SIP_SEC_E_OK;
1736 static sip_uint32
1737 sip_sec_init_sec_context__ntlm(SipSecContext context,
1738 SipSecBuffer in_buff,
1739 SipSecBuffer *out_buff,
1740 SIPE_UNUSED_PARAMETER const char *service_name)
1742 context_ntlm ctx = (context_ntlm) context;
1744 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1746 ctx->step++;
1747 if (ctx->step == 1) {
1748 if (!context->is_connection_based) {
1749 out_buff->length = 0;
1750 out_buff->value = NULL;
1751 } else {
1752 sip_sec_ntlm_gen_negotiate(out_buff);
1754 return SIP_SEC_I_CONTINUE_NEEDED;
1756 } else {
1757 sip_uint32 res;
1758 guchar *client_sign_key = NULL;
1759 guchar *server_sign_key = NULL;
1760 guchar *client_seal_key = NULL;
1761 guchar *server_seal_key = NULL;
1762 guchar *server_challenge = NULL;
1763 guint64 time_val = 0;
1764 guchar *target_info = NULL;
1765 int target_info_len = 0;
1766 guint32 flags;
1767 gchar *tmp;
1769 if (!in_buff.value || !in_buff.length) {
1770 return SIP_SEC_E_INTERNAL_ERROR;
1773 sip_sec_ntlm_parse_challenge(in_buff,
1774 &flags,
1775 &server_challenge, /* 8 bytes */
1776 &time_val,
1777 &target_info,
1778 &target_info_len);
1780 res = sip_sec_ntlm_gen_authenticate(
1781 &client_sign_key,
1782 &server_sign_key,
1783 &client_seal_key,
1784 &server_seal_key,
1785 ctx->username,
1786 ctx->password,
1787 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1788 ctx->domain,
1789 server_challenge,
1790 time_val,
1791 target_info,
1792 target_info_len,
1793 context->is_connection_based,
1794 out_buff,
1795 &flags);
1796 g_free(server_challenge);
1797 g_free(target_info);
1798 g_free(tmp);
1800 if (res != SIP_SEC_E_OK) {
1801 g_free(client_sign_key);
1802 g_free(server_sign_key);
1803 g_free(client_seal_key);
1804 g_free(server_seal_key);
1805 return res;
1808 g_free(ctx->client_sign_key);
1809 ctx->client_sign_key = client_sign_key;
1811 g_free(ctx->server_sign_key);
1812 ctx->server_sign_key = server_sign_key;
1814 g_free(ctx->client_seal_key);
1815 ctx->client_seal_key = client_seal_key;
1817 g_free(ctx->server_seal_key);
1818 ctx->server_seal_key = server_seal_key;
1820 ctx->flags = flags;
1821 return SIP_SEC_E_OK;
1826 * @param message a NULL terminated string to sign
1829 static sip_uint32
1830 sip_sec_make_signature__ntlm(SipSecContext context,
1831 const char *message,
1832 SipSecBuffer *signature)
1834 signature->length = 16;
1835 signature->value = g_malloc0(16);
1837 /* FIXME? We always use a random_pad of 0 */
1838 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1839 message,
1841 ((context_ntlm) context)->client_sign_key,
1842 ((context_ntlm) context)->client_seal_key,
1843 signature->value);
1844 return SIP_SEC_E_OK;
1848 * @param message a NULL terminated string to check signature of
1849 * @return SIP_SEC_E_OK on success
1851 static sip_uint32
1852 sip_sec_verify_signature__ntlm(SipSecContext context,
1853 const char *message,
1854 SipSecBuffer signature)
1856 guint8 mac[16];
1857 guint32 random_pad = GUINT32_FROM_LE(((guint32 *) signature.value)[1]);
1859 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1860 message,
1861 random_pad,
1862 ((context_ntlm) context)->server_sign_key,
1863 ((context_ntlm) context)->server_seal_key,
1864 mac);
1865 return(memcmp(signature.value, mac, 16) ?
1866 SIP_SEC_E_INTERNAL_ERROR :
1867 SIP_SEC_E_OK);
1870 static void
1871 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1873 context_ntlm ctx = (context_ntlm) context;
1875 g_free(ctx->domain);
1876 g_free(ctx->username);
1877 g_free(ctx->password);
1878 g_free(ctx->client_sign_key);
1879 g_free(ctx->server_sign_key);
1880 g_free(ctx->client_seal_key);
1881 g_free(ctx->server_seal_key);
1882 g_free(ctx);
1885 SipSecContext
1886 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1888 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1889 if (!context) return(NULL);
1891 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1892 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1893 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1894 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1895 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1897 return((SipSecContext) context);
1900 void sip_sec_init__ntlm(void)
1902 #ifdef HAVE_LANGINFO_CODESET
1903 const char *sys_cp = nl_langinfo(CODESET);
1904 #else
1905 const char *sys_cp = SIPE_DEFAULT_CODESET;
1906 #endif /* HAVE_LANGINFO_CODESET */
1908 /* fall back to utf-8 */
1909 if (!sys_cp) sys_cp = "UTF-8";
1911 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1912 if (convert_from_utf16le == (GIConv)-1) {
1913 purple_debug_error("sipe", "g_iconv_open from UTF-16LE to %s failed\n",
1914 sys_cp);
1917 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1918 if (convert_from_utf16le == (GIConv)-1) {
1919 purple_debug_error("sipe", "g_iconv_open from %s to UTF-16LE failed\n",
1920 sys_cp);
1924 void sip_sec_destroy__ntlm(void)
1926 g_iconv_close(convert_to_utf16le);
1927 g_iconv_close(convert_from_utf16le);
1931 Local Variables:
1932 mode: c
1933 c-file-style: "bsd"
1934 indent-tabs-mode: t
1935 tab-width: 8
1936 End: