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 #include <glib/gprintf.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <sys/types.h>
43 #include <netinet/in.h>
46 #include "libc_interface.h"
50 #define _LIBC_INTERNAL_
56 #ifdef HAVE_LANGINFO_CODESET
58 #endif /* HAVE_LANGINFO_CODESET */
64 #include "sipe-utils.h"
65 #include "sip-sec-mech.h"
66 #include "sip-sec-ntlm.h"
69 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
70 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
71 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
72 #define r9 0x00000008 /* r9 */
73 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
74 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
75 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
76 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
77 #define r8 0x00000100 /* r8 */
78 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
79 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
80 #define anonymous 0x00000800 /* J */
81 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
82 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
83 #define r7 0x00004000 /* r7 */
84 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
85 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
86 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
87 #define r6 0x00040000 /* r6 */
88 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
89 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
90 #define r5 0x00200000 /* r5 */
91 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
92 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
93 #define r4 0x01000000 /* r4 */
94 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
95 #define r3 0x04000000 /* r3 */
96 #define r2 0x08000000 /* r2 */
97 #define r1 0x10000000 /* r1 */
98 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
99 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
100 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
104 #define MsvAvNbComputerName 1
105 #define MsvAvNbDomainName 2
106 #define MsvAvDnsComputerName 3
107 #define MsvAvDnsDomainName 4
108 /** @since Windows XP */
109 #define MsvAvDnsTreeName 5
110 /** @since Windows XP */
112 /** @since Windows Vista */
113 #define MsvAvTimestamp 7
114 /** @since Windows Vista */
115 #define MsAvRestrictions 8
116 /** @since Windows 7 */
117 #define MsvAvTargetName 9
118 /** @since Windows 7 */
119 #define MsvChannelBindings 10
121 /***********************************************
123 * Start of merged code from original sip-ntlm.c
125 ***********************************************/
127 /* Negotiate flags required in connection-oriented NTLM */
128 #define NEGOTIATE_FLAGS_CONN \
129 ( NTLMSSP_NEGOTIATE_UNICODE | \
130 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
131 NTLMSSP_REQUEST_TARGET | \
132 NTLMSSP_NEGOTIATE_NTLM | \
133 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
136 /* Negotiate flags required in connectionless NTLM */
137 #define NEGOTIATE_FLAGS \
138 ( NTLMSSP_NEGOTIATE_UNICODE | \
139 NTLMSSP_NEGOTIATE_SIGN | \
140 NTLMSSP_NEGOTIATE_DATAGRAM | \
141 NTLMSSP_NEGOTIATE_NTLM | \
142 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
143 NTLMSSP_NEGOTIATE_KEY_EXCH )
145 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
147 #define NTLMSSP_NT_OR_LM_KEY_LEN 24
148 #define NTLMSSP_SESSION_KEY_LEN 16
149 #define MD4_DIGEST_LEN 16
150 #define MD5_DIGEST_LEN 16
152 #define IS_FLAG(flags, flag) ((flags & flag) == flag)
162 guint8 product_major_version
;
163 guint8 product_minor_version
;
164 guint16 product_build
;
166 guint8 ntlm_revision_current
;
176 struct ntlm_message
{
177 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
178 guint32 type
; /* 0x00000003 */
181 struct negotiate_message
{
182 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
183 guint32 type
; /* 0x00000001 */
184 guint32 flags
; /* 0xb203 */
185 struct smb_header domain
;
186 struct smb_header host
;
189 * - DomainName (always ASCII)
190 * - WorkstationName (always ASCII)
194 struct challenge_message
{
195 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
196 guint32 type
; /* 0x00000002 */
197 struct smb_header target_name
;
198 guint32 flags
; /* 0x8201 */
201 struct smb_header target_info
;
204 * - TargetName (negotiated encoding)
205 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
209 struct authenticate_message
{
210 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
211 guint32 type
; /* 0x00000003 */
212 /** LmChallengeResponseFields */
213 struct smb_header lm_resp
;
214 /** NtChallengeResponseFields */
215 struct smb_header nt_resp
;
216 /** DomainNameFields */
217 struct smb_header domain
;
218 /** UserNameFields */
219 struct smb_header user
;
220 /** WorkstationFields */
221 struct smb_header host
;
222 /** EncryptedRandomSessionKeyFields */
223 struct smb_header session_key
;
228 * - LmChallengeResponse
229 * - NtChallengeResponse
230 * - DomainName (negotiated encoding)
231 * - UserName (negotiated encoding)
232 * - Workstation (negotiated encoding)
233 * - EncryptedRandomSessionKey
237 #ifndef HAVE_LANGINFO_CODESET
238 static char SIPE_DEFAULT_CODESET
[] = "ANSI_X3.4-1968";
241 /* Private Methods */
243 static void setup_des_key(const unsigned char key_56
[], unsigned char *key
)
246 key
[1] = ((key_56
[0] << 7) & 0xFF) | (key_56
[1] >> 1);
247 key
[2] = ((key_56
[1] << 6) & 0xFF) | (key_56
[2] >> 2);
248 key
[3] = ((key_56
[2] << 5) & 0xFF) | (key_56
[3] >> 3);
249 key
[4] = ((key_56
[3] << 4) & 0xFF) | (key_56
[4] >> 4);
250 key
[5] = ((key_56
[4] << 3) & 0xFF) | (key_56
[5] >> 5);
251 key
[6] = ((key_56
[5] << 2) & 0xFF) | (key_56
[6] >> 6);
252 key
[7] = (key_56
[6] << 1) & 0xFF;
255 static void des_ecb_encrypt(const unsigned char *plaintext
, unsigned char *result
, const unsigned char *key
)
257 PurpleCipher
*cipher
;
258 PurpleCipherContext
*context
;
261 cipher
= purple_ciphers_find_cipher("des");
262 context
= purple_cipher_context_new(cipher
, NULL
);
263 purple_cipher_context_set_key(context
, (guchar
*)key
);
264 purple_cipher_context_encrypt(context
, (guchar
*)plaintext
, 8, (guchar
*)result
, &outlen
);
265 purple_cipher_context_destroy(context
);
269 unicode_strconvcopy_dir(gchar
*dest
, const gchar
*source
, int remlen
, gsize source_len
, gboolean to_16LE
)
272 gchar
*inbuf
= (gchar
*) source
;
273 gchar
*outbuf
= dest
;
274 gsize inbytes
= source_len
;
275 gsize outbytes
= remlen
;
276 #ifdef HAVE_LANGINFO_CODESET
277 char *sys_cp
= nl_langinfo(CODESET
);
279 char *sys_cp
= SIPE_DEFAULT_CODESET
;
280 #endif /* HAVE_LANGINFO_CODESET */
282 /* fall back to utf-8 */
283 if (!sys_cp
) sys_cp
= "UTF-8";
285 fd
= to_16LE
? g_iconv_open("UTF-16LE", sys_cp
) : g_iconv_open(sys_cp
, "UTF-16LE");
286 if( fd
== (GIConv
)-1 ) {
287 purple_debug_error( "sipe", "iconv_open returned -1, cannot continue\n" );
289 g_iconv(fd
, &inbuf
, &inbytes
, &outbuf
, &outbytes
);
291 return (remlen
- outbytes
);
295 unicode_strconvcopy(gchar
*dest
, const gchar
*source
, int remlen
)
297 return unicode_strconvcopy_dir(dest
, source
, remlen
, strlen(source
), TRUE
);
300 /* UTF-16LE to native encoding
301 * Must be g_free'd after use */
303 unicode_strconvcopy_back(const gchar
*source
,
307 int dest_len
= 2 * len
;
308 gchar
*dest
= g_new0(gchar
, dest_len
);
310 dest_len
= unicode_strconvcopy_dir(dest
, source
, dest_len
, len
, FALSE
);
311 res
= g_strndup(dest
, dest_len
);
317 // (k = 7 byte key, d = 8 byte data) returns 8 bytes in results
319 DES (const unsigned char *k
, const unsigned char *d
, unsigned char * results
)
321 unsigned char key
[8];
322 setup_des_key(k
, key
);
323 des_ecb_encrypt(d
, results
, key
);
326 // (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results:
328 DESL (unsigned char *k
, const unsigned char *d
, unsigned char * results
)
330 unsigned char keys
[21];
332 // Copy the first 16 bytes
335 // Zero out the last 5 bytes of the key
336 memset(keys
+ 16, 0, 5);
338 DES(keys
, d
, results
);
339 DES(keys
+ 7, d
, results
+ 8);
340 DES(keys
+ 14, d
, results
+ 16);
345 MD4 (const unsigned char * d
, int len
, unsigned char * result
)
347 PurpleCipher
* cipher
= purple_ciphers_find_cipher("md4");
348 PurpleCipherContext
* context
= purple_cipher_context_new(cipher
, NULL
);
349 purple_cipher_context_append(context
, (guchar
*)d
, len
);
350 purple_cipher_context_digest(context
, MD4_DIGEST_LEN
, (guchar
*)result
, NULL
);
351 purple_cipher_context_destroy(context
);
356 MD5 (const unsigned char * d
, int len
, unsigned char * result
)
358 PurpleCipher
* cipher
= purple_ciphers_find_cipher("md5");
359 PurpleCipherContext
* context
= purple_cipher_context_new(cipher
, NULL
);
360 purple_cipher_context_append(context
, (guchar
*)d
, len
);
361 purple_cipher_context_digest(context
, MD5_DIGEST_LEN
, (guchar
*)result
, NULL
);
362 purple_cipher_context_destroy(context
);
368 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
371 unsigned char ibuff[64 + data_len];
372 unsigned char obuff[64 + 16];
377 for (i = 0; i < key_len; i++) {
378 ibuff[i] = key[i] ^ 0x36;
379 obuff[i] = key[i] ^ 0x5c;
381 for (i = key_len; i < 64; i++) {
386 memcpy(ibuff+64, data, data_len);
388 MD5 (ibuff, 64 + data_len, obuff+64);
389 MD5 (obuff, 64 + 16, result);
391 #define HMAC_MD5 HMACT64
396 HMAC_MD5 (const unsigned char *key
, int key_len
, const unsigned char *data
, int data_len
, unsigned char *result
)
398 PurpleCipher
*cipher
= purple_ciphers_find_cipher("hmac");
399 PurpleCipherContext
*context
= purple_cipher_context_new(cipher
, NULL
);
401 purple_cipher_context_set_option(context
, "hash", "md5");
402 purple_cipher_context_set_key_with_len(context
, (guchar
*)key
, (key_len
));
404 purple_cipher_context_append(context
, (guchar
*)data
, data_len
);
405 purple_cipher_context_digest(context
, 16, (guchar
*)result
, NULL
);
406 purple_cipher_context_destroy(context
);
410 Define NTOWFv1(Passwd, User, UserDom) as
416 NTOWFv1 (const char* password
, SIPE_UNUSED_PARAMETER
const char *user
, SIPE_UNUSED_PARAMETER
const char *domain
, unsigned char *result
)
418 int len
= 2 * strlen(password
); // utf16 should not be more
419 unsigned char *unicode_password
= g_new0(unsigned char, len
);
421 len
= unicode_strconvcopy((gchar
*) unicode_password
, password
, len
);
422 MD4 (unicode_password
, len
, result
);
423 g_free(unicode_password
);
427 Define NTOWFv2(Passwd, User, UserDom) as
428 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
433 NTOWFv2 (const char* password
, const char *user
, const char *domain
, unsigned char *result
)
435 unsigned char response_key_nt_v1
[16];
436 int len_user
= user
? strlen(user
) : 0;
437 int len_domain
= domain
? strlen(domain
) : 0;
438 unsigned char user_upper
[len_user
+ 1];
439 int len_user_u
= 2 * len_user
; // utf16 should not be more
440 int len_domain_u
= 2 * len_domain
; // utf16 should not be more
441 unsigned char buff
[(len_user
+ len_domain
)*2];
445 for (i
= 0; i
< len_user
; i
++) {
446 user_upper
[i
] = g_ascii_toupper(user
[i
]);
448 user_upper
[len_user
] = 0;
450 len_user_u
= unicode_strconvcopy((gchar
*)buff
, (gchar
*)user_upper
, len_user_u
);
451 len_domain_u
= unicode_strconvcopy((gchar
*)(buff
+len_user_u
), (gchar
*)domain
, len_domain_u
);
453 NTOWFv1(password
, user
, domain
, response_key_nt_v1
);
455 HMAC_MD5(response_key_nt_v1
, 16, buff
, len_user_u
+ len_domain_u
, result
);
459 RC4K (const unsigned char * k
, unsigned long key_len
, const unsigned char * d
, int len
, unsigned char * result
)
461 PurpleCipherContext
* context
= purple_cipher_context_new_by_name("rc4", NULL
);
462 purple_cipher_context_set_option(context
, "key_len", (gpointer
)key_len
);
463 purple_cipher_context_set_key(context
, k
);
464 purple_cipher_context_encrypt(context
, (const guchar
*)d
, len
, result
, NULL
);
465 purple_cipher_context_destroy(context
);
469 KXKEY ( guint32 flags
,
470 const unsigned char * session_base_key
,
471 const unsigned char * lm_challenge_resonse
,
472 const guint8
* server_challenge
, /* 8-bytes, nonce */
473 unsigned char * key_exchange_key
)
475 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
)) {
476 // Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
477 // Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
480 memcpy(tmp
, server_challenge
, 8);
481 memcpy(tmp
+8, lm_challenge_resonse
, 8);
482 HMAC_MD5(session_base_key
, 16, tmp
, 16, key_exchange_key
);
484 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
485 memcpy(key_exchange_key
, session_base_key
, 16);
490 // This method is only used for NTLMv2 and extended session security
492 If (Mode equals "Client")
493 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
494 "session key to client-to-server signing key magic constant"))
496 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
497 "session key to server-to-client signing key magic constant"))
501 SIGNKEY (const unsigned char * random_session_key
, gboolean client
, unsigned char * result
)
503 char * magic
= client
504 ? "session key to client-to-server signing key magic constant"
505 : "session key to server-to-client signing key magic constant";
507 int len
= strlen(magic
) + 1;
508 unsigned char md5_input
[16 + len
];
509 memcpy(md5_input
, random_session_key
, 16);
510 memcpy(md5_input
+ 16, magic
, len
);
512 MD5 (md5_input
, len
+ 16, result
);
516 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
517 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
518 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
519 Set SealKey to RandomSessionKey
520 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
521 Set SealKey to RandomSessionKey[0..6]
523 Set SealKey to RandomSessionKey[0..4]
526 If (Mode equals "Client")
527 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
529 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
532 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
533 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
535 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
539 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
541 SEALKEY (guint32 flags
, const unsigned char * random_session_key
, gboolean client
, unsigned char * result
)
543 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
))
545 char * magic
= client
546 ? "session key to client-to-server sealing key magic constant"
547 : "session key to server-to-client sealing key magic constant";
549 int len
= strlen(magic
) + 1;
550 unsigned char md5_input
[16 + len
];
553 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_128
)) {
554 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key (Extended session security)\n");
556 } else if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_56
)) {
557 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key (Extended session security)\n");
560 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key (Extended session security)\n");
564 memcpy(md5_input
, random_session_key
, key_len
);
565 memcpy(md5_input
+ key_len
, magic
, len
);
567 MD5 (md5_input
, key_len
+ len
, result
);
571 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_56
)) {
572 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key\n");
573 memcpy(result
, random_session_key
, 7);
576 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key\n");
577 memcpy(result
, random_session_key
, 5);
586 LMOWFv1 (const char *password
, SIPE_UNUSED_PARAMETER
const char *user
, SIPE_UNUSED_PARAMETER
const char *domain
, unsigned char *result
)
589 unsigned char magic
[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
590 unsigned char uppercase_password
[14];
593 int len
= strlen(password
);
598 // Uppercase password
599 for (i
= 0; i
< len
; i
++) {
600 uppercase_password
[i
] = g_ascii_toupper(password
[i
]);
604 for (; i
< 14; i
++) {
605 uppercase_password
[i
] = 0;
608 DES (uppercase_password
, magic
, result
);
609 DES (uppercase_password
+ 7, magic
, result
+ 8);
613 NONCE(unsigned char *buffer
, int num
)
616 for (i
= 0; i
< num
; i
++) {
617 buffer
[i
] = (rand() & 0xff);
622 Z(unsigned char *buffer
, int num
)
625 for (i
= 0; i
< num
; i
++) {
630 /* End Private Methods */
633 sip_sec_ntlm_challenge_message_describe(struct challenge_message
*cmsg
);
636 purple_ntlm_parse_challenge(SipSecBuffer in_buff
,
637 gboolean is_connection_based
,
640 guint32 our_flags
= is_connection_based
? NEGOTIATE_FLAGS_CONN
: NEGOTIATE_FLAGS
;
641 static gchar nonce
[8];
642 struct challenge_message
*cmsg
= (struct challenge_message
*)in_buff
.value
;
644 memcpy(nonce
, cmsg
->nonce
, 8);
646 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", cmsg
->flags
, (cmsg
->flags
& our_flags
) == our_flags
);
649 *flags
= cmsg
->flags
;
654 /* source copy from gg's common.c */
655 static guint32 crc32_table
[256];
656 static int crc32_initialized
= 0;
658 static void crc32_make_table()
663 memset(crc32_table
, 0, sizeof(crc32_table
));
665 for (i
= 128; i
; i
>>= 1) {
666 h
= (h
>> 1) ^ ((h
& 1) ? 0xedb88320L
: 0);
668 for (j
= 0; j
< 256; j
+= 2 * i
)
669 crc32_table
[i
+ j
] = crc32_table
[j
] ^ h
;
672 crc32_initialized
= 1;
675 static guint32
crc32(guint32 crc
, const guint8
*buf
, int len
)
677 if (!crc32_initialized
)
686 crc
= (crc
>> 8) ^ crc32_table
[(crc
^ *buf
++) & 0xff];
688 return crc
^ 0xffffffffL
;
692 CRC32 (const char *msg
, int len
)
694 guint32 crc
= 0L;//crc32(0L, Z_NULL, 0);
695 crc
= crc32(crc
, (guint8
*) msg
, len
);
696 //char * ptr = (char*) &crc;
697 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
702 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
703 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
704 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
705 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
707 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
708 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
709 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
711 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
713 // Version(4), RandomPad(4), Checksum(4), SeqNum(4)
714 // Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
715 // MAC(Handle, SigningKey, SeqNum, Message)
720 unsigned char *sign_key
,
721 unsigned long sign_key_len
,
722 unsigned char *seal_key
,
723 unsigned long seal_key_len
,
729 gchar signature
[33];
732 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
)) {
734 Define MAC(Handle, SigningKey, SeqNum, Message) as
735 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
736 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
737 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
738 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
739 Set SeqNum to SeqNum + 1
742 /* If a key exchange key is negotiated
743 Define MAC(Handle, SigningKey, SeqNum, Message) as
744 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
745 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
746 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
747 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
748 Set SeqNum to SeqNum + 1
752 guchar tmp
[4 + buf_len
];
754 purple_debug_info("sipe", "NTLM MAC(): Extented Session Security\n");
756 res_ptr
= (gint32
*)result
;
757 res_ptr
[0] = 0x00000001; // 4 bytes
758 res_ptr
[3] = sequence
;
760 res_ptr
= (gint32
*)tmp
;
761 res_ptr
[0] = sequence
;
762 memcpy(tmp
+4, buf
, buf_len
);
764 HMAC_MD5(sign_key
, sign_key_len
, tmp
, 4 + buf_len
, hmac
);
766 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
)) {
767 purple_debug_info("sipe", "NTLM MAC(): Key Exchange\n");
768 RC4K(seal_key
, seal_key_len
, hmac
, 8, result
+4);
769 //RC4K(sign_key, sign_key_len, hmac, 8, result+4);
771 purple_debug_info("sipe", "NTLM MAC(): *NO* Key Exchange\n");
772 memcpy(result
+4, hmac
, 8);
775 //SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
776 //RC4Init(Handle, SealingKey')
777 ///MD5 (seal_key, 8, seal_key_);
779 /* The content of the first 4 bytes is irrelevant */
780 gint32 plaintext
[] = {0, CRC32(buf
, strlen(buf
)), sequence
}; // 4, 4, 4 bytes
782 purple_debug_info("sipe", "NTLM MAC(): *NO* Extented Session Security\n");
784 RC4K(sign_key
, sign_key_len
, (const guchar
*)plaintext
, 12, result
+4);
785 //RC4K(seal_key, 8, (const guchar *)plaintext, 12, result+4);
787 res_ptr
= (gint32
*)result
;
788 // Highest four bytes are the Version
789 res_ptr
[0] = 0x00000001; // 4 bytes
791 // Replace the first four bytes of the ciphertext with the random_pad
792 res_ptr
[1] = random_pad
; // 4 bytes
795 for (i
= 0, j
= 0; i
< 16; i
++, j
+=2) {
796 g_sprintf(&signature
[j
], "%02X", result
[i
]);
799 return g_strdup(signature
);
803 purple_ntlm_sipe_signature_make (guint32 flags
, const char * msg
, guint32 random_pad
, unsigned char * signing_key
)
805 return MAC(flags
, msg
, strlen(msg
), signing_key
, 16, 0,16, random_pad
, 100);
809 purple_ntlm_verify_signature (char * a
, char * b
)
812 * Make sure the last 24 bytes match
816 return g_ascii_strncasecmp(a
+ 8, b
+ 8, 24) == 0;
820 purple_ntlm_gen_authenticate(guchar
**ntlm_key
, /* signing key */
822 const gchar
*password
,
823 const gchar
*hostname
,
825 const guint8
*nonce
, /* server challenge */
826 gboolean is_connection_based
,
827 SipSecBuffer
*out_buff
,
830 guint32 neg_flags
= is_connection_based
? NEGOTIATE_FLAGS_CONN
: NEGOTIATE_FLAGS
;
831 gboolean is_key_exch
= IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
);
832 int msglen
= sizeof(struct authenticate_message
) + 2*(strlen(domain
)
833 + strlen(user
)+ strlen(hostname
) + NTLMSSP_NT_OR_LM_KEY_LEN
)
834 + (is_key_exch
? NTLMSSP_SESSION_KEY_LEN
: 0);
835 struct authenticate_message
*tmsg
= g_malloc0(msglen
);
838 unsigned char response_key_lm
[16];
839 unsigned char lm_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
840 unsigned char response_key_nt
[16];
841 unsigned char nt_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
842 unsigned char session_base_key
[16];
843 unsigned char key_exchange_key
[16];
844 unsigned char exported_session_key
[16];
845 unsigned char encrypted_random_session_key
[16];
846 unsigned char client_signing_key
[16];
848 NTOWFv1 (password
, user
, domain
, response_key_nt
);
849 LMOWFv1 (password
, user
, domain
, response_key_lm
);
851 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_LM_KEY
)) {
852 // @TODO do not even reference nt_challenge_response
853 Z (nt_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
854 DESL (response_key_lm
, nonce
, lm_challenge_response
);
855 } else if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
)) {
856 unsigned char client_challenge
[8];
857 unsigned char prehash
[16];
858 unsigned char hash
[16];
860 NONCE (client_challenge
, 8);
862 /* nt_challenge_response */
863 memcpy(prehash
, nonce
, 8);
864 memcpy(prehash
+ 8, client_challenge
, 8);
865 MD5 (prehash
, 16, hash
);
866 DESL (response_key_nt
, hash
, nt_challenge_response
);
868 /* lm_challenge_response */
869 memcpy(lm_challenge_response
, client_challenge
, 8);
870 Z (lm_challenge_response
+8, 16);
872 DESL (response_key_nt
, nonce
, nt_challenge_response
);
873 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_NT_ONLY
)) {
874 memcpy(lm_challenge_response
, nt_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
876 DESL (response_key_lm
, nonce
, lm_challenge_response
);
880 /* authenticate message initialization */
881 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
884 /* Set Negotiate Flags */
885 tmsg
->flags
= neg_flags
;
888 tmsg
->domain
.offset
= sizeof(struct authenticate_message
);
889 tmp
= ((char*) tmsg
) + sizeof(struct authenticate_message
);
890 remlen
= ((char *)tmsg
)+msglen
-tmp
;
891 tmsg
->domain
.len
= tmsg
->domain
.maxlen
= unicode_strconvcopy(tmp
, domain
, remlen
);
892 tmp
+= tmsg
->domain
.len
;
893 remlen
= ((char *)tmsg
)+msglen
-tmp
;
896 tmsg
->user
.offset
= tmsg
->domain
.offset
+ tmsg
->domain
.len
;
897 tmsg
->user
.len
= tmsg
->user
.maxlen
= unicode_strconvcopy(tmp
, user
, remlen
);
898 tmp
+= tmsg
->user
.len
;
899 remlen
= ((char *)tmsg
)+msglen
-tmp
;
902 tmsg
->host
.offset
= tmsg
->user
.offset
+ tmsg
->user
.len
;
903 tmsg
->host
.len
= tmsg
->host
.maxlen
= unicode_strconvcopy(tmp
, hostname
, remlen
);
904 tmp
+= tmsg
->host
.len
;
907 tmsg
->lm_resp
.len
= tmsg
->lm_resp
.maxlen
= NTLMSSP_NT_OR_LM_KEY_LEN
;
908 tmsg
->lm_resp
.offset
= tmsg
->host
.offset
+ tmsg
->host
.len
;
909 memcpy(tmp
, lm_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
910 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
913 tmsg
->nt_resp
.len
= tmsg
->nt_resp
.maxlen
= NTLMSSP_NT_OR_LM_KEY_LEN
;
914 tmsg
->nt_resp
.offset
= tmsg
->lm_resp
.offset
+ tmsg
->lm_resp
.len
;
915 memcpy(tmp
, nt_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
916 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
919 MD4(response_key_nt
, 16, session_base_key
); // "User Session Key" -> "master key"
920 KXKEY(neg_flags
, session_base_key
, lm_challenge_response
, nonce
, key_exchange_key
); // same for NTLNv1 w/o Ext.Sess.Sec
924 tmsg
->session_key
.len
= tmsg
->session_key
.maxlen
= NTLMSSP_SESSION_KEY_LEN
;
925 tmsg
->session_key
.offset
= tmsg
->nt_resp
.offset
+ tmsg
->nt_resp
.len
;
927 NONCE (exported_session_key
, 16); // random master key
928 RC4K (key_exchange_key
, 16, exported_session_key
, 16, encrypted_random_session_key
);
930 memcpy(tmp
, encrypted_random_session_key
, 16);
931 tmp
+= NTLMSSP_SESSION_KEY_LEN
;
935 tmsg
->session_key
.len
= tmsg
->session_key
.maxlen
= 0;
936 tmsg
->session_key
.offset
= tmsg
->nt_resp
.offset
+ tmsg
->nt_resp
.len
;
938 memcpy(exported_session_key
, key_exchange_key
, 16);
941 //Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
942 //Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
943 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
)) {
944 SIGNKEY(exported_session_key
, FALSE
, client_signing_key
); //Server
946 memcpy(client_signing_key
, exported_session_key
, 16);
948 *ntlm_key
= (guchar
*)g_strndup((gchar
*)client_signing_key
, 16);
952 tmp
= purple_base64_encode(exported_session_key
, 16);
953 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE session key: %s\n", tmp
);
956 out_buff
->value
= tmsg
;
957 out_buff
->length
= msglen
;
961 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
964 purple_ntlm_gen_negotiate(SipSecBuffer
*out_buff
)
966 int msglen
= sizeof(struct negotiate_message
);
967 struct negotiate_message
*tmsg
= g_malloc0(msglen
);
969 /* negotiate message initialization */
970 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
973 /* Set Negotiate Flags */
974 tmsg
->flags
= NEGOTIATE_FLAGS_CONN
;
977 tmsg
->domain
.offset
= sizeof(struct negotiate_message
);
978 tmsg
->domain
.len
= tmsg
->domain
.maxlen
= 0;
981 tmsg
->host
.offset
= tmsg
->domain
.offset
+ tmsg
->domain
.len
;
982 tmsg
->host
.len
= tmsg
->host
.maxlen
= 0;
985 //tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
986 //tmsg->ver.product_minor_version = 1;
987 //tmsg->ver.product_build = 2600;
988 //tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
990 out_buff
->value
= tmsg
;
991 out_buff
->length
= msglen
;
994 /***********************************************
996 * End of merged code from original sip-ntlm.c
998 ***********************************************/
1000 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1001 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1004 sip_sec_ntlm_negotiate_flags_describe(guint32 flags
)
1006 GString
* str
= g_string_new(NULL
);
1008 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_UNICODE
, "NTLMSSP_NEGOTIATE_UNICODE");
1009 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM
, "NTLMSSP_NEGOTIATE_OEM");
1010 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_REQUEST_TARGET
, "NTLMSSP_REQUEST_TARGET");
1011 APPEND_NEG_FLAG(str
, flags
, r9
, "r9");
1012 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_SIGN
, "NTLMSSP_NEGOTIATE_SIGN");
1013 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_SEAL
, "NTLMSSP_NEGOTIATE_SEAL");
1014 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_DATAGRAM
, "NTLMSSP_NEGOTIATE_DATAGRAM");
1015 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_LM_KEY
, "NTLMSSP_NEGOTIATE_LM_KEY");
1016 APPEND_NEG_FLAG(str
, flags
, r8
, "r8");
1017 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_NTLM
, "NTLMSSP_NEGOTIATE_NTLM");
1018 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_NT_ONLY
, "NTLMSSP_NEGOTIATE_NT_ONLY");
1019 APPEND_NEG_FLAG(str
, flags
, anonymous
, "anonymous");
1020 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1021 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1022 APPEND_NEG_FLAG(str
, flags
, r7
, "r7");
1023 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_ALWAYS_SIGN
, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1024 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_TARGET_TYPE_DOMAIN
, "NTLMSSP_TARGET_TYPE_DOMAIN");
1025 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_TARGET_TYPE_SERVER
, "NTLMSSP_TARGET_TYPE_SERVER");
1026 APPEND_NEG_FLAG(str
, flags
, r6
, "r6");
1027 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1028 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_IDENTIFY
, "NTLMSSP_NEGOTIATE_IDENTIFY");
1029 APPEND_NEG_FLAG(str
, flags
, r5
, "r5");
1030 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_REQUEST_NON_NT_SESSION_KEY
, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1031 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_TARGET_INFO
, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1032 APPEND_NEG_FLAG(str
, flags
, r4
, "r4");
1033 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_VERSION
, "NTLMSSP_NEGOTIATE_VERSION");
1034 APPEND_NEG_FLAG(str
, flags
, r3
, "r3");
1035 APPEND_NEG_FLAG(str
, flags
, r2
, "r2");
1036 APPEND_NEG_FLAG(str
, flags
, r1
, "r1");
1037 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_128
, "NTLMSSP_NEGOTIATE_128");
1038 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1039 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_56
, "NTLMSSP_NEGOTIATE_56");
1041 return g_string_free(str
, FALSE
);
1044 #define AV_DESC(av, av_value, av_len, av_name) \
1045 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1046 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1050 sip_sec_ntlm_describe_version(struct version
*ver
) {
1051 GString
* str
= g_string_new(NULL
);
1052 gchar
*ver_desc
= "";
1053 gchar
*ntlm_revision_desc
= "";
1055 if (ver
->product_major_version
== 6) {
1056 ver_desc
= "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1057 } else if (ver
->product_major_version
== 5 && ver
->product_minor_version
== 2) {
1058 ver_desc
= "Windows Server 2003";
1059 } else if (ver
->product_major_version
== 5 && ver
->product_minor_version
== 1) {
1060 ver_desc
= "Windows XP SP2";
1063 if (ver
->ntlm_revision_current
== 0x0F) {
1064 ntlm_revision_desc
= "NTLMSSP_REVISION_W2K3";
1065 } else if (ver
->ntlm_revision_current
== 0x0A) {
1066 ntlm_revision_desc
= "NTLMSSP_REVISION_W2K3_RC1";
1069 g_string_append_printf(str
, "\tproduct: %d.%d.%d (%s)\n",
1070 ver
->product_major_version
, ver
->product_minor_version
, ver
->product_build
, ver_desc
);
1071 g_string_append_printf(str
, "\tntlm_revision_current: 0x%02X (%s)\n", ver
->ntlm_revision_current
, ntlm_revision_desc
);
1073 return g_string_free(str
, FALSE
);
1077 sip_sec_ntlm_describe_smb_header(struct smb_header
*header
,
1080 GString
* str
= g_string_new(NULL
);
1082 g_string_append_printf(str
, "\t%s.len : %d\n", name
, header
->len
);
1083 g_string_append_printf(str
, "\t%s.maxlen: %d\n", name
, header
->maxlen
);
1084 g_string_append_printf(str
, "\t%s.offset: %d\n", name
, header
->offset
);
1086 return g_string_free(str
, FALSE
);
1090 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message
*cmsg
)
1092 GString
* str
= g_string_new(NULL
);
1095 g_string_append(str
, (tmp
= sip_sec_ntlm_negotiate_flags_describe(cmsg
->flags
)));
1098 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->domain
), "domain")));
1101 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->host
), "host")));
1104 tmp
= sip_sec_ntlm_describe_version(&(cmsg
->ver
));
1105 g_string_append(str
, tmp
);
1108 if (cmsg
->domain
.len
&& cmsg
->domain
.offset
) {
1109 gchar
*domain
= g_strndup(((gchar
*)cmsg
+ cmsg
->domain
.offset
), cmsg
->domain
.len
);
1110 g_string_append_printf(str
, "\tdomain: %s\n", domain
);
1114 if (cmsg
->host
.len
&& cmsg
->host
.offset
) {
1115 gchar
*host
= g_strndup(((gchar
*)cmsg
+ cmsg
->host
.offset
), cmsg
->host
.len
);
1116 g_string_append_printf(str
, "\thost: %s\n", host
);
1120 return g_string_free(str
, FALSE
);
1124 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message
*cmsg
)
1126 GString
* str
= g_string_new(NULL
);
1130 g_string_append(str
, (tmp
= sip_sec_ntlm_negotiate_flags_describe(cmsg
->flags
)));
1133 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->lm_resp
), "lm_resp")));
1136 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->nt_resp
), "nt_resp")));
1139 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->domain
), "domain")));
1142 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->user
), "user")));
1145 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->host
), "host")));
1148 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->session_key
), "session_key")));
1151 tmp
= sip_sec_ntlm_describe_version(&(cmsg
->ver
));
1152 g_string_append(str
, tmp
);
1157 buff
.value
= cmsg
->mic
;
1158 g_string_append_printf(str
, "\t%s: %s\n", "mic", (tmp
= bytes_to_hex_str(&buff
)));
1161 if (cmsg
->lm_resp
.len
&& cmsg
->lm_resp
.offset
) {
1162 buff
.length
= cmsg
->lm_resp
.len
;
1163 buff
.value
= (gchar
*)cmsg
+ cmsg
->lm_resp
.offset
;
1164 g_string_append_printf(str
, "\t%s: %s\n", "lm_resp", (tmp
= bytes_to_hex_str(&buff
)));
1168 if (cmsg
->nt_resp
.len
&& cmsg
->nt_resp
.offset
) {
1169 buff
.length
= cmsg
->nt_resp
.len
;
1170 buff
.value
= (gchar
*)cmsg
+ cmsg
->nt_resp
.offset
;
1171 g_string_append_printf(str
, "\t%s: %s\n", "nt_resp", (tmp
= bytes_to_hex_str(&buff
)));
1175 if (cmsg
->domain
.len
&& cmsg
->domain
.offset
) {
1176 gchar
*domain
= unicode_strconvcopy_back(((gchar
*)cmsg
+ cmsg
->domain
.offset
), cmsg
->domain
.len
);
1177 g_string_append_printf(str
, "\t%s: %s\n", "domain", domain
);
1181 if (cmsg
->user
.len
&& cmsg
->user
.offset
) {
1182 gchar
*user
= unicode_strconvcopy_back(((gchar
*)cmsg
+ cmsg
->user
.offset
), cmsg
->user
.len
);
1183 g_string_append_printf(str
, "\t%s: %s\n", "user", user
);
1187 if (cmsg
->host
.len
&& cmsg
->host
.offset
) {
1188 gchar
*host
= unicode_strconvcopy_back(((gchar
*)cmsg
+ cmsg
->host
.offset
), cmsg
->host
.len
);
1189 g_string_append_printf(str
, "\t%s: %s\n", "host", host
);
1193 if (cmsg
->session_key
.len
&& cmsg
->session_key
.offset
) {
1194 buff
.length
= cmsg
->session_key
.len
;
1195 buff
.value
= (gchar
*)cmsg
+ cmsg
->session_key
.offset
;
1196 g_string_append_printf(str
, "\t%s: %s\n", "session_key", (tmp
= bytes_to_hex_str(&buff
)));
1200 return g_string_free(str
, FALSE
);
1204 sip_sec_ntlm_challenge_message_describe(struct challenge_message
*cmsg
)
1206 GString
* str
= g_string_new(NULL
);
1209 g_string_append(str
, (tmp
= sip_sec_ntlm_negotiate_flags_describe(cmsg
->flags
)));
1212 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->target_name
), "target_name")));
1215 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->target_info
), "target_info")));
1218 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_version(&(cmsg
->ver
))));
1221 if (cmsg
->target_name
.len
&& cmsg
->target_name
.offset
) {
1222 gchar
*target_name
= unicode_strconvcopy_back(((gchar
*)cmsg
+ cmsg
->target_name
.offset
), cmsg
->target_name
.len
);
1223 g_string_append_printf(str
, "\ttarget_name: %s\n", target_name
);
1224 g_free(target_name
);
1227 if (cmsg
->target_info
.len
&& cmsg
->target_info
.offset
) {
1228 void *target_info
= ((gchar
*)cmsg
+ cmsg
->target_info
.offset
);
1229 struct av_pair
*av
= (struct av_pair
*)target_info
;
1231 while (av
->av_id
!= MsvAvEOL
) {
1232 gchar
*av_value
= ((gchar
*)av
) + 4;
1234 switch (av
->av_id
) {
1236 g_string_append_printf(str
, "\t%s\n", "MsvAvEOL");
1238 case MsvAvNbComputerName
:
1239 { AV_DESC(av
, av_value
, av
->av_len
, "MsvAvNbComputerName") break; }
1240 case MsvAvNbDomainName
:
1241 { AV_DESC(av
, av_value
, av
->av_len
, "MsvAvNbDomainName") break; }
1242 case MsvAvDnsComputerName
:
1243 { AV_DESC(av
, av_value
, av
->av_len
, "MsvAvDnsComputerName") break; }
1244 case MsvAvDnsDomainName
:
1245 { AV_DESC(av
, av_value
, av
->av_len
, "MsvAvDnsDomainName") break; }
1246 case MsvAvDnsTreeName
:
1247 { AV_DESC(av
, av_value
, av
->av_len
, "MsvAvDnsTreeName") break; }
1249 g_string_append_printf(str
, "\t%s: %d\n", "MsvAvFlags", *((guint32
*)av_value
));
1251 case MsvAvTimestamp
:
1252 g_string_append_printf(str
, "\t%s\n", "MsvAvTimestamp");
1254 case MsAvRestrictions
:
1255 g_string_append_printf(str
, "\t%s\n", "MsAvRestrictions");
1257 case MsvAvTargetName
:
1258 { AV_DESC(av
, av_value
, av
->av_len
, "MsvAvTargetName") break; }
1259 case MsvChannelBindings
:
1260 g_string_append_printf(str
, "\t%s\n", "MsvChannelBindings");
1264 av
= (struct av_pair
*)(((guint8
*)av
) + 4 + av
->av_len
);
1268 return g_string_free(str
, FALSE
);
1272 sip_sec_ntlm_message_describe(SipSecBuffer buff
)
1274 struct ntlm_message
*msg
;
1276 if (buff
.length
== 0 || buff
.value
== NULL
|| buff
.length
< 12) return NULL
;
1279 if(!sipe_strequal("NTLMSSP", (char*)msg
)) return NULL
;
1281 if (msg
->type
== 1) return sip_sec_ntlm_negotiate_message_describe((struct negotiate_message
*)msg
);
1282 if (msg
->type
== 2) return sip_sec_ntlm_challenge_message_describe((struct challenge_message
*)msg
);
1283 if (msg
->type
== 3) return sip_sec_ntlm_authenticate_message_describe((struct authenticate_message
*)msg
);
1288 /* sip-sec-mech.h API implementation for NTLM */
1290 /* Security context for NTLM */
1291 typedef struct _context_ntlm
{
1292 struct sip_sec_context common
;
1304 sip_sec_acquire_cred__ntlm(SipSecContext context
,
1306 const char *username
,
1307 const char *password
)
1309 context_ntlm ctx
= (context_ntlm
)context
;
1311 /* NTLM requires a domain, username & password */
1312 if (!domain
|| !username
|| !password
)
1313 return SIP_SEC_E_INTERNAL_ERROR
;
1315 ctx
->domain
= g_strdup(domain
);
1316 ctx
->username
= g_strdup(username
);
1317 ctx
->password
= g_strdup(password
);
1319 return SIP_SEC_E_OK
;
1323 sip_sec_init_sec_context__ntlm(SipSecContext context
,
1324 SipSecBuffer in_buff
,
1325 SipSecBuffer
*out_buff
,
1326 SIPE_UNUSED_PARAMETER
const char *service_name
)
1328 context_ntlm ctx
= (context_ntlm
) context
;
1330 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1333 if (ctx
->step
== 1) {
1334 if (!context
->is_connection_based
) {
1335 out_buff
->length
= 0;
1336 out_buff
->value
= NULL
;
1338 purple_ntlm_gen_negotiate(out_buff
);
1340 return SIP_SEC_I_CONTINUE_NEEDED
;
1348 if (!in_buff
.value
|| !in_buff
.length
) {
1349 return SIP_SEC_E_INTERNAL_ERROR
;
1352 nonce
= g_memdup(purple_ntlm_parse_challenge(in_buff
, context
->is_connection_based
, &flags
), 8);
1354 purple_ntlm_gen_authenticate(&ntlm_key
,
1357 (tmp
= g_ascii_strup(sipe_get_host_name(), -1)),
1360 context
->is_connection_based
,
1367 ctx
->key
= ntlm_key
;
1369 return SIP_SEC_E_OK
;
1374 * @param message a NULL terminated string to sign
1378 sip_sec_make_signature__ntlm(SipSecContext context
,
1379 const char *message
,
1380 SipSecBuffer
*signature
)
1382 /* FIXME? We always use a random_pad of 0 */
1383 gchar
*signature_hex
= purple_ntlm_sipe_signature_make(((context_ntlm
) context
)->flags
,
1386 ((context_ntlm
) context
)->key
);
1388 hex_str_to_bytes(signature_hex
, signature
);
1389 g_free(signature_hex
);
1391 return SIP_SEC_E_OK
;
1395 * @param message a NULL terminated string to check signature of
1396 * @return SIP_SEC_E_OK on success
1399 sip_sec_verify_signature__ntlm(SipSecContext context
,
1400 const char *message
,
1401 SipSecBuffer signature
)
1403 guint32 random_pad
= ((guint32
*) signature
.value
)[1];
1404 char *signature_hex
= bytes_to_hex_str(&signature
);
1405 gchar
*signature_calc
= purple_ntlm_sipe_signature_make(((context_ntlm
) context
)->flags
,
1408 ((context_ntlm
) context
)->key
);
1411 if (purple_ntlm_verify_signature(signature_calc
, signature_hex
)) {
1414 res
= SIP_SEC_E_INTERNAL_ERROR
;
1416 g_free(signature_calc
);
1417 g_free(signature_hex
);
1422 sip_sec_destroy_sec_context__ntlm(SipSecContext context
)
1424 context_ntlm ctx
= (context_ntlm
) context
;
1426 g_free(ctx
->domain
);
1427 g_free(ctx
->username
);
1428 g_free(ctx
->password
);
1434 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type
)
1436 context_ntlm context
= g_malloc0(sizeof(struct _context_ntlm
));
1437 if (!context
) return(NULL
);
1439 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__ntlm
;
1440 context
->common
.init_context_func
= sip_sec_init_sec_context__ntlm
;
1441 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__ntlm
;
1442 context
->common
.make_signature_func
= sip_sec_make_signature__ntlm
;
1443 context
->common
.verify_signature_func
= sip_sec_verify_signature__ntlm
;
1445 return((SipSecContext
) context
);