interface cleanup: flatten interface dependencies
[siplcs.git] / src / core / sip-sec-ntlm.c
blob6d3b12157d6b4de74a898b54fbe4c8fc25d29ab6
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"
60 #include "util.h"
61 #include "xmlnode.h"
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-utils.h"
69 /* [MS-NLMP] */
70 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
71 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
72 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
73 #define r9 0x00000008 /* r9 */
74 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
75 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
76 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
77 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
78 #define r8 0x00000100 /* r8 */
79 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
80 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
81 #define anonymous 0x00000800 /* J */
82 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
83 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
84 #define r7 0x00004000 /* r7 */
85 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
86 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
87 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
88 #define r6 0x00040000 /* r6 */
89 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
90 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
91 #define r5 0x00200000 /* r5 */
92 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
93 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
94 #define r4 0x01000000 /* r4 */
95 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
96 #define r3 0x04000000 /* r3 */
97 #define r2 0x08000000 /* r2 */
98 #define r1 0x10000000 /* r1 */
99 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
100 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
101 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
103 /* AvId */
104 #define MsvAvEOL 0
105 #define MsvAvNbComputerName 1
106 #define MsvAvNbDomainName 2
107 #define MsvAvDnsComputerName 3
108 #define MsvAvDnsDomainName 4
109 /** @since Windows XP */
110 #define MsvAvDnsTreeName 5
111 /** @since Windows XP */
112 #define MsvAvFlags 6
113 /** @since Windows Vista */
114 #define MsvAvTimestamp 7
115 /** @since Windows Vista */
116 #define MsAvRestrictions 8
117 /** @since Windows 7 */
118 #define MsvAvTargetName 9
119 /** @since Windows 7 */
120 #define MsvChannelBindings 10
122 /* time_t <-> (guint64) time_val conversion */
123 #define TIME_VAL_FACTOR 10000000
124 #define TIME_VAL_OFFSET 116444736000000000LL
125 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
126 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
128 /* 8 bytes */
129 /* LE (Little Endian) byte order */
130 struct version {
131 guint8 product_major_version;
132 guint8 product_minor_version;
133 guint16 product_build;
134 guint8 zero2[3];
135 guint8 ntlm_revision_current;
139 * NTLMv1 is no longer used except in tests. R.I.P.
141 * It remains in this file only for documentary purposes
143 #ifdef _SIPE_COMPILING_TESTS
144 static gboolean use_ntlm_v2 = FALSE;
146 guint64 test_time_val = 0; /* actual time in implementation */
147 guchar test_client_challenge [8]; /* random in implementation */
148 guchar test_random_session_key[16]; /* random in implementation */
149 struct version test_version; /* hard-coded in implementation */
150 #endif
152 /* Minimum set of common features we need to work. */
153 /* we operate in NTLMv2 mode */
154 #define NEGOTIATE_FLAGS_COMMON_MIN \
155 ( NTLMSSP_NEGOTIATE_UNICODE | \
156 NTLMSSP_NEGOTIATE_NTLM | \
157 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
158 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
159 NTLMSSP_NEGOTIATE_TARGET_INFO \
162 /* Negotiate flags for connection-based mode. Nice to have but optional. */
163 #define NEGOTIATE_FLAGS_CONN \
164 ( NEGOTIATE_FLAGS_COMMON_MIN | \
165 NTLMSSP_NEGOTIATE_VERSION | \
166 NTLMSSP_NEGOTIATE_128 | \
167 NTLMSSP_NEGOTIATE_56 | \
168 NTLMSSP_REQUEST_TARGET \
171 /* Extra negotiate flags required in connectionless NTLM */
172 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
173 ( NTLMSSP_NEGOTIATE_SIGN | \
174 NTLMSSP_NEGOTIATE_DATAGRAM | \
175 NTLMSSP_NEGOTIATE_IDENTIFY | \
176 NTLMSSP_NEGOTIATE_KEY_EXCH \
179 /* Negotiate flags required in connectionless NTLM */
180 #define NEGOTIATE_FLAGS_CONNLESS \
181 ( NEGOTIATE_FLAGS_CONN | \
182 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
185 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
186 #define NTLMSSP_LM_RESP_LEN 24
187 #define NTLMSSP_SESSION_KEY_LEN 16
188 #define MD4_DIGEST_LEN 16
189 #define MD5_DIGEST_LEN 16
191 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
193 /* 4 bytes */
194 /* LE (Little Endian) byte order */
195 struct av_pair {
196 guint16 av_id;
197 guint16 av_len;
198 /* value */
201 /* to meet sparc's alignment requirement */
202 #define ALIGN_AV \
203 memcpy(&av_aligned, av, sizeof(av_aligned)); \
204 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
205 av_len = GUINT16_FROM_LE(av_aligned.av_len)
206 #define ALIGN_AV_LOOP_START \
207 struct av_pair av_aligned; \
208 guint16 av_id; \
209 guint16 av_len; \
210 ALIGN_AV; \
211 while (av_id != MsvAvEOL) { \
212 gchar *av_value = ((gchar *)av) + \
213 sizeof(struct av_pair); \
214 switch (av_id)
215 #define ALIGN_AV_LOOP_END \
216 av = av_value + av_len; \
217 ALIGN_AV; \
220 /* 8 bytes */
221 /* LE (Little Endian) byte order */
222 struct smb_header {
223 guint16 len;
224 guint16 maxlen;
225 guint32 offset;
228 /* LE (Little Endian) byte order */
229 struct ntlm_message {
230 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
231 guint32 type; /* 0x00000003 */
234 /* LE (Little Endian) byte order */
235 struct negotiate_message {
236 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
237 guint32 type; /* 0x00000001 */
238 guint32 flags; /* 0xb203 */
239 struct smb_header domain;
240 struct smb_header host;
241 struct version ver;
242 /* payload
243 * - DomainName (always ASCII)
244 * - WorkstationName (always ASCII)
248 /* LE (Little Endian) byte order */
249 struct challenge_message {
250 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
251 guint32 type; /* 0x00000002 */
252 struct smb_header target_name;
253 guint32 flags; /* 0x8201 */
254 guint8 nonce[8];
255 guint8 zero1[8];
256 struct smb_header target_info;
257 struct version ver;
258 /* payload
259 * - TargetName (negotiated encoding)
260 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
264 /* LE (Little Endian) byte order */
265 struct authenticate_message {
266 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
267 guint32 type; /* 0x00000003 */
268 /** LmChallengeResponseFields */
269 struct smb_header lm_resp;
270 /** NtChallengeResponseFields */
271 struct smb_header nt_resp;
272 /** DomainNameFields */
273 struct smb_header domain;
274 /** UserNameFields */
275 struct smb_header user;
276 /** WorkstationFields */
277 struct smb_header host;
278 /** EncryptedRandomSessionKeyFields */
279 struct smb_header session_key;
280 guint32 flags;
281 struct version ver;
282 //guint8 mic[16];
283 /* payload
284 * - LmChallengeResponse
285 * - NtChallengeResponse
286 * - DomainName (negotiated encoding)
287 * - UserName (negotiated encoding)
288 * - Workstation (negotiated encoding)
289 * - EncryptedRandomSessionKey
293 #ifndef HAVE_LANGINFO_CODESET
294 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
295 #endif
297 /* Private Methods */
299 /* Utility Functions */
300 static GIConv convert_from_utf16le = (GIConv)-1;
301 static GIConv convert_to_utf16le = (GIConv)-1;
303 static gsize
304 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
306 gsize inbytes = strlen(source);
307 gsize outbytes = remlen;
308 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
309 return(remlen - outbytes);
312 /* UTF-16LE to native encoding
313 * Must be g_free'd after use */
314 static gchar *
315 unicode_strconvcopy_back(const gchar *source, gsize len)
317 gsize outbytes = 2 * len;
318 gchar *dest = g_new0(gchar, outbytes + 1);
319 gchar *outbuf = dest;
320 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
321 return dest;
324 /* crc32 source copy from gg's common.c */
325 static guint32 crc32_table[256];
326 static int crc32_initialized = 0;
328 static void crc32_make_table()
330 guint32 h = 1;
331 unsigned int i, j;
333 memset(crc32_table, 0, sizeof(crc32_table));
335 for (i = 128; i; i >>= 1) {
336 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
338 for (j = 0; j < 256; j += 2 * i)
339 crc32_table[i + j] = crc32_table[j] ^ h;
342 crc32_initialized = 1;
345 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
347 if (!crc32_initialized)
348 crc32_make_table();
350 if (!buf || len < 0)
351 return crc;
353 crc ^= 0xffffffffL;
355 while (len--)
356 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
358 return crc ^ 0xffffffffL;
361 static guint32
362 CRC32 (const char *msg, int len)
364 guint32 crc = 0L;
365 crc = crc32(crc, (guint8 *) msg, len);
366 return crc;
369 /* Cyphers */
371 #ifdef _SIPE_COMPILING_TESTS
372 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
374 key[0] = key_56[0];
375 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
376 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
377 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
378 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
379 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
380 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
381 key[7] = (key_56[6] << 1) & 0xFF;
384 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
386 PurpleCipher *cipher;
387 PurpleCipherContext *context;
388 size_t outlen;
390 cipher = purple_ciphers_find_cipher("des");
391 context = purple_cipher_context_new(cipher, NULL);
392 purple_cipher_context_set_key(context, (guchar*)key);
393 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
394 purple_cipher_context_destroy(context);
397 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
398 static void
399 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
401 unsigned char key[8];
402 setup_des_key(k, key);
403 des_ecb_encrypt(d, results, key);
406 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
407 static void
408 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
410 unsigned char keys[21];
412 /* Copy the first 16 bytes */
413 memcpy(keys, k, 16);
415 /* Zero out the last 5 bytes of the key */
416 memset(keys + 16, 0, 5);
418 DES(keys, d, results);
419 DES(keys + 7, d, results + 8);
420 DES(keys + 14, d, results + 16);
422 #endif
424 static void
425 RC4K (const unsigned char * k, unsigned long key_len, const unsigned char * d, int len, unsigned char * result)
427 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
428 purple_cipher_context_set_option(context, "key_len", (gpointer)key_len);
429 purple_cipher_context_set_key(context, k);
430 purple_cipher_context_encrypt(context, (const guchar *)d, len, result, NULL);
431 purple_cipher_context_destroy(context);
434 /* out 16 bytes */
435 static void
436 MD4 (const unsigned char * d, int len, unsigned char * result)
438 PurpleCipher * cipher = purple_ciphers_find_cipher("md4");
439 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
440 purple_cipher_context_append(context, (guchar*)d, len);
441 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
442 purple_cipher_context_destroy(context);
445 /* out 16 bytes */
446 static void
447 MD5 (const unsigned char * d, int len, unsigned char * result)
449 PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
450 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
451 purple_cipher_context_append(context, (guchar*)d, len);
452 purple_cipher_context_digest(context, MD5_DIGEST_LEN, (guchar*)result, NULL);
453 purple_cipher_context_destroy(context);
456 /* out 16 bytes */
458 static void
459 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
461 int i;
462 unsigned char ibuff[64 + data_len];
463 unsigned char obuff[64 + 16];
465 if (key_len > 64)
466 key_len = 64;
468 for (i = 0; i < key_len; i++) {
469 ibuff[i] = key[i] ^ 0x36;
470 obuff[i] = key[i] ^ 0x5c;
472 for (i = key_len; i < 64; i++) {
473 ibuff[i] = 0x36;
474 obuff[i] = 0x5c;
477 memcpy(ibuff+64, data, data_len);
479 MD5 (ibuff, 64 + data_len, obuff+64);
480 MD5 (obuff, 64 + 16, result);
482 #define HMAC_MD5 HMACT64
485 /* out 16 bytes */
486 static void
487 HMAC_MD5 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
489 PurpleCipher *cipher = purple_ciphers_find_cipher("hmac");
490 PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL);
492 purple_cipher_context_set_option(context, "hash", "md5");
493 purple_cipher_context_set_key_with_len(context, (guchar *)key, (key_len));
495 purple_cipher_context_append(context, (guchar *)data, data_len);
496 purple_cipher_context_digest(context, 16, (guchar*)result, NULL);
497 purple_cipher_context_destroy(context);
500 /* NTLM Core Methods */
502 static void
503 NONCE(unsigned char *buffer, int num)
505 int i;
506 for (i = 0; i < num; i++) {
507 buffer[i] = (rand() & 0xff);
511 #ifdef _SIPE_COMPILING_TESTS
512 static void
513 Z(unsigned char *buffer, int num)
515 memset(buffer, 0, num);
518 static void
519 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
521 /* "KGS!@#$%" */
522 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
523 unsigned char uppercase_password[14];
524 int i;
526 int len = strlen(password);
527 if (len > 14) {
528 len = 14;
531 // Uppercase password
532 for (i = 0; i < len; i++) {
533 uppercase_password[i] = g_ascii_toupper(password[i]);
536 // Zero the rest
537 for (; i < 14; i++) {
538 uppercase_password[i] = 0;
541 DES (uppercase_password, magic, result);
542 DES (uppercase_password + 7, magic, result + 8);
544 #endif
547 Define NTOWFv1(Passwd, User, UserDom) as
548 MD4(UNICODE(Passwd))
549 EndDefine
551 /* out 16 bytes */
552 static void
553 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
555 int len_u = 2 * strlen(password); // utf16 should not be more
556 unsigned char unicode_password[len_u];
558 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
559 MD4 (unicode_password, len_u, result);
563 Define NTOWFv2(Passwd, User, UserDom) as
564 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
565 EndDefine
567 /* out 16 bytes */
568 void
569 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
571 unsigned char response_key_nt_v1 [16];
572 int len_user = user ? strlen(user) : 0;
573 int len_domain = domain ? strlen(domain) : 0;
574 unsigned char user_upper[len_user + 1];
575 int len_user_u = 2 * len_user; // utf16 should not be more
576 int len_domain_u = 2 * len_domain; // utf16 should not be more
577 unsigned char buff[(len_user + len_domain)*2];
578 int i;
580 /* Uppercase user */
581 for (i = 0; i < len_user; i++) {
582 user_upper[i] = g_ascii_toupper(user[i]);
584 user_upper[len_user] = 0;
586 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
587 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
589 NTOWFv1(password, user, domain, response_key_nt_v1);
591 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
594 static void
595 compute_response(const guint32 neg_flags,
596 const unsigned char *response_key_nt,
597 const unsigned char *response_key_lm,
598 const guint8 *server_challenge,
599 const guint8 *client_challenge,
600 const guint64 time_val,
601 const guint8 *target_info,
602 int target_info_len,
603 unsigned char *lm_challenge_response,
604 unsigned char *nt_challenge_response,
605 unsigned char *session_base_key)
607 #ifdef _SIPE_COMPILING_TESTS
608 if (use_ntlm_v2)
610 #endif
612 Responserversion - The 1-byte response version. Currently set to 1.
613 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
614 Time - The 8-byte little-endian time in GMT.
615 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
616 ClientChallenge - The 8-byte challenge message generated by the client.
617 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
619 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
620 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
621 Time, //8bytes - 8
622 ClientChallenge, //8bytes - 16
623 Z(4), //4bytes - 24
624 ServerName, //variable - 28
625 Z(4)) //4bytes - 28+target_info_len
626 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
627 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
628 Set LmChallengeResponse to ConcatenationOf(
629 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
630 ClientChallenge )
631 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
632 EndDefine
634 guint8 tmp [16];
635 guint8 nt_proof_str [16];
637 /* client_challenge (8) & temp (temp_len) buff */
638 int temp_len = 8+8+8+4+target_info_len+4;
639 guint8 temp2 [8 + temp_len];
640 memset(temp2, 0, 8 + temp_len); /* init to 0 */
641 temp2[8+0] = 1;
642 temp2[8+1] = 1;
643 *((guint64 *)(temp2+8+8)) = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
644 memcpy(temp2+8+16, client_challenge, 8);
645 memcpy(temp2+8+28, target_info, target_info_len);
647 /* NTProofStr */
648 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
649 memcpy(temp2, server_challenge, 8);
650 HMAC_MD5(response_key_nt, 16, temp2, 8+temp_len, nt_proof_str);
652 /* NtChallengeResponse */
653 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
654 memcpy(nt_challenge_response, nt_proof_str, 16);
655 memcpy(nt_challenge_response+16, temp2+8, temp_len);
657 /* SessionBaseKey */
658 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
659 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
661 /* lm_challenge_response */
662 memcpy(tmp, server_challenge, 8);
663 memcpy(tmp+8, client_challenge, 8);
664 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
665 memcpy(lm_challenge_response+16, client_challenge, 8);
667 #ifndef _SIPE_COMPILING_TESTS
668 /* Not used in NTLMv2 */
669 (void)neg_flags;
670 #else
672 else
674 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
675 // @TODO do not even reference nt_challenge_response
676 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
677 DESL (response_key_lm, server_challenge, lm_challenge_response);
678 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
679 unsigned char prehash [16];
680 unsigned char hash [16];
682 /* nt_challenge_response */
683 memcpy(prehash, server_challenge, 8);
684 memcpy(prehash + 8, client_challenge, 8);
685 MD5 (prehash, 16, hash);
686 DESL (response_key_nt, hash, nt_challenge_response);
688 /* lm_challenge_response */
689 memcpy(lm_challenge_response, client_challenge, 8);
690 Z (lm_challenge_response+8, 16);
691 } else {
692 DESL (response_key_nt, server_challenge, nt_challenge_response);
693 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
694 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
695 } else {
696 DESL (response_key_lm, server_challenge, lm_challenge_response);
700 /* Session Key */
701 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
703 #endif
706 static void
707 KXKEY ( guint32 flags,
708 const unsigned char * session_base_key,
709 const unsigned char * lm_challenge_resonse,
710 const guint8 * server_challenge, /* 8-bytes, nonce */
711 unsigned char * key_exchange_key)
713 #ifdef _SIPE_COMPILING_TESTS
714 if (use_ntlm_v2)
716 #else
717 /* Not used in NTLMv2 */
718 (void)flags;
719 (void)lm_challenge_resonse;
720 (void)server_challenge;
721 #endif
722 memcpy(key_exchange_key, session_base_key, 16);
723 #ifdef _SIPE_COMPILING_TESTS
725 else
727 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
728 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
729 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
730 EndDefine
732 guint8 tmp[16];
733 memcpy(tmp, server_challenge, 8);
734 memcpy(tmp+8, lm_challenge_resonse, 8);
735 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
736 } else {
737 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
738 memcpy(key_exchange_key, session_base_key, 16);
741 #endif
745 If (Mode equals "Client")
746 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
747 "session key to client-to-server signing key magic constant"))
748 Else
749 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
750 "session key to server-to-client signing key magic constant"))
751 Endif
753 static void
754 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
756 char * magic = client
757 ? "session key to client-to-server signing key magic constant"
758 : "session key to server-to-client signing key magic constant";
760 int len = strlen(magic) + 1;
761 unsigned char md5_input [16 + len];
762 memcpy(md5_input, random_session_key, 16);
763 memcpy(md5_input + 16, magic, len);
765 MD5 (md5_input, len + 16, result);
769 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
770 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
771 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
772 Set SealKey to RandomSessionKey
773 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
774 Set SealKey to RandomSessionKey[0..6]
775 Else
776 Set SealKey to RandomSessionKey[0..4]
777 Endif
779 If (Mode equals "Client")
780 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
781 Else
782 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
783 Endif
785 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
786 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
787 Else
788 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
789 Endif
790 EndDefine
792 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
793 static void
794 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
796 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
798 char * magic = client
799 ? "session key to client-to-server sealing key magic constant"
800 : "session key to server-to-client sealing key magic constant";
802 int len = strlen(magic) + 1;
803 unsigned char md5_input [16 + len];
804 int key_len;
806 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
807 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key (Extended session security)\n");
808 key_len = 16;
809 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
810 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key (Extended session security)\n");
811 key_len = 7;
812 } else {
813 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key (Extended session security)\n");
814 key_len = 5;
817 memcpy(md5_input, random_session_key, key_len);
818 memcpy(md5_input + key_len, magic, len);
820 MD5 (md5_input, key_len + len, result);
822 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
824 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
825 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key\n");
826 memcpy(result, random_session_key, 7);
827 result[7] = 0xA0;
828 } else {
829 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key\n");
830 memcpy(result, random_session_key, 5);
831 result[5] = 0xE5;
832 result[6] = 0x38;
833 result[7] = 0xB0;
836 else
838 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key\n");
839 memcpy(result, random_session_key, 16);
844 = for Extended Session Security =
845 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
846 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
847 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
849 = if Extended Session Security is NOT negotiated =
850 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
851 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
852 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
853 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
855 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
857 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
858 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
860 /** MAC(Handle, SigningKey, SeqNum, Message) */
861 /* out 16 bytes */
862 static void
863 MAC (guint32 flags,
864 const char *buf,
865 int buf_len,
866 unsigned char *sign_key,
867 unsigned long sign_key_len,
868 unsigned char *seal_key,
869 unsigned long seal_key_len,
870 guint32 random_pad,
871 guint32 sequence,
872 unsigned char *result)
874 guint32 *res_ptr;
876 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
878 Define MAC(Handle, SigningKey, SeqNum, Message) as
879 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
880 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
881 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
882 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
883 Set SeqNum to SeqNum + 1
884 EndDefine
886 /* If a key exchange key is negotiated
887 Define MAC(Handle, SigningKey, SeqNum, Message) as
888 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
889 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
890 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
891 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
892 Set SeqNum to SeqNum + 1
893 EndDefine
896 unsigned char seal_key_ [16];
897 guchar hmac[16];
898 guchar tmp[4 + buf_len];
900 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
901 RC4Init(Handle, SealingKey')
903 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
904 unsigned char tmp2 [16+4];
906 memcpy(tmp2, seal_key, seal_key_len);
907 *((guint32 *)(tmp2+16)) = GUINT32_TO_LE(sequence);
908 MD5 (tmp2, 16+4, seal_key_);
909 } else {
910 memcpy(seal_key_, seal_key, seal_key_len);
913 purple_debug_info("sipe", "NTLM MAC(): Extented Session Security\n");
915 res_ptr = (guint32 *)result;
916 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
917 res_ptr[3] = GUINT32_TO_LE(sequence);
919 res_ptr = (guint32 *)tmp;
920 res_ptr[0] = GUINT32_TO_LE(sequence);
921 memcpy(tmp+4, buf, buf_len);
923 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
925 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
926 purple_debug_info("sipe", "NTLM MAC(): Key Exchange\n");
927 RC4K(seal_key_, seal_key_len, hmac, 8, result+4);
928 } else {
929 purple_debug_info("sipe", "NTLM MAC(): *NO* Key Exchange\n");
930 memcpy(result+4, hmac, 8);
932 } else {
933 /* The content of the first 4 bytes is irrelevant */
934 guint32 crc = CRC32(buf, strlen(buf));
935 guint32 plaintext [] = {
936 GUINT32_TO_LE(0),
937 GUINT32_TO_LE(crc),
938 GUINT32_TO_LE(sequence)
939 }; // 4, 4, 4 bytes
941 purple_debug_info("sipe", "NTLM MAC(): *NO* Extented Session Security\n");
943 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, result+4);
945 res_ptr = (guint32 *)result;
946 // Highest four bytes are the Version
947 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
949 // Replace the first four bytes of the ciphertext with the random_pad
950 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
954 /* End Core NTLM Methods */
957 * @param flags (out) flags received from server
958 * @param server_challenge must be g_free()'d after use if requested
959 * @param target_info must be g_free()'d after use if requested
961 static void
962 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
963 guint32 *flags,
964 guchar **server_challenge, /* 8 bytes */
965 guint64 *time_val,
966 guchar **target_info,
967 int *target_info_len)
969 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
970 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
972 /* server challenge (nonce) */
973 if (server_challenge) {
974 *server_challenge = g_memdup(cmsg->nonce, 8);
977 /* flags */
978 if (flags) {
979 *flags = host_flags;
982 /* target_info */
983 if (cmsg->target_info.len && cmsg->target_info.offset) {
984 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
985 void *av = content;
986 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
988 ALIGN_AV_LOOP_START
990 /* @since Vista */
991 case MsvAvTimestamp:
992 if (time_val) {
993 guint64 tmp;
995 /* to meet sparc's alignment requirement */
996 memcpy(&tmp, av_value, sizeof(tmp));
997 *time_val = GUINT64_FROM_LE(tmp);
999 break;
1001 ALIGN_AV_LOOP_END;
1003 if (target_info_len) {
1004 *target_info_len = len;
1006 if (target_info) {
1007 *target_info = g_memdup(content, len);
1013 * @param client_sign_key (out) must be g_free()'d after use
1014 * @param server_sign_key (out) must be g_free()'d after use
1015 * @param client_seal_key (out) must be g_free()'d after use
1016 * @param server_seal_key (out) must be g_free()'d after use
1017 * @param flags (in, out) negotiated flags
1019 static sip_uint32
1020 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
1021 guchar **server_sign_key,
1022 guchar **client_seal_key,
1023 guchar **server_seal_key,
1024 const gchar *user,
1025 const gchar *password,
1026 const gchar *hostname,
1027 const gchar *domain,
1028 const guint8 *server_challenge, /* nonce */
1029 const guint64 time_val,
1030 const guint8 *target_info,
1031 int target_info_len,
1032 gboolean is_connection_based,
1033 SipSecBuffer *out_buff,
1034 guint32 *flags)
1036 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
1037 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1038 int ntlmssp_nt_resp_len =
1039 #ifdef _SIPE_COMPILING_TESTS
1040 use_ntlm_v2 ?
1041 #endif
1042 (16 + (32+target_info_len))
1043 #ifdef _SIPE_COMPILING_TESTS
1044 : NTLMSSP_LM_RESP_LEN
1045 #endif
1047 gsize msglen = sizeof(struct authenticate_message)
1048 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1049 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1050 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1051 struct authenticate_message *tmsg;
1052 char *tmp;
1053 guint32 offset;
1054 guint16 len;
1055 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1056 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1057 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1058 unsigned char nt_challenge_response [ntlmssp_nt_resp_len]; /* variable or 24 */
1059 unsigned char session_base_key [16];
1060 unsigned char key_exchange_key [16];
1061 unsigned char exported_session_key[16];
1062 unsigned char encrypted_random_session_key [16];
1063 unsigned char key [16];
1064 unsigned char client_challenge [8];
1065 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1067 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1068 !(is_connection_based || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)))
1070 purple_debug_info("sipe", "sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1071 return SIP_SEC_E_INTERNAL_ERROR;
1074 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1075 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1078 tmsg = g_malloc0(msglen);
1080 NONCE (client_challenge, 8);
1082 #ifdef _SIPE_COMPILING_TESTS
1083 memcpy(client_challenge, test_client_challenge, 8);
1084 time_vl = test_time_val ? test_time_val : time_vl;
1086 if (use_ntlm_v2) {
1088 #endif
1089 NTOWFv2 (password, user, domain, response_key_nt);
1090 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1091 #ifdef _SIPE_COMPILING_TESTS
1092 } else {
1093 NTOWFv1 (password, user, domain, response_key_nt);
1094 LMOWFv1 (password, user, domain, response_key_lm);
1096 #endif
1098 compute_response(neg_flags,
1099 response_key_nt,
1100 response_key_lm,
1101 server_challenge,
1102 client_challenge,
1103 time_vl,
1104 target_info,
1105 target_info_len,
1106 lm_challenge_response, /* out */
1107 nt_challenge_response, /* out */
1108 session_base_key); /* out */
1110 /* same as session_base_key for
1111 * - NTLNv1 w/o Ext.Sess.Sec and
1112 * - NTLMv2
1114 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1116 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1117 NONCE (exported_session_key, 16); // random master key
1118 #ifdef _SIPE_COMPILING_TESTS
1119 memcpy(exported_session_key, test_random_session_key, 16);
1120 #endif
1121 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1122 } else {
1123 memcpy(exported_session_key, key_exchange_key, 16);
1126 tmp = buff_to_hex_str(exported_session_key, 16);
1127 purple_debug_info("sipe", "NTLM AUTHENTICATE: exported session key (not encrypted): %s\n", tmp);
1128 g_free(tmp);
1130 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1131 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1133 /* p.46
1134 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1135 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1137 SIGNKEY(exported_session_key, TRUE, key);
1138 *client_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1139 SIGNKEY(exported_session_key, FALSE, key);
1140 *server_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1141 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1142 *client_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1143 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1144 *server_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1147 /* @TODO: */
1148 /* @since Vista
1149 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1150 the client SHOULD provide a MIC:
1151 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1152 - then in the Value field, set bit 0x2 to 1.
1153 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1154 and the Value field bit 0x2 to 1.
1155 - Populate the MIC field with the MIC.
1158 /* Connection-oriented:
1159 Set MIC to HMAC_MD5(ExportedSessionKey,
1160 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1161 Connectionless:
1162 Set MIC to HMAC_MD5(ExportedSessionKey,
1163 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1166 /* on the server-side:
1167 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1168 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1169 Set MIC to HMAC_MD5(ExportedSessionKey,
1170 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1171 Else
1172 Set ExportedSessionKey to KeyExchangeKey
1173 Set MIC to HMAC_MD5(KeyExchangeKey,
1174 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1175 =====
1176 @since Vista
1177 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1178 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1179 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1180 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1181 an AV_PAIR structure whose two fields:
1182 - AvId == MsvAvFlags
1183 - Value bit 0x2 == 1
1184 @supported NT, 2000, XP
1185 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1186 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1187 the server time, then the server SHOULD return a failure.
1189 Connectionless:
1190 Set MIC to HMAC_MD5(ResponseKeyNT,
1191 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1194 /* authenticate message initialization */
1195 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1196 tmsg->type = GUINT32_TO_LE(3);
1198 /* Initial offset */
1199 offset = sizeof(struct authenticate_message);
1200 tmp = ((char*) tmsg) + offset;
1202 #define _FILL_SMB_HEADER(header) \
1203 tmsg->header.offset = GUINT32_TO_LE(offset); \
1204 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1205 tmp += len; \
1206 offset += len
1207 #define _APPEND_STRING(header, src) \
1208 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1209 _FILL_SMB_HEADER(header)
1210 #define _APPEND_DATA(header, src, srclen) \
1211 len = (srclen); \
1212 memcpy(tmp, (src), len); \
1213 _FILL_SMB_HEADER(header)
1215 /* Domain */
1216 _APPEND_STRING(domain, domain);
1218 /* User */
1219 _APPEND_STRING(user, user);
1221 /* Host */
1222 _APPEND_STRING(host, hostname);
1224 /* LM */
1225 /* @since Windows 7
1226 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1227 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1228 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1230 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1232 /* NT */
1233 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1235 /* Session Key */
1236 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1238 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1240 else
1242 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1243 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1246 /* Version */
1247 #ifdef _SIPE_COMPILING_TESTS
1248 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1249 #else
1250 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1251 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1252 tmsg->ver.product_minor_version = 1;
1253 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1254 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1256 #endif
1258 /* Set Negotiate Flags */
1259 tmsg->flags = GUINT32_TO_LE(neg_flags);
1260 *flags = neg_flags;
1262 out_buff->value = (guint8 *)tmsg;
1263 out_buff->length = msglen;
1265 return SIP_SEC_E_OK;
1269 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1271 static void
1272 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1274 guint32 offset;
1275 guint16 len;
1276 int msglen = sizeof(struct negotiate_message);
1277 struct negotiate_message *tmsg = g_malloc0(msglen);
1279 /* negotiate message initialization */
1280 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1281 tmsg->type = GUINT32_TO_LE(1);
1283 /* Set Negotiate Flags */
1284 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1286 /* Domain */
1287 offset = sizeof(struct negotiate_message);
1288 tmsg->domain.offset = GUINT32_TO_LE(offset);
1289 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1291 /* Host */
1292 offset += len;
1293 tmsg->host.offset = GUINT32_TO_LE(offset);
1294 tmsg->host.len = tmsg->host.maxlen = len = 0;
1296 /* Version */
1297 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1298 tmsg->ver.product_minor_version = 1;
1299 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1300 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1302 out_buff->value = (guint8 *)tmsg;
1303 out_buff->length = msglen;
1306 static void
1307 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1308 const char *msg,
1309 guint32 random_pad,
1310 unsigned char *sign_key,
1311 unsigned char *seal_key,
1312 unsigned char *result)
1314 char *res;
1316 MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100, result);
1318 res = buff_to_hex_str(result, 16);
1319 purple_debug_info("sipe", "NTLM calculated MAC: %s\n", res);
1320 g_free(res);
1324 /* Describe NTLM messages functions */
1326 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1327 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1329 static gchar *
1330 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1332 GString* str = g_string_new(NULL);
1334 flags = GUINT32_FROM_LE(flags);
1336 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1337 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1338 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1339 APPEND_NEG_FLAG(str, flags, r9, "r9");
1340 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1341 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1342 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1343 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1344 APPEND_NEG_FLAG(str, flags, r8, "r8");
1345 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1346 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1347 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1348 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1349 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1350 APPEND_NEG_FLAG(str, flags, r7, "r7");
1351 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1352 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1353 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1354 APPEND_NEG_FLAG(str, flags, r6, "r6");
1355 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1356 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1357 APPEND_NEG_FLAG(str, flags, r5, "r5");
1358 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1359 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1360 APPEND_NEG_FLAG(str, flags, r4, "r4");
1361 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1362 APPEND_NEG_FLAG(str, flags, r3, "r3");
1363 APPEND_NEG_FLAG(str, flags, r2, "r2");
1364 APPEND_NEG_FLAG(str, flags, r1, "r1");
1365 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1366 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1367 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1369 return g_string_free(str, FALSE);
1372 static gchar *
1373 sip_sec_ntlm_describe_version(struct version *ver) {
1374 GString* str = g_string_new(NULL);
1375 gchar *ver_desc = "";
1376 gchar *ntlm_revision_desc = "";
1378 if (ver->product_major_version == 6) {
1379 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1380 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1381 ver_desc = "Windows Server 2003";
1382 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1383 ver_desc = "Windows XP SP2";
1386 if (ver->ntlm_revision_current == 0x0F) {
1387 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1388 } else if (ver->ntlm_revision_current == 0x0A) {
1389 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1392 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1393 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1394 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1396 return g_string_free(str, FALSE);
1399 static gchar *
1400 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1401 const char* name)
1403 GString* str = g_string_new(NULL);
1405 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1406 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1407 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1409 return g_string_free(str, FALSE);
1412 static gchar *
1413 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1415 GString* str = g_string_new(NULL);
1416 char *tmp;
1418 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1419 g_free(tmp);
1421 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1422 g_free(tmp);
1424 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1425 g_free(tmp);
1427 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1428 g_string_append(str, tmp);
1429 g_free(tmp);
1431 if (cmsg->domain.len && cmsg->domain.offset) {
1432 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1433 g_string_append_printf(str, "\tdomain: %s\n", domain);
1434 g_free(domain);
1437 if (cmsg->host.len && cmsg->host.offset) {
1438 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1439 g_string_append_printf(str, "\thost: %s\n", host);
1440 g_free(host);
1443 return g_string_free(str, FALSE);
1446 static void
1447 describe_av_pairs(GString* str, const void *av)
1449 #define AV_DESC(av_name) \
1451 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1452 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1453 g_free(tmp); \
1456 ALIGN_AV_LOOP_START
1458 case MsvAvNbComputerName:
1459 AV_DESC("MsvAvNbComputerName");
1460 break;
1461 case MsvAvNbDomainName:
1462 AV_DESC("MsvAvNbDomainName");
1463 break;
1464 case MsvAvDnsComputerName:
1465 AV_DESC("MsvAvDnsComputerName");
1466 break;
1467 case MsvAvDnsDomainName:
1468 AV_DESC("MsvAvDnsDomainName");
1469 break;
1470 case MsvAvDnsTreeName:
1471 AV_DESC("MsvAvDnsTreeName");
1472 break;
1473 case MsvAvFlags:
1475 guint32 flags;
1477 /* to meet sparc's alignment requirement */
1478 memcpy(&flags, av_value, sizeof(guint32));
1479 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1481 break;
1482 case MsvAvTimestamp:
1484 char *tmp;
1485 guint64 time_val;
1486 time_t time_t_val;
1488 /* to meet sparc's alignment requirement */
1489 memcpy(&time_val, av_value, sizeof(time_val));
1490 time_t_val = TIME_VAL_TO_T(time_val);
1492 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1493 asctime(gmtime(&time_t_val)));
1494 g_free(tmp);
1496 break;
1497 case MsAvRestrictions:
1498 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1499 break;
1500 case MsvAvTargetName:
1501 AV_DESC("MsvAvTargetName");
1502 break;
1503 case MsvChannelBindings:
1504 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1505 break;
1507 ALIGN_AV_LOOP_END;
1510 static gchar *
1511 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1513 GString* str = g_string_new(NULL);
1514 char *tmp;
1515 gsize value_len;
1516 guint8 *value;
1518 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1519 g_free(tmp);
1521 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1522 g_free(tmp);
1524 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1525 g_free(tmp);
1527 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1528 g_free(tmp);
1530 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1531 g_free(tmp);
1533 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1534 g_free(tmp);
1536 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1537 g_free(tmp);
1539 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1540 g_string_append(str, tmp);
1541 g_free(tmp);
1543 /* mic */
1544 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1545 //g_free(tmp);
1547 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1548 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1549 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1550 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1551 g_free(tmp);
1554 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1555 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1556 int nt_resp_len = nt_resp_len_full;
1558 value_len = nt_resp_len_full;
1559 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1560 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1561 g_free(tmp);
1563 if (nt_resp_len > 24) { /* NTLMv2 */
1564 nt_resp_len = 16;
1567 value_len = nt_resp_len;
1568 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1569 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1570 g_free(tmp);
1572 if (nt_resp_len_full > 24) { /* NTLMv2 */
1573 /* Work around Debian/x86_64 compiler bug */
1574 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1575 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1576 const guint8 *temp = (guint8 *)cmsg + offset;
1577 const guint response_version = temp[0];
1578 const guint hi_response_version = temp[1];
1579 const guint8 *client_challenge = temp + 16;
1580 const guint8 *target_info = temp + 28;
1581 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1582 guint64 time_val;
1583 time_t time_t_val;
1584 char *tmp;
1586 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1587 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1588 g_free(tmp);
1590 /* This is not int64 aligned on sparc */
1591 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1592 time_t_val = TIME_VAL_TO_T(time_val);
1594 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1595 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1597 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1598 asctime(gmtime(&time_t_val)));
1599 g_free(tmp);
1601 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1602 g_free(tmp);
1604 describe_av_pairs(str, target_info);
1606 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1610 if (cmsg->domain.len && cmsg->domain.offset) {
1611 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1612 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1613 g_free(domain);
1616 if (cmsg->user.len && cmsg->user.offset) {
1617 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1618 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1619 g_free(user);
1622 if (cmsg->host.len && cmsg->host.offset) {
1623 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1624 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1625 g_free(host);
1628 if (cmsg->session_key.len && cmsg->session_key.offset) {
1629 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1630 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1631 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1632 g_free(tmp);
1635 return g_string_free(str, FALSE);
1638 static gchar *
1639 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1641 GString* str = g_string_new(NULL);
1642 char *tmp;
1644 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1645 g_free(tmp);
1647 /* nonce (server_challenge) */
1648 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1649 g_free(tmp);
1651 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1652 g_free(tmp);
1654 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1655 g_free(tmp);
1657 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1658 g_free(tmp);
1660 if (cmsg->target_name.len && cmsg->target_name.offset) {
1661 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1662 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1663 g_free(target_name);
1666 if (cmsg->target_info.len && cmsg->target_info.offset) {
1667 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1668 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1670 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1671 g_free(tmp);
1673 describe_av_pairs(str, target_info);
1676 return g_string_free(str, FALSE);
1679 gchar *
1680 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1682 struct ntlm_message *msg;
1683 gchar *res = NULL;
1685 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1687 msg = (struct ntlm_message *)buff.value;
1688 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1690 switch (GUINT32_FROM_LE(msg->type)) {
1691 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1692 break;
1693 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1694 break;
1695 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1696 break;
1699 return res;
1702 /* sip-sec-mech.h API implementation for NTLM */
1704 /* Security context for NTLM */
1705 typedef struct _context_ntlm {
1706 struct sip_sec_context common;
1707 char* domain;
1708 char *username;
1709 char *password;
1710 int step;
1711 guchar *client_sign_key;
1712 guchar *server_sign_key;
1713 guchar *client_seal_key;
1714 guchar *server_seal_key;
1715 guint32 flags;
1716 } *context_ntlm;
1719 static sip_uint32
1720 sip_sec_acquire_cred__ntlm(SipSecContext context,
1721 const char *domain,
1722 const char *username,
1723 const char *password)
1725 context_ntlm ctx = (context_ntlm)context;
1727 /* NTLM requires a domain, username & password */
1728 if (!domain || !username || !password)
1729 return SIP_SEC_E_INTERNAL_ERROR;
1731 ctx->domain = g_strdup(domain);
1732 ctx->username = g_strdup(username);
1733 ctx->password = g_strdup(password);
1735 return SIP_SEC_E_OK;
1738 static sip_uint32
1739 sip_sec_init_sec_context__ntlm(SipSecContext context,
1740 SipSecBuffer in_buff,
1741 SipSecBuffer *out_buff,
1742 SIPE_UNUSED_PARAMETER const char *service_name)
1744 context_ntlm ctx = (context_ntlm) context;
1746 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1748 ctx->step++;
1749 if (ctx->step == 1) {
1750 if (!context->is_connection_based) {
1751 out_buff->length = 0;
1752 out_buff->value = NULL;
1753 } else {
1754 sip_sec_ntlm_gen_negotiate(out_buff);
1756 return SIP_SEC_I_CONTINUE_NEEDED;
1758 } else {
1759 sip_uint32 res;
1760 guchar *client_sign_key = NULL;
1761 guchar *server_sign_key = NULL;
1762 guchar *client_seal_key = NULL;
1763 guchar *server_seal_key = NULL;
1764 guchar *server_challenge = NULL;
1765 guint64 time_val = 0;
1766 guchar *target_info = NULL;
1767 int target_info_len = 0;
1768 guint32 flags;
1769 gchar *tmp;
1771 if (!in_buff.value || !in_buff.length) {
1772 return SIP_SEC_E_INTERNAL_ERROR;
1775 sip_sec_ntlm_parse_challenge(in_buff,
1776 &flags,
1777 &server_challenge, /* 8 bytes */
1778 &time_val,
1779 &target_info,
1780 &target_info_len);
1782 res = sip_sec_ntlm_gen_authenticate(
1783 &client_sign_key,
1784 &server_sign_key,
1785 &client_seal_key,
1786 &server_seal_key,
1787 ctx->username,
1788 ctx->password,
1789 (tmp = g_ascii_strup(sipe_get_host_name(), -1)),
1790 ctx->domain,
1791 server_challenge,
1792 time_val,
1793 target_info,
1794 target_info_len,
1795 context->is_connection_based,
1796 out_buff,
1797 &flags);
1798 g_free(server_challenge);
1799 g_free(target_info);
1800 g_free(tmp);
1802 if (res != SIP_SEC_E_OK) {
1803 g_free(client_sign_key);
1804 g_free(server_sign_key);
1805 g_free(client_seal_key);
1806 g_free(server_seal_key);
1807 return res;
1810 g_free(ctx->client_sign_key);
1811 ctx->client_sign_key = client_sign_key;
1813 g_free(ctx->server_sign_key);
1814 ctx->server_sign_key = server_sign_key;
1816 g_free(ctx->client_seal_key);
1817 ctx->client_seal_key = client_seal_key;
1819 g_free(ctx->server_seal_key);
1820 ctx->server_seal_key = server_seal_key;
1822 ctx->flags = flags;
1823 return SIP_SEC_E_OK;
1828 * @param message a NULL terminated string to sign
1831 static sip_uint32
1832 sip_sec_make_signature__ntlm(SipSecContext context,
1833 const char *message,
1834 SipSecBuffer *signature)
1836 signature->length = 16;
1837 signature->value = g_malloc0(16);
1839 /* FIXME? We always use a random_pad of 0 */
1840 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1841 message,
1843 ((context_ntlm) context)->client_sign_key,
1844 ((context_ntlm) context)->client_seal_key,
1845 signature->value);
1846 return SIP_SEC_E_OK;
1850 * @param message a NULL terminated string to check signature of
1851 * @return SIP_SEC_E_OK on success
1853 static sip_uint32
1854 sip_sec_verify_signature__ntlm(SipSecContext context,
1855 const char *message,
1856 SipSecBuffer signature)
1858 guint8 mac[16];
1859 guint32 random_pad = GUINT32_FROM_LE(((guint32 *) signature.value)[1]);
1861 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1862 message,
1863 random_pad,
1864 ((context_ntlm) context)->server_sign_key,
1865 ((context_ntlm) context)->server_seal_key,
1866 mac);
1867 return(memcmp(signature.value, mac, 16) ?
1868 SIP_SEC_E_INTERNAL_ERROR :
1869 SIP_SEC_E_OK);
1872 static void
1873 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1875 context_ntlm ctx = (context_ntlm) context;
1877 g_free(ctx->domain);
1878 g_free(ctx->username);
1879 g_free(ctx->password);
1880 g_free(ctx->client_sign_key);
1881 g_free(ctx->server_sign_key);
1882 g_free(ctx->client_seal_key);
1883 g_free(ctx->server_seal_key);
1884 g_free(ctx);
1887 SipSecContext
1888 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1890 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1891 if (!context) return(NULL);
1893 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1894 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1895 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1896 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1897 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1899 return((SipSecContext) context);
1902 void sip_sec_init__ntlm(void)
1904 #ifdef HAVE_LANGINFO_CODESET
1905 const char *sys_cp = nl_langinfo(CODESET);
1906 #else
1907 const char *sys_cp = SIPE_DEFAULT_CODESET;
1908 #endif /* HAVE_LANGINFO_CODESET */
1910 /* fall back to utf-8 */
1911 if (!sys_cp) sys_cp = "UTF-8";
1913 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1914 if (convert_from_utf16le == (GIConv)-1) {
1915 purple_debug_error("sipe", "g_iconv_open from UTF-16LE to %s failed\n",
1916 sys_cp);
1919 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1920 if (convert_from_utf16le == (GIConv)-1) {
1921 purple_debug_error("sipe", "g_iconv_open from %s to UTF-16LE failed\n",
1922 sys_cp);
1926 void sip_sec_destroy__ntlm(void)
1928 g_iconv_close(convert_to_utf16le);
1929 g_iconv_close(convert_from_utf16le);
1933 Local Variables:
1934 mode: c
1935 c-file-style: "bsd"
1936 indent-tabs-mode: t
1937 tab-width: 8
1938 End: