Get rid of old hex/string conversion functions
[siplcs.git] / src / core / sip-sec-ntlm.c
blobf1997d3f6330b87078e152a29ed6e93d29469223
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 <glib.h>
49 #include <glib/gprintf.h>
50 #include <stdio.h>
51 #include <errno.h>
52 #include <string.h>
53 #include <stdlib.h>
54 #include "debug.h"
56 #ifdef _WIN32
57 #include "internal.h"
58 #endif /* _WIN32 */
60 #ifdef HAVE_LANGINFO_CODESET
61 #include <langinfo.h>
62 #endif /* HAVE_LANGINFO_CODESET */
64 #include "util.h"
65 #include "cipher.h"
67 #include "sipe.h"
68 #include "sipe-utils.h"
69 #include "sip-sec-mech.h"
70 #include "sip-sec-ntlm.h"
72 /* [MS-NLMP] */
73 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
74 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
75 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
76 #define r9 0x00000008 /* r9 */
77 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
78 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
79 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
80 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
81 #define r8 0x00000100 /* r8 */
82 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
83 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
84 #define anonymous 0x00000800 /* J */
85 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
86 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
87 #define r7 0x00004000 /* r7 */
88 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
89 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
90 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
91 #define r6 0x00040000 /* r6 */
92 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
93 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
94 #define r5 0x00200000 /* r5 */
95 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
96 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
97 #define r4 0x01000000 /* r4 */
98 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
99 #define r3 0x04000000 /* r3 */
100 #define r2 0x08000000 /* r2 */
101 #define r1 0x10000000 /* r1 */
102 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
103 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
104 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
106 /* AvId */
107 #define MsvAvEOL 0
108 #define MsvAvNbComputerName 1
109 #define MsvAvNbDomainName 2
110 #define MsvAvDnsComputerName 3
111 #define MsvAvDnsDomainName 4
112 /** @since Windows XP */
113 #define MsvAvDnsTreeName 5
114 /** @since Windows XP */
115 #define MsvAvFlags 6
116 /** @since Windows Vista */
117 #define MsvAvTimestamp 7
118 /** @since Windows Vista */
119 #define MsAvRestrictions 8
120 /** @since Windows 7 */
121 #define MsvAvTargetName 9
122 /** @since Windows 7 */
123 #define MsvChannelBindings 10
125 /* time_t <-> (guint64) time_val conversion */
126 #define TIME_VAL_FACTOR 10000000
127 #define TIME_VAL_OFFSET 116444736000000000LL
128 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
129 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
131 /* 8 bytes */
132 /* LE (Little Endian) byte order */
133 struct version {
134 guint8 product_major_version;
135 guint8 product_minor_version;
136 guint16 product_build;
137 guint8 zero2[3];
138 guint8 ntlm_revision_current;
142 * NTLMv1 is no longer used except in tests. R.I.P.
144 * It remains in this file only for documentary purposes
146 #ifdef _SIPE_COMPILING_TESTS
147 static gboolean use_ntlm_v2 = FALSE;
149 guint64 test_time_val = 0; /* actual time in implementation */
150 guchar test_client_challenge [8]; /* random in implementation */
151 guchar test_random_session_key[16]; /* random in implementation */
152 struct version test_version; /* hard-coded in implementation */
153 #endif
155 /* Minimum set of common features we need to work. */
156 /* we operate in NTLMv2 mode */
157 #define NEGOTIATE_FLAGS_COMMON_MIN \
158 ( NTLMSSP_NEGOTIATE_UNICODE | \
159 NTLMSSP_NEGOTIATE_NTLM | \
160 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
161 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
162 NTLMSSP_NEGOTIATE_TARGET_INFO \
165 /* Negotiate flags for connection-based mode. Nice to have but optional. */
166 #define NEGOTIATE_FLAGS_CONN \
167 ( NEGOTIATE_FLAGS_COMMON_MIN | \
168 NTLMSSP_NEGOTIATE_VERSION | \
169 NTLMSSP_NEGOTIATE_128 | \
170 NTLMSSP_NEGOTIATE_56 | \
171 NTLMSSP_REQUEST_TARGET \
174 /* Extra negotiate flags required in connectionless NTLM */
175 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
176 ( NTLMSSP_NEGOTIATE_SIGN | \
177 NTLMSSP_NEGOTIATE_DATAGRAM | \
178 NTLMSSP_NEGOTIATE_IDENTIFY | \
179 NTLMSSP_NEGOTIATE_KEY_EXCH \
182 /* Negotiate flags required in connectionless NTLM */
183 #define NEGOTIATE_FLAGS \
184 ( NEGOTIATE_FLAGS_CONN | \
185 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
188 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
189 #define NTLMSSP_LM_RESP_LEN 24
190 #define NTLMSSP_SESSION_KEY_LEN 16
191 #define MD4_DIGEST_LEN 16
192 #define MD5_DIGEST_LEN 16
194 #define IS_FLAG(flags, flag) ((flags & flag) == flag)
196 /* 4 bytes */
197 /* LE (Little Endian) byte order */
198 struct av_pair {
199 guint16 av_id;
200 guint16 av_len;
201 /* value */
204 /* to meet sparc's alignment requirement */
205 #define ALIGN_AV \
206 memcpy(&av_aligned, av, sizeof(av_aligned)); \
207 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
208 av_len = GUINT16_FROM_LE(av_aligned.av_len)
209 #define ALIGN_AV_LOOP_START \
210 struct av_pair av_aligned; \
211 guint16 av_id; \
212 guint16 av_len; \
213 ALIGN_AV; \
214 while (av_id != MsvAvEOL) { \
215 gchar *av_value = ((gchar *)av) + \
216 sizeof(struct av_pair); \
217 switch (av_id)
218 #define ALIGN_AV_LOOP_END \
219 av = av_value + av_len; \
220 ALIGN_AV; \
223 /* 8 bytes */
224 /* LE (Little Endian) byte order */
225 struct smb_header {
226 guint16 len;
227 guint16 maxlen;
228 guint32 offset;
231 /* LE (Little Endian) byte order */
232 struct ntlm_message {
233 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
234 guint32 type; /* 0x00000003 */
237 /* LE (Little Endian) byte order */
238 struct negotiate_message {
239 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
240 guint32 type; /* 0x00000001 */
241 guint32 flags; /* 0xb203 */
242 struct smb_header domain;
243 struct smb_header host;
244 struct version ver;
245 /* payload
246 * - DomainName (always ASCII)
247 * - WorkstationName (always ASCII)
251 /* LE (Little Endian) byte order */
252 struct challenge_message {
253 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
254 guint32 type; /* 0x00000002 */
255 struct smb_header target_name;
256 guint32 flags; /* 0x8201 */
257 guint8 nonce[8];
258 guint8 zero1[8];
259 struct smb_header target_info;
260 struct version ver;
261 /* payload
262 * - TargetName (negotiated encoding)
263 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
267 /* LE (Little Endian) byte order */
268 struct authenticate_message {
269 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
270 guint32 type; /* 0x00000003 */
271 /** LmChallengeResponseFields */
272 struct smb_header lm_resp;
273 /** NtChallengeResponseFields */
274 struct smb_header nt_resp;
275 /** DomainNameFields */
276 struct smb_header domain;
277 /** UserNameFields */
278 struct smb_header user;
279 /** WorkstationFields */
280 struct smb_header host;
281 /** EncryptedRandomSessionKeyFields */
282 struct smb_header session_key;
283 guint32 flags;
284 struct version ver;
285 //guint8 mic[16];
286 /* payload
287 * - LmChallengeResponse
288 * - NtChallengeResponse
289 * - DomainName (negotiated encoding)
290 * - UserName (negotiated encoding)
291 * - Workstation (negotiated encoding)
292 * - EncryptedRandomSessionKey
296 #ifndef HAVE_LANGINFO_CODESET
297 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
298 #endif
300 /* Private Methods */
302 /* Utility Functions */
303 static GIConv convert_from_utf16le = (GIConv)-1;
304 static GIConv convert_to_utf16le = (GIConv)-1;
306 static gsize
307 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
309 gsize inbytes = strlen(source);
310 gsize outbytes = remlen;
311 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
312 return(remlen - outbytes);
315 /* UTF-16LE to native encoding
316 * Must be g_free'd after use */
317 static gchar *
318 unicode_strconvcopy_back(const gchar *source, gsize len)
320 gsize outbytes = 2 * len;
321 gchar *dest = g_new0(gchar, outbytes + 1);
322 gchar *outbuf = dest;
323 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
324 return dest;
327 /* crc32 source copy from gg's common.c */
328 static guint32 crc32_table[256];
329 static int crc32_initialized = 0;
331 static void crc32_make_table()
333 guint32 h = 1;
334 unsigned int i, j;
336 memset(crc32_table, 0, sizeof(crc32_table));
338 for (i = 128; i; i >>= 1) {
339 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
341 for (j = 0; j < 256; j += 2 * i)
342 crc32_table[i + j] = crc32_table[j] ^ h;
345 crc32_initialized = 1;
348 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
350 if (!crc32_initialized)
351 crc32_make_table();
353 if (!buf || len < 0)
354 return crc;
356 crc ^= 0xffffffffL;
358 while (len--)
359 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
361 return crc ^ 0xffffffffL;
364 static guint32
365 CRC32 (const char *msg, int len)
367 guint32 crc = 0L;
368 crc = crc32(crc, (guint8 *) msg, len);
369 return crc;
372 /* Cyphers */
374 #ifdef _SIPE_COMPILING_TESTS
375 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
377 key[0] = key_56[0];
378 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
379 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
380 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
381 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
382 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
383 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
384 key[7] = (key_56[6] << 1) & 0xFF;
387 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
389 PurpleCipher *cipher;
390 PurpleCipherContext *context;
391 size_t outlen;
393 cipher = purple_ciphers_find_cipher("des");
394 context = purple_cipher_context_new(cipher, NULL);
395 purple_cipher_context_set_key(context, (guchar*)key);
396 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
397 purple_cipher_context_destroy(context);
400 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
401 static void
402 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
404 unsigned char key[8];
405 setup_des_key(k, key);
406 des_ecb_encrypt(d, results, key);
409 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
410 static void
411 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
413 unsigned char keys[21];
415 /* Copy the first 16 bytes */
416 memcpy(keys, k, 16);
418 /* Zero out the last 5 bytes of the key */
419 memset(keys + 16, 0, 5);
421 DES(keys, d, results);
422 DES(keys + 7, d, results + 8);
423 DES(keys + 14, d, results + 16);
425 #endif
427 static void
428 RC4K (const unsigned char * k, unsigned long key_len, const unsigned char * d, int len, unsigned char * result)
430 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
431 purple_cipher_context_set_option(context, "key_len", (gpointer)key_len);
432 purple_cipher_context_set_key(context, k);
433 purple_cipher_context_encrypt(context, (const guchar *)d, len, result, NULL);
434 purple_cipher_context_destroy(context);
437 /* out 16 bytes */
438 static void
439 MD4 (const unsigned char * d, int len, unsigned char * result)
441 PurpleCipher * cipher = purple_ciphers_find_cipher("md4");
442 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
443 purple_cipher_context_append(context, (guchar*)d, len);
444 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
445 purple_cipher_context_destroy(context);
448 /* out 16 bytes */
449 static void
450 MD5 (const unsigned char * d, int len, unsigned char * result)
452 PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
453 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
454 purple_cipher_context_append(context, (guchar*)d, len);
455 purple_cipher_context_digest(context, MD5_DIGEST_LEN, (guchar*)result, NULL);
456 purple_cipher_context_destroy(context);
459 /* out 16 bytes */
461 static void
462 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
464 int i;
465 unsigned char ibuff[64 + data_len];
466 unsigned char obuff[64 + 16];
468 if (key_len > 64)
469 key_len = 64;
471 for (i = 0; i < key_len; i++) {
472 ibuff[i] = key[i] ^ 0x36;
473 obuff[i] = key[i] ^ 0x5c;
475 for (i = key_len; i < 64; i++) {
476 ibuff[i] = 0x36;
477 obuff[i] = 0x5c;
480 memcpy(ibuff+64, data, data_len);
482 MD5 (ibuff, 64 + data_len, obuff+64);
483 MD5 (obuff, 64 + 16, result);
485 #define HMAC_MD5 HMACT64
488 /* out 16 bytes */
489 static void
490 HMAC_MD5 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
492 PurpleCipher *cipher = purple_ciphers_find_cipher("hmac");
493 PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL);
495 purple_cipher_context_set_option(context, "hash", "md5");
496 purple_cipher_context_set_key_with_len(context, (guchar *)key, (key_len));
498 purple_cipher_context_append(context, (guchar *)data, data_len);
499 purple_cipher_context_digest(context, 16, (guchar*)result, NULL);
500 purple_cipher_context_destroy(context);
503 /* NTLM Core Methods */
505 static void
506 NONCE(unsigned char *buffer, int num)
508 int i;
509 for (i = 0; i < num; i++) {
510 buffer[i] = (rand() & 0xff);
514 #ifdef _SIPE_COMPILING_TESTS
515 static void
516 Z(unsigned char *buffer, int num)
518 memset(buffer, 0, num);
521 static void
522 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
524 /* "KGS!@#$%" */
525 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
526 unsigned char uppercase_password[14];
527 int i;
529 int len = strlen(password);
530 if (len > 14) {
531 len = 14;
534 // Uppercase password
535 for (i = 0; i < len; i++) {
536 uppercase_password[i] = g_ascii_toupper(password[i]);
539 // Zero the rest
540 for (; i < 14; i++) {
541 uppercase_password[i] = 0;
544 DES (uppercase_password, magic, result);
545 DES (uppercase_password + 7, magic, result + 8);
547 #endif
550 Define NTOWFv1(Passwd, User, UserDom) as
551 MD4(UNICODE(Passwd))
552 EndDefine
554 /* out 16 bytes */
555 static void
556 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
558 int len_u = 2 * strlen(password); // utf16 should not be more
559 unsigned char unicode_password[len_u];
561 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
562 MD4 (unicode_password, len_u, result);
566 Define NTOWFv2(Passwd, User, UserDom) as
567 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
568 EndDefine
570 /* out 16 bytes */
571 void
572 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
574 unsigned char response_key_nt_v1 [16];
575 int len_user = user ? strlen(user) : 0;
576 int len_domain = domain ? strlen(domain) : 0;
577 unsigned char user_upper[len_user + 1];
578 int len_user_u = 2 * len_user; // utf16 should not be more
579 int len_domain_u = 2 * len_domain; // utf16 should not be more
580 unsigned char buff[(len_user + len_domain)*2];
581 int i;
583 /* Uppercase user */
584 for (i = 0; i < len_user; i++) {
585 user_upper[i] = g_ascii_toupper(user[i]);
587 user_upper[len_user] = 0;
589 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
590 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
592 NTOWFv1(password, user, domain, response_key_nt_v1);
594 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
597 static void
598 compute_response(const guint32 neg_flags,
599 const unsigned char *response_key_nt,
600 const unsigned char *response_key_lm,
601 const guint8 *server_challenge,
602 const guint8 *client_challenge,
603 const guint64 time_val,
604 const guint8 *target_info,
605 int target_info_len,
606 unsigned char *lm_challenge_response,
607 unsigned char *nt_challenge_response,
608 unsigned char *session_base_key)
610 #ifdef _SIPE_COMPILING_TESTS
611 if (use_ntlm_v2)
613 #endif
615 Responserversion - The 1-byte response version. Currently set to 1.
616 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
617 Time - The 8-byte little-endian time in GMT.
618 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
619 ClientChallenge - The 8-byte challenge message generated by the client.
620 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
622 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
623 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
624 Time, //8bytes - 8
625 ClientChallenge, //8bytes - 16
626 Z(4), //4bytes - 24
627 ServerName, //variable - 28
628 Z(4)) //4bytes - 28+target_info_len
629 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
630 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
631 Set LmChallengeResponse to ConcatenationOf(
632 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
633 ClientChallenge )
634 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
635 EndDefine
637 guint8 tmp [16];
638 guint8 nt_proof_str [16];
640 /* client_challenge (8) & temp (temp_len) buff */
641 int temp_len = 8+8+8+4+target_info_len+4;
642 guint8 temp2 [8 + temp_len];
643 memset(temp2, 0, 8 + temp_len); /* init to 0 */
644 temp2[8+0] = 1;
645 temp2[8+1] = 1;
646 *((guint64 *)(temp2+8+8)) = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
647 memcpy(temp2+8+16, client_challenge, 8);
648 memcpy(temp2+8+28, target_info, target_info_len);
650 /* NTProofStr */
651 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
652 memcpy(temp2, server_challenge, 8);
653 HMAC_MD5(response_key_nt, 16, temp2, 8+temp_len, nt_proof_str);
655 /* NtChallengeResponse */
656 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
657 memcpy(nt_challenge_response, nt_proof_str, 16);
658 memcpy(nt_challenge_response+16, temp2+8, temp_len);
660 /* SessionBaseKey */
661 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
662 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
664 /* lm_challenge_response */
665 memcpy(tmp, server_challenge, 8);
666 memcpy(tmp+8, client_challenge, 8);
667 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
668 memcpy(lm_challenge_response+16, client_challenge, 8);
670 #ifndef _SIPE_COMPILING_TESTS
671 /* Not used in NTLMv2 */
672 (void)neg_flags;
673 #else
675 else
677 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
678 // @TODO do not even reference nt_challenge_response
679 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
680 DESL (response_key_lm, server_challenge, lm_challenge_response);
681 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
682 unsigned char prehash [16];
683 unsigned char hash [16];
685 /* nt_challenge_response */
686 memcpy(prehash, server_challenge, 8);
687 memcpy(prehash + 8, client_challenge, 8);
688 MD5 (prehash, 16, hash);
689 DESL (response_key_nt, hash, nt_challenge_response);
691 /* lm_challenge_response */
692 memcpy(lm_challenge_response, client_challenge, 8);
693 Z (lm_challenge_response+8, 16);
694 } else {
695 DESL (response_key_nt, server_challenge, nt_challenge_response);
696 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
697 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
698 } else {
699 DESL (response_key_lm, server_challenge, lm_challenge_response);
703 /* Session Key */
704 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
706 #endif
709 static void
710 KXKEY ( guint32 flags,
711 const unsigned char * session_base_key,
712 const unsigned char * lm_challenge_resonse,
713 const guint8 * server_challenge, /* 8-bytes, nonce */
714 unsigned char * key_exchange_key)
716 #ifdef _SIPE_COMPILING_TESTS
717 if (use_ntlm_v2)
719 #else
720 /* Not used in NTLMv2 */
721 (void)flags;
722 (void)lm_challenge_resonse;
723 (void)server_challenge;
724 #endif
725 memcpy(key_exchange_key, session_base_key, 16);
726 #ifdef _SIPE_COMPILING_TESTS
728 else
730 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
731 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
732 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
733 EndDefine
735 guint8 tmp[16];
736 memcpy(tmp, server_challenge, 8);
737 memcpy(tmp+8, lm_challenge_resonse, 8);
738 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
739 } else {
740 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
741 memcpy(key_exchange_key, session_base_key, 16);
744 #endif
748 If (Mode equals "Client")
749 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
750 "session key to client-to-server signing key magic constant"))
751 Else
752 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
753 "session key to server-to-client signing key magic constant"))
754 Endif
756 static void
757 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
759 char * magic = client
760 ? "session key to client-to-server signing key magic constant"
761 : "session key to server-to-client signing key magic constant";
763 int len = strlen(magic) + 1;
764 unsigned char md5_input [16 + len];
765 memcpy(md5_input, random_session_key, 16);
766 memcpy(md5_input + 16, magic, len);
768 MD5 (md5_input, len + 16, result);
772 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
773 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
774 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
775 Set SealKey to RandomSessionKey
776 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
777 Set SealKey to RandomSessionKey[0..6]
778 Else
779 Set SealKey to RandomSessionKey[0..4]
780 Endif
782 If (Mode equals "Client")
783 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
784 Else
785 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
786 Endif
788 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
789 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
790 Else
791 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
792 Endif
793 EndDefine
795 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
796 static void
797 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
799 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
801 char * magic = client
802 ? "session key to client-to-server sealing key magic constant"
803 : "session key to server-to-client sealing key magic constant";
805 int len = strlen(magic) + 1;
806 unsigned char md5_input [16 + len];
807 int key_len;
809 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
810 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key (Extended session security)\n");
811 key_len = 16;
812 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
813 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key (Extended session security)\n");
814 key_len = 7;
815 } else {
816 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key (Extended session security)\n");
817 key_len = 5;
820 memcpy(md5_input, random_session_key, key_len);
821 memcpy(md5_input + key_len, magic, len);
823 MD5 (md5_input, key_len + len, result);
825 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
827 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
828 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key\n");
829 memcpy(result, random_session_key, 7);
830 result[7] = 0xA0;
831 } else {
832 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key\n");
833 memcpy(result, random_session_key, 5);
834 result[5] = 0xE5;
835 result[6] = 0x38;
836 result[7] = 0xB0;
839 else
841 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key\n");
842 memcpy(result, random_session_key, 16);
847 = for Extended Session Security =
848 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
849 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
850 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
852 = if Extended Session Security is NOT negotiated =
853 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
854 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
855 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
856 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
858 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
860 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
861 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
863 /** MAC(Handle, SigningKey, SeqNum, Message) */
864 static gchar *
865 MAC (guint32 flags,
866 const char *buf,
867 int buf_len,
868 unsigned char *sign_key,
869 unsigned long sign_key_len,
870 unsigned char *seal_key,
871 unsigned long seal_key_len,
872 guint32 random_pad,
873 guint32 sequence)
875 guchar result [16];
876 guint32 *res_ptr;
877 gchar signature [33];
878 int i, j;
880 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
882 Define MAC(Handle, SigningKey, SeqNum, Message) as
883 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
884 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
885 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
886 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
887 Set SeqNum to SeqNum + 1
888 EndDefine
890 /* If a key exchange key is negotiated
891 Define MAC(Handle, SigningKey, SeqNum, Message) as
892 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
893 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
894 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
895 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
896 Set SeqNum to SeqNum + 1
897 EndDefine
900 unsigned char seal_key_ [16];
901 guchar hmac[16];
902 guchar tmp[4 + buf_len];
904 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
905 RC4Init(Handle, SealingKey')
907 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
908 unsigned char tmp2 [16+4];
910 memcpy(tmp2, seal_key, seal_key_len);
911 *((guint32 *)(tmp2+16)) = GUINT32_TO_LE(sequence);
912 MD5 (tmp2, 16+4, seal_key_);
913 } else {
914 memcpy(seal_key_, seal_key, seal_key_len);
917 purple_debug_info("sipe", "NTLM MAC(): Extented Session Security\n");
919 res_ptr = (guint32 *)result;
920 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
921 res_ptr[3] = GUINT32_TO_LE(sequence);
923 res_ptr = (guint32 *)tmp;
924 res_ptr[0] = GUINT32_TO_LE(sequence);
925 memcpy(tmp+4, buf, buf_len);
927 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
929 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
930 purple_debug_info("sipe", "NTLM MAC(): Key Exchange\n");
931 RC4K(seal_key_, seal_key_len, hmac, 8, result+4);
932 } else {
933 purple_debug_info("sipe", "NTLM MAC(): *NO* Key Exchange\n");
934 memcpy(result+4, hmac, 8);
936 } else {
937 /* The content of the first 4 bytes is irrelevant */
938 guint32 crc = CRC32(buf, strlen(buf));
939 guint32 plaintext [] = {
940 GUINT32_TO_LE(0),
941 GUINT32_TO_LE(crc),
942 GUINT32_TO_LE(sequence)
943 }; // 4, 4, 4 bytes
945 purple_debug_info("sipe", "NTLM MAC(): *NO* Extented Session Security\n");
947 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, result+4);
949 res_ptr = (guint32 *)result;
950 // Highest four bytes are the Version
951 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
953 // Replace the first four bytes of the ciphertext with the random_pad
954 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
957 for (i = 0, j = 0; i < 16; i++, j+=2) {
958 g_sprintf(&signature[j], "%02X", result[i]);
961 return g_strdup(signature);
964 /* End Core NTLM Methods */
967 * @param flags (out) flags received from server
968 * @param server_challenge must be g_free()'d after use if requested
969 * @param target_info must be g_free()'d after use if requested
971 static void
972 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
973 guint32 *flags,
974 guchar **server_challenge, /* 8 bytes */
975 guint64 *time_val,
976 guchar **target_info,
977 int *target_info_len)
979 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
980 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
982 /* server challenge (nonce) */
983 if (server_challenge) {
984 *server_challenge = g_memdup(cmsg->nonce, 8);
987 /* flags */
988 if (flags) {
989 *flags = host_flags;
992 /* target_info */
993 if (cmsg->target_info.len && cmsg->target_info.offset) {
994 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
995 void *av = content;
996 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
998 ALIGN_AV_LOOP_START
1000 /* @since Vista */
1001 case MsvAvTimestamp:
1002 if (time_val) {
1003 guint64 tmp;
1005 /* to meet sparc's alignment requirement */
1006 memcpy(&tmp, av_value, sizeof(tmp));
1007 *time_val = GUINT64_FROM_LE(tmp);
1009 break;
1011 ALIGN_AV_LOOP_END;
1013 if (target_info_len) {
1014 *target_info_len = len;
1016 if (target_info) {
1017 *target_info = g_memdup(content, len);
1023 * @param client_sign_key (out) must be g_free()'d after use
1024 * @param server_sign_key (out) must be g_free()'d after use
1025 * @param client_seal_key (out) must be g_free()'d after use
1026 * @param server_seal_key (out) must be g_free()'d after use
1027 * @param flags (in, out) negotiated flags
1029 static sip_uint32
1030 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
1031 guchar **server_sign_key,
1032 guchar **client_seal_key,
1033 guchar **server_seal_key,
1034 const gchar *user,
1035 const gchar *password,
1036 const gchar *hostname,
1037 const gchar *domain,
1038 const guint8 *server_challenge, /* nonce */
1039 const guint64 time_val,
1040 const guint8 *target_info,
1041 int target_info_len,
1042 gboolean is_connection_based,
1043 SipSecBuffer *out_buff,
1044 guint32 *flags)
1046 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
1047 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1048 int ntlmssp_nt_resp_len =
1049 #ifdef _SIPE_COMPILING_TESTS
1050 use_ntlm_v2 ?
1051 #endif
1052 (16 + (32+target_info_len))
1053 #ifdef _SIPE_COMPILING_TESTS
1054 : NTLMSSP_LM_RESP_LEN
1055 #endif
1057 gsize msglen = sizeof(struct authenticate_message)
1058 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1059 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1060 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1061 struct authenticate_message *tmsg;
1062 char *tmp;
1063 guint32 offset;
1064 guint16 len;
1065 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1066 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1067 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1068 unsigned char nt_challenge_response [ntlmssp_nt_resp_len]; /* variable or 24 */
1069 unsigned char session_base_key [16];
1070 unsigned char key_exchange_key [16];
1071 unsigned char exported_session_key[16];
1072 unsigned char encrypted_random_session_key [16];
1073 unsigned char key [16];
1074 unsigned char client_challenge [8];
1075 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1077 if (!IS_FLAG(*flags, is_connection_based ?
1078 NEGOTIATE_FLAGS_COMMON_MIN :
1079 NEGOTIATE_FLAGS_COMMON_MIN | NEGOTIATE_FLAGS_CONNLESS_EXTRA))
1081 purple_debug_info("sipe", "sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1082 return SIP_SEC_E_INTERNAL_ERROR;
1085 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1086 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1089 tmsg = g_malloc0(msglen);
1091 NONCE (client_challenge, 8);
1093 #ifdef _SIPE_COMPILING_TESTS
1094 memcpy(client_challenge, test_client_challenge, 8);
1095 time_vl = test_time_val ? test_time_val : time_vl;
1097 if (use_ntlm_v2) {
1099 #endif
1100 NTOWFv2 (password, user, domain, response_key_nt);
1101 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1102 #ifdef _SIPE_COMPILING_TESTS
1103 } else {
1104 NTOWFv1 (password, user, domain, response_key_nt);
1105 LMOWFv1 (password, user, domain, response_key_lm);
1107 #endif
1109 compute_response(neg_flags,
1110 response_key_nt,
1111 response_key_lm,
1112 server_challenge,
1113 client_challenge,
1114 time_vl,
1115 target_info,
1116 target_info_len,
1117 lm_challenge_response, /* out */
1118 nt_challenge_response, /* out */
1119 session_base_key); /* out */
1121 /* same as session_base_key for
1122 * - NTLNv1 w/o Ext.Sess.Sec and
1123 * - NTLMv2
1125 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1127 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1128 NONCE (exported_session_key, 16); // random master key
1129 #ifdef _SIPE_COMPILING_TESTS
1130 memcpy(exported_session_key, test_random_session_key, 16);
1131 #endif
1132 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1133 } else {
1134 memcpy(exported_session_key, key_exchange_key, 16);
1137 tmp = buff_to_hex_str(exported_session_key, 16);
1138 purple_debug_info("sipe", "NTLM AUTHENTICATE: exported session key (not encrypted): %s\n", tmp);
1139 g_free(tmp);
1141 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1142 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1144 /* p.46
1145 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1146 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1148 SIGNKEY(exported_session_key, TRUE, key);
1149 *client_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1150 SIGNKEY(exported_session_key, FALSE, key);
1151 *server_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1152 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1153 *client_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1154 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1155 *server_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1158 /* @TODO: */
1159 /* @since Vista
1160 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1161 the client SHOULD provide a MIC:
1162 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1163 - then in the Value field, set bit 0x2 to 1.
1164 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1165 and the Value field bit 0x2 to 1.
1166 - Populate the MIC field with the MIC.
1169 /* Connection-oriented:
1170 Set MIC to HMAC_MD5(ExportedSessionKey,
1171 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1172 Connectionless:
1173 Set MIC to HMAC_MD5(ExportedSessionKey,
1174 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1177 /* on the server-side:
1178 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1179 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1180 Set MIC to HMAC_MD5(ExportedSessionKey,
1181 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1182 Else
1183 Set ExportedSessionKey to KeyExchangeKey
1184 Set MIC to HMAC_MD5(KeyExchangeKey,
1185 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1186 =====
1187 @since Vista
1188 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1189 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1190 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1191 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1192 an AV_PAIR structure whose two fields:
1193 - AvId == MsvAvFlags
1194 - Value bit 0x2 == 1
1195 @supported NT, 2000, XP
1196 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1197 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1198 the server time, then the server SHOULD return a failure.
1200 Connectionless:
1201 Set MIC to HMAC_MD5(ResponseKeyNT,
1202 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1205 /* authenticate message initialization */
1206 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1207 tmsg->type = GUINT32_TO_LE(3);
1209 /* Initial offset */
1210 offset = sizeof(struct authenticate_message);
1211 tmp = ((char*) tmsg) + offset;
1213 #define _FILL_SMB_HEADER(header) \
1214 tmsg->header.offset = GUINT32_TO_LE(offset); \
1215 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1216 tmp += len; \
1217 offset += len
1218 #define _APPEND_STRING(header, src) \
1219 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1220 _FILL_SMB_HEADER(header)
1221 #define _APPEND_DATA(header, src, srclen) \
1222 len = (srclen); \
1223 memcpy(tmp, (src), len); \
1224 _FILL_SMB_HEADER(header)
1226 /* Domain */
1227 _APPEND_STRING(domain, domain);
1229 /* User */
1230 _APPEND_STRING(user, user);
1232 /* Host */
1233 _APPEND_STRING(host, hostname);
1235 /* LM */
1236 /* @since Windows 7
1237 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1238 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1239 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1241 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1243 /* NT */
1244 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1246 /* Session Key */
1247 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1249 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1251 else
1253 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1254 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1257 /* Version */
1258 #ifdef _SIPE_COMPILING_TESTS
1259 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1260 #else
1261 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1262 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1263 tmsg->ver.product_minor_version = 1;
1264 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1265 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1267 #endif
1269 /* Set Negotiate Flags */
1270 tmsg->flags = GUINT32_TO_LE(neg_flags);
1271 *flags = neg_flags;
1273 out_buff->value = (guint8 *)tmsg;
1274 out_buff->length = msglen;
1276 return SIP_SEC_E_OK;
1280 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1282 static void
1283 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1285 guint32 offset;
1286 guint16 len;
1287 int msglen = sizeof(struct negotiate_message);
1288 struct negotiate_message *tmsg = g_malloc0(msglen);
1290 /* negotiate message initialization */
1291 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1292 tmsg->type = GUINT32_TO_LE(1);
1294 /* Set Negotiate Flags */
1295 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1297 /* Domain */
1298 offset = sizeof(struct negotiate_message);
1299 tmsg->domain.offset = GUINT32_TO_LE(offset);
1300 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1302 /* Host */
1303 offset += len;
1304 tmsg->host.offset = GUINT32_TO_LE(offset);
1305 tmsg->host.len = tmsg->host.maxlen = len = 0;
1307 /* Version */
1308 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1309 tmsg->ver.product_minor_version = 1;
1310 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1311 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1313 out_buff->value = (guint8 *)tmsg;
1314 out_buff->length = msglen;
1317 static gchar *
1318 sip_sec_ntlm_sipe_signature_make (guint32 flags, const char *msg, guint32 random_pad, unsigned char *sign_key, unsigned char *seal_key)
1320 gchar *res = MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100);
1321 purple_debug_info("sipe", "NTLM calculated MAC: %s\n", res);
1322 return res;
1325 static gboolean
1326 sip_sec_ntlm_verify_signature (char * a, char * b)
1328 return g_ascii_strncasecmp(a, b, 16*2) == 0;
1332 /* Describe NTLM messages functions */
1334 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1335 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1337 static gchar *
1338 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1340 GString* str = g_string_new(NULL);
1342 flags = GUINT32_FROM_LE(flags);
1344 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1345 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1346 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1347 APPEND_NEG_FLAG(str, flags, r9, "r9");
1348 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1349 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1350 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1351 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1352 APPEND_NEG_FLAG(str, flags, r8, "r8");
1353 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1354 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1355 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1356 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1357 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1358 APPEND_NEG_FLAG(str, flags, r7, "r7");
1359 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1360 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1361 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1362 APPEND_NEG_FLAG(str, flags, r6, "r6");
1363 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1364 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1365 APPEND_NEG_FLAG(str, flags, r5, "r5");
1366 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1367 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1368 APPEND_NEG_FLAG(str, flags, r4, "r4");
1369 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1370 APPEND_NEG_FLAG(str, flags, r3, "r3");
1371 APPEND_NEG_FLAG(str, flags, r2, "r2");
1372 APPEND_NEG_FLAG(str, flags, r1, "r1");
1373 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1374 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1375 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1377 return g_string_free(str, FALSE);
1380 static gchar *
1381 sip_sec_ntlm_describe_version(struct version *ver) {
1382 GString* str = g_string_new(NULL);
1383 gchar *ver_desc = "";
1384 gchar *ntlm_revision_desc = "";
1386 if (ver->product_major_version == 6) {
1387 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1388 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1389 ver_desc = "Windows Server 2003";
1390 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1391 ver_desc = "Windows XP SP2";
1394 if (ver->ntlm_revision_current == 0x0F) {
1395 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1396 } else if (ver->ntlm_revision_current == 0x0A) {
1397 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1400 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1401 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1402 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1404 return g_string_free(str, FALSE);
1407 static gchar *
1408 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1409 const char* name)
1411 GString* str = g_string_new(NULL);
1413 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1414 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1415 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1417 return g_string_free(str, FALSE);
1420 static gchar *
1421 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1423 GString* str = g_string_new(NULL);
1424 char *tmp;
1426 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1427 g_free(tmp);
1429 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1430 g_free(tmp);
1432 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1433 g_free(tmp);
1435 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1436 g_string_append(str, tmp);
1437 g_free(tmp);
1439 if (cmsg->domain.len && cmsg->domain.offset) {
1440 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1441 g_string_append_printf(str, "\tdomain: %s\n", domain);
1442 g_free(domain);
1445 if (cmsg->host.len && cmsg->host.offset) {
1446 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1447 g_string_append_printf(str, "\thost: %s\n", host);
1448 g_free(host);
1451 return g_string_free(str, FALSE);
1454 static void
1455 describe_av_pairs(GString* str, const void *av)
1457 #define AV_DESC(av_name) \
1459 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1460 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1461 g_free(tmp); \
1464 ALIGN_AV_LOOP_START
1466 case MsvAvNbComputerName:
1467 AV_DESC("MsvAvNbComputerName");
1468 break;
1469 case MsvAvNbDomainName:
1470 AV_DESC("MsvAvNbDomainName");
1471 break;
1472 case MsvAvDnsComputerName:
1473 AV_DESC("MsvAvDnsComputerName");
1474 break;
1475 case MsvAvDnsDomainName:
1476 AV_DESC("MsvAvDnsDomainName");
1477 break;
1478 case MsvAvDnsTreeName:
1479 AV_DESC("MsvAvDnsTreeName");
1480 break;
1481 case MsvAvFlags:
1483 guint32 flags;
1485 /* to meet sparc's alignment requirement */
1486 memcpy(&flags, av_value, sizeof(guint32));
1487 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1489 break;
1490 case MsvAvTimestamp:
1492 char *tmp;
1493 guint64 time_val;
1494 time_t time_t_val;
1496 /* to meet sparc's alignment requirement */
1497 memcpy(&time_val, av_value, sizeof(time_val));
1498 time_t_val = TIME_VAL_TO_T(time_val);
1500 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1501 asctime(gmtime(&time_t_val)));
1502 g_free(tmp);
1504 break;
1505 case MsAvRestrictions:
1506 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1507 break;
1508 case MsvAvTargetName:
1509 AV_DESC("MsvAvTargetName");
1510 break;
1511 case MsvChannelBindings:
1512 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1513 break;
1515 ALIGN_AV_LOOP_END;
1518 static gchar *
1519 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1521 GString* str = g_string_new(NULL);
1522 char *tmp;
1523 gsize value_len;
1524 guint8 *value;
1526 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1527 g_free(tmp);
1529 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1530 g_free(tmp);
1532 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1533 g_free(tmp);
1535 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1536 g_free(tmp);
1538 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1539 g_free(tmp);
1541 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1542 g_free(tmp);
1544 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1545 g_free(tmp);
1547 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1548 g_string_append(str, tmp);
1549 g_free(tmp);
1551 /* mic */
1552 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1553 //g_free(tmp);
1555 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1556 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1557 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1558 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1559 g_free(tmp);
1562 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1563 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1564 int nt_resp_len = nt_resp_len_full;
1566 value_len = nt_resp_len_full;
1567 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1568 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1569 g_free(tmp);
1571 if (nt_resp_len > 24) { /* NTLMv2 */
1572 nt_resp_len = 16;
1575 value_len = nt_resp_len;
1576 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1577 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1578 g_free(tmp);
1580 if (nt_resp_len_full > 24) { /* NTLMv2 */
1581 char *tmp;
1582 const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1583 const guint response_version = *((guchar*)temp);
1584 const guint hi_response_version = *((guchar*)(temp+1));
1585 guint64 time_val;
1586 time_t time_t_val;
1587 const guint8 *client_challenge = temp + 16;
1588 const guint8 *target_info = temp + 28;
1589 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1591 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1592 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1593 g_free(tmp);
1595 /* This is not int64 aligned on sparc */
1596 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1597 time_t_val = TIME_VAL_TO_T(time_val);
1599 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1600 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1602 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1603 asctime(gmtime(&time_t_val)));
1604 g_free(tmp);
1606 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1607 g_free(tmp);
1609 describe_av_pairs(str, target_info);
1611 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1615 if (cmsg->domain.len && cmsg->domain.offset) {
1616 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1617 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1618 g_free(domain);
1621 if (cmsg->user.len && cmsg->user.offset) {
1622 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1623 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1624 g_free(user);
1627 if (cmsg->host.len && cmsg->host.offset) {
1628 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1629 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1630 g_free(host);
1633 if (cmsg->session_key.len && cmsg->session_key.offset) {
1634 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1635 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1636 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1637 g_free(tmp);
1640 return g_string_free(str, FALSE);
1643 static gchar *
1644 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1646 GString* str = g_string_new(NULL);
1647 char *tmp;
1649 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1650 g_free(tmp);
1652 /* nonce (server_challenge) */
1653 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1654 g_free(tmp);
1656 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1657 g_free(tmp);
1659 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1660 g_free(tmp);
1662 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1663 g_free(tmp);
1665 if (cmsg->target_name.len && cmsg->target_name.offset) {
1666 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1667 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1668 g_free(target_name);
1671 if (cmsg->target_info.len && cmsg->target_info.offset) {
1672 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1673 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1675 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1676 g_free(tmp);
1678 describe_av_pairs(str, target_info);
1681 return g_string_free(str, FALSE);
1684 gchar *
1685 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1687 struct ntlm_message *msg;
1688 gchar *res = NULL;
1690 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1692 msg = (struct ntlm_message *)buff.value;
1693 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1695 switch (GUINT32_FROM_LE(msg->type)) {
1696 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1697 break;
1698 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1699 break;
1700 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1701 break;
1704 return res;
1707 /* sip-sec-mech.h API implementation for NTLM */
1709 /* Security context for NTLM */
1710 typedef struct _context_ntlm {
1711 struct sip_sec_context common;
1712 char* domain;
1713 char *username;
1714 char *password;
1715 int step;
1716 guchar *client_sign_key;
1717 guchar *server_sign_key;
1718 guchar *client_seal_key;
1719 guchar *server_seal_key;
1720 guint32 flags;
1721 } *context_ntlm;
1724 static sip_uint32
1725 sip_sec_acquire_cred__ntlm(SipSecContext context,
1726 const char *domain,
1727 const char *username,
1728 const char *password)
1730 context_ntlm ctx = (context_ntlm)context;
1732 /* NTLM requires a domain, username & password */
1733 if (!domain || !username || !password)
1734 return SIP_SEC_E_INTERNAL_ERROR;
1736 ctx->domain = g_strdup(domain);
1737 ctx->username = g_strdup(username);
1738 ctx->password = g_strdup(password);
1740 return SIP_SEC_E_OK;
1743 static sip_uint32
1744 sip_sec_init_sec_context__ntlm(SipSecContext context,
1745 SipSecBuffer in_buff,
1746 SipSecBuffer *out_buff,
1747 SIPE_UNUSED_PARAMETER const char *service_name)
1749 context_ntlm ctx = (context_ntlm) context;
1751 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1753 ctx->step++;
1754 if (ctx->step == 1) {
1755 if (!context->is_connection_based) {
1756 out_buff->length = 0;
1757 out_buff->value = NULL;
1758 } else {
1759 sip_sec_ntlm_gen_negotiate(out_buff);
1761 return SIP_SEC_I_CONTINUE_NEEDED;
1763 } else {
1764 sip_uint32 res;
1765 guchar *client_sign_key = NULL;
1766 guchar *server_sign_key = NULL;
1767 guchar *client_seal_key = NULL;
1768 guchar *server_seal_key = NULL;
1769 guchar *server_challenge = NULL;
1770 guint64 time_val = 0;
1771 guchar *target_info = NULL;
1772 int target_info_len = 0;
1773 guint32 flags;
1774 gchar *tmp;
1776 if (!in_buff.value || !in_buff.length) {
1777 return SIP_SEC_E_INTERNAL_ERROR;
1780 sip_sec_ntlm_parse_challenge(in_buff,
1781 &flags,
1782 &server_challenge, /* 8 bytes */
1783 &time_val,
1784 &target_info,
1785 &target_info_len);
1787 res = sip_sec_ntlm_gen_authenticate(
1788 &client_sign_key,
1789 &server_sign_key,
1790 &client_seal_key,
1791 &server_seal_key,
1792 ctx->username,
1793 ctx->password,
1794 (tmp = g_ascii_strup(sipe_get_host_name(), -1)),
1795 ctx->domain,
1796 server_challenge,
1797 time_val,
1798 target_info,
1799 target_info_len,
1800 context->is_connection_based,
1801 out_buff,
1802 &flags);
1803 g_free(server_challenge);
1804 g_free(target_info);
1805 g_free(tmp);
1807 if (res != SIP_SEC_E_OK) {
1808 g_free(client_sign_key);
1809 g_free(server_sign_key);
1810 g_free(client_seal_key);
1811 g_free(server_seal_key);
1812 return res;
1815 g_free(ctx->client_sign_key);
1816 ctx->client_sign_key = client_sign_key;
1818 g_free(ctx->server_sign_key);
1819 ctx->server_sign_key = server_sign_key;
1821 g_free(ctx->client_seal_key);
1822 ctx->client_seal_key = client_seal_key;
1824 g_free(ctx->server_seal_key);
1825 ctx->server_seal_key = server_seal_key;
1827 ctx->flags = flags;
1828 return SIP_SEC_E_OK;
1833 * @param message a NULL terminated string to sign
1836 static sip_uint32
1837 sip_sec_make_signature__ntlm(SipSecContext context,
1838 const char *message,
1839 SipSecBuffer *signature)
1841 /* FIXME? We always use a random_pad of 0 */
1842 gchar *signature_hex = sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1843 message,
1845 ((context_ntlm) context)->client_sign_key,
1846 ((context_ntlm) context)->client_seal_key);
1848 signature->length = hex_str_to_buff(signature_hex, &signature->value);
1849 g_free(signature_hex);
1851 return SIP_SEC_E_OK;
1855 * @param message a NULL terminated string to check signature of
1856 * @return SIP_SEC_E_OK on success
1858 static sip_uint32
1859 sip_sec_verify_signature__ntlm(SipSecContext context,
1860 const char *message,
1861 SipSecBuffer signature)
1863 guint32 random_pad = GUINT32_FROM_LE(((guint32 *) signature.value)[1]);
1864 char *signature_hex = buff_to_hex_str(signature.value, signature.length);
1865 gchar *signature_calc = sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1866 message,
1867 random_pad,
1868 ((context_ntlm) context)->server_sign_key,
1869 ((context_ntlm) context)->server_seal_key);
1870 sip_uint32 res;
1872 if (sip_sec_ntlm_verify_signature(signature_calc, signature_hex)) {
1873 res = SIP_SEC_E_OK;
1874 } else {
1875 res = SIP_SEC_E_INTERNAL_ERROR;
1877 g_free(signature_calc);
1878 g_free(signature_hex);
1879 return(res);
1882 static void
1883 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1885 context_ntlm ctx = (context_ntlm) context;
1887 g_free(ctx->domain);
1888 g_free(ctx->username);
1889 g_free(ctx->password);
1890 g_free(ctx->client_sign_key);
1891 g_free(ctx->server_sign_key);
1892 g_free(ctx->client_seal_key);
1893 g_free(ctx->server_seal_key);
1894 g_free(ctx);
1897 SipSecContext
1898 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1900 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1901 if (!context) return(NULL);
1903 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1904 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1905 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1906 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1907 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1909 return((SipSecContext) context);
1912 void sip_sec_init__ntlm(void)
1914 #ifdef HAVE_LANGINFO_CODESET
1915 const char *sys_cp = nl_langinfo(CODESET);
1916 #else
1917 const char *sys_cp = SIPE_DEFAULT_CODESET;
1918 #endif /* HAVE_LANGINFO_CODESET */
1920 /* fall back to utf-8 */
1921 if (!sys_cp) sys_cp = "UTF-8";
1923 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1924 if (convert_from_utf16le == (GIConv)-1) {
1925 purple_debug_error("sipe", "g_iconv_open from UTF-16LE to %s failed\n",
1926 sys_cp);
1929 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1930 if (convert_from_utf16le == (GIConv)-1) {
1931 purple_debug_error("sipe", "g_iconv_open from %s to UTF-16LE failed\n",
1932 sys_cp);
1936 void sip_sec_destroy__ntlm(void)
1938 g_iconv_close(convert_to_utf16le);
1939 g_iconv_close(convert_from_utf16le);
1943 Local Variables:
1944 mode: c
1945 c-file-style: "bsd"
1946 indent-tabs-mode: t
1947 tab-width: 8
1948 End: