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
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.
49 #include <glib/gprintf.h>
57 #include <sys/types.h>
59 #include <sys/sockio.h>
65 #ifdef HAVE_LANGINFO_CODESET
67 #endif /* HAVE_LANGINFO_CODESET */
73 #include "sipe-utils.h"
74 #include "sip-sec-mech.h"
75 #include "sip-sec-ntlm.h"
78 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
79 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
80 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
81 #define r9 0x00000008 /* r9 */
82 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
83 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
84 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
85 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
86 #define r8 0x00000100 /* r8 */
87 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
88 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
89 #define anonymous 0x00000800 /* J */
90 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
91 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
92 #define r7 0x00004000 /* r7 */
93 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
94 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
95 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
96 #define r6 0x00040000 /* r6 */
97 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
98 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
99 #define r5 0x00200000 /* r5 */
100 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
101 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
102 #define r4 0x01000000 /* r4 */
103 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
104 #define r3 0x04000000 /* r3 */
105 #define r2 0x08000000 /* r2 */
106 #define r1 0x10000000 /* r1 */
107 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
108 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
109 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
113 #define MsvAvNbComputerName 1
114 #define MsvAvNbDomainName 2
115 #define MsvAvDnsComputerName 3
116 #define MsvAvDnsDomainName 4
117 /** @since Windows XP */
118 #define MsvAvDnsTreeName 5
119 /** @since Windows XP */
121 /** @since Windows Vista */
122 #define MsvAvTimestamp 7
123 /** @since Windows Vista */
124 #define MsAvRestrictions 8
125 /** @since Windows 7 */
126 #define MsvAvTargetName 9
127 /** @since Windows 7 */
128 #define MsvChannelBindings 10
130 /* time_t <-> (guint64) time_val conversion */
131 #define TIME_VAL_FACTOR 10000000
132 #define TIME_VAL_OFFSET 116444736000000000LL
133 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
134 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
137 /* LE (Little Endian) byte order */
139 guint8 product_major_version
;
140 guint8 product_minor_version
;
141 guint16 product_build
;
143 guint8 ntlm_revision_current
;
147 * NTLMv1 is no longer used except in tests. R.I.P.
149 * It remains in this file only for documentary purposes
151 #ifdef _SIPE_COMPILING_TESTS
152 static gboolean use_ntlm_v2
= FALSE
;
154 guint64 test_time_val
= 0; /* actual time in implementation */
155 guchar test_client_challenge
[8]; /* random in implementation */
156 guchar test_random_session_key
[16]; /* random in implementation */
157 struct version test_version
; /* optional, not set in in implementation */
160 /* Minimum set of common features we need to work. */
161 /* we operate in NTLMv2 mode */
162 #define NEGOTIATE_FLAGS_COMMON_MIN \
163 ( NTLMSSP_NEGOTIATE_UNICODE | \
164 NTLMSSP_NEGOTIATE_NTLM | \
165 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
166 NTLMSSP_NEGOTIATE_TARGET_INFO \
169 /* Negotiate flags for connection-based mode. Nice to have but optional. */
170 #define NEGOTIATE_FLAGS_CONN \
171 ( NEGOTIATE_FLAGS_COMMON_MIN | \
172 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
173 NTLMSSP_NEGOTIATE_VERSION | \
174 NTLMSSP_NEGOTIATE_128 | \
175 NTLMSSP_NEGOTIATE_56 | \
176 NTLMSSP_REQUEST_TARGET \
179 /* Negotiate flags required in connectionless NTLM */
180 #define NEGOTIATE_FLAGS \
181 ( NEGOTIATE_FLAGS_CONN | \
182 NTLMSSP_NEGOTIATE_SIGN | \
183 NTLMSSP_NEGOTIATE_DATAGRAM | \
184 NTLMSSP_NEGOTIATE_IDENTIFY | \
185 NTLMSSP_NEGOTIATE_KEY_EXCH \
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)
197 /* LE (Little Endian) byte order */
204 /* to meet sparc's alignment requirement */
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; \
214 while (av_id != MsvAvEOL) { \
215 gchar *av_value = ((gchar *)av) + \
216 sizeof(struct av_pair); \
218 #define ALIGN_AV_LOOP_END \
219 av = av_value + av_len; \
224 /* LE (Little Endian) byte order */
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
;
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 */
259 struct smb_header target_info
;
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
;
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";
300 /* Private Methods */
302 /* Utility Functions */
303 static GIConv convert_from_utf16le
= (GIConv
)-1;
304 static GIConv convert_to_utf16le
= (GIConv
)-1;
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 */
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
);
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()
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
)
359 crc
= (crc
>> 8) ^ crc32_table
[(crc
^ *buf
++) & 0xff];
361 return crc
^ 0xffffffffL
;
365 CRC32 (const char *msg
, int len
)
368 crc
= crc32(crc
, (guint8
*) msg
, len
);
374 #ifdef _SIPE_COMPILING_TESTS
375 static void setup_des_key(const unsigned char key_56
[], unsigned char *key
)
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
;
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 */
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: */
411 DESL (const unsigned char *k
, const unsigned char *d
, unsigned char * results
)
413 unsigned char keys
[21];
415 /* Copy the first 16 bytes */
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);
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
);
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
);
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
);
462 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
465 unsigned char ibuff[64 + data_len];
466 unsigned char obuff[64 + 16];
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++) {
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
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 */
506 NONCE(unsigned char *buffer
, int num
)
509 for (i
= 0; i
< num
; i
++) {
510 buffer
[i
] = (rand() & 0xff);
514 #ifdef _SIPE_COMPILING_TESTS
516 Z(unsigned char *buffer
, int num
)
518 memset(buffer
, 0, num
);
522 LMOWFv1 (const char *password
, SIPE_UNUSED_PARAMETER
const char *user
, SIPE_UNUSED_PARAMETER
const char *domain
, unsigned char *result
)
525 unsigned char magic
[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
526 unsigned char uppercase_password
[14];
529 int len
= strlen(password
);
534 // Uppercase password
535 for (i
= 0; i
< len
; i
++) {
536 uppercase_password
[i
] = g_ascii_toupper(password
[i
]);
540 for (; i
< 14; i
++) {
541 uppercase_password
[i
] = 0;
544 DES (uppercase_password
, magic
, result
);
545 DES (uppercase_password
+ 7, magic
, result
+ 8);
550 Define NTOWFv1(Passwd, User, UserDom) as
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 ) )
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];
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
);
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
,
606 unsigned char *lm_challenge_response
,
607 unsigned char *nt_challenge_response
,
608 unsigned char *session_base_key
)
610 #ifdef _SIPE_COMPILING_TESTS
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
625 ClientChallenge, //8bytes - 16
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)),
634 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
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 */
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
);
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
);
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 */
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);
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
);
699 DESL (response_key_lm
, server_challenge
, lm_challenge_response
);
704 MD4(response_key_nt
, 16, session_base_key
); // "User Session Key" -> "master key"
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
720 /* Not used in NTLMv2 */
722 (void)lm_challenge_resonse
;
723 (void)server_challenge
;
725 memcpy(key_exchange_key
, session_base_key
, 16);
726 #ifdef _SIPE_COMPILING_TESTS
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]))
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
);
740 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
741 memcpy(key_exchange_key
, session_base_key
, 16);
748 If (Mode equals "Client")
749 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
750 "session key to client-to-server signing key magic constant"))
752 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
753 "session key to server-to-client signing key magic constant"))
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]
779 Set SealKey to RandomSessionKey[0..4]
782 If (Mode equals "Client")
783 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
785 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
788 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
789 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
791 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
795 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
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
];
809 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_128
)) {
810 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key (Extended session security)\n");
812 } else if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_56
)) {
813 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key (Extended session security)\n");
816 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key (Extended session security)\n");
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);
832 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key\n");
833 memcpy(result
, random_session_key
, 5);
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) */
868 unsigned char *sign_key
,
869 unsigned long sign_key_len
,
870 unsigned char *seal_key
,
871 unsigned long seal_key_len
,
877 gchar signature
[33];
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
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
900 unsigned char seal_key_
[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_
);
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);
933 purple_debug_info("sipe", "NTLM MAC(): *NO* Key Exchange\n");
934 memcpy(result
+4, hmac
, 8);
937 /* The content of the first 4 bytes is irrelevant */
938 guint32 crc
= CRC32(buf
, strlen(buf
));
939 guint32 plaintext
[] = {
942 GUINT32_TO_LE(sequence
)
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
972 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff
,
973 gboolean is_connection_based
,
975 guchar
**server_challenge
, /* 8 bytes */
977 guchar
**target_info
,
978 int *target_info_len
)
980 struct challenge_message
*cmsg
= (struct challenge_message
*)in_buff
.value
;
981 guint32 host_flags
= GUINT32_FROM_LE(cmsg
->flags
);
983 /* server challenge (nonce) */
984 if (server_challenge
) {
985 *server_challenge
= g_memdup(cmsg
->nonce
, 8);
994 if (cmsg
->target_info
.len
&& cmsg
->target_info
.offset
) {
995 void *content
= (gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->target_info
.offset
);
997 guint16 len
= GUINT16_FROM_LE(cmsg
->target_info
.len
);
1002 case MsvAvTimestamp
:
1006 /* to meet sparc's alignment requirement */
1007 memcpy(&tmp
, av_value
, sizeof(tmp
));
1008 *time_val
= GUINT64_FROM_LE(tmp
);
1014 if (target_info_len
) {
1015 *target_info_len
= len
;
1018 *target_info
= g_memdup(content
, len
);
1024 * @param client_sign_key (out) must be g_free()'d after use
1025 * @param server_sign_key (out) must be g_free()'d after use
1026 * @param client_seal_key (out) must be g_free()'d after use
1027 * @param server_seal_key (out) must be g_free()'d after use
1028 * @param flags (in, out) negotiated flags
1031 sip_sec_ntlm_gen_authenticate(guchar
**client_sign_key
,
1032 guchar
**server_sign_key
,
1033 guchar
**client_seal_key
,
1034 guchar
**server_seal_key
,
1036 const gchar
*password
,
1037 const gchar
*hostname
,
1038 const gchar
*domain
,
1039 const guint8
*server_challenge
, /* nonce */
1040 const guint64 time_val
,
1041 const guint8
*target_info
,
1042 int target_info_len
,
1043 gboolean is_connection_based
,
1044 SipSecBuffer
*out_buff
,
1047 guint32 orig_flags
= is_connection_based
? NEGOTIATE_FLAGS_CONN
: NEGOTIATE_FLAGS
;
1048 guint32 neg_flags
= (*flags
& orig_flags
) | NTLMSSP_REQUEST_TARGET
;
1049 int ntlmssp_nt_resp_len
=
1050 #ifdef _SIPE_COMPILING_TESTS
1053 (16 + (32+target_info_len
))
1054 #ifdef _SIPE_COMPILING_TESTS
1055 : NTLMSSP_LM_RESP_LEN
1058 gsize msglen
= sizeof(struct authenticate_message
)
1059 + 2*(strlen(domain
) + strlen(user
)+ strlen(hostname
))
1060 + NTLMSSP_LM_RESP_LEN
+ ntlmssp_nt_resp_len
1061 + (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
) ? NTLMSSP_SESSION_KEY_LEN
: 0);
1062 struct authenticate_message
*tmsg
;
1066 unsigned char response_key_lm
[NTLMSSP_LN_OR_NT_KEY_LEN
]; /* 16 */
1067 unsigned char response_key_nt
[NTLMSSP_LN_OR_NT_KEY_LEN
]; /* 16 */
1068 unsigned char lm_challenge_response
[NTLMSSP_LM_RESP_LEN
]; /* 24 */
1069 unsigned char nt_challenge_response
[ntlmssp_nt_resp_len
]; /* variable or 24 */
1070 unsigned char session_base_key
[16];
1071 unsigned char key_exchange_key
[16];
1072 unsigned char exported_session_key
[16];
1073 unsigned char encrypted_random_session_key
[16];
1074 unsigned char key
[16];
1075 unsigned char client_challenge
[8];
1076 guint64 time_vl
= time_val
? time_val
: TIME_T_TO_VAL(time(NULL
));
1078 if (!IS_FLAG(*flags
, NEGOTIATE_FLAGS_COMMON_MIN
)) {
1079 purple_debug_info("sipe", "sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1080 return SIP_SEC_E_INTERNAL_ERROR
;
1083 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_128
)) {
1084 neg_flags
= neg_flags
& ~NTLMSSP_NEGOTIATE_56
;
1087 tmsg
= g_malloc0(msglen
);
1089 NONCE (client_challenge
, 8);
1091 #ifdef _SIPE_COMPILING_TESTS
1092 memcpy(client_challenge
, test_client_challenge
, 8);
1093 time_vl
= test_time_val
? test_time_val
: time_vl
;
1098 NTOWFv2 (password
, user
, domain
, response_key_nt
);
1099 memcpy(response_key_lm
, response_key_nt
, NTLMSSP_LN_OR_NT_KEY_LEN
);
1100 #ifdef _SIPE_COMPILING_TESTS
1102 NTOWFv1 (password
, user
, domain
, response_key_nt
);
1103 LMOWFv1 (password
, user
, domain
, response_key_lm
);
1107 compute_response(neg_flags
,
1115 lm_challenge_response
, /* out */
1116 nt_challenge_response
, /* out */
1117 session_base_key
); /* out */
1119 /* same as session_base_key for
1120 * - NTLNv1 w/o Ext.Sess.Sec and
1123 KXKEY(neg_flags
, session_base_key
, lm_challenge_response
, server_challenge
, key_exchange_key
);
1125 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
)) {
1126 NONCE (exported_session_key
, 16); // random master key
1127 #ifdef _SIPE_COMPILING_TESTS
1128 memcpy(exported_session_key
, test_random_session_key
, 16);
1130 RC4K (key_exchange_key
, 16, exported_session_key
, 16, encrypted_random_session_key
);
1132 memcpy(exported_session_key
, key_exchange_key
, 16);
1135 tmp
= buff_to_hex_str(exported_session_key
, 16);
1136 purple_debug_info("sipe", "NTLM AUTHENTICATE: exported session key (not encrypted): %s\n", tmp
);
1140 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1141 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1143 SIGNKEY(exported_session_key
, TRUE
, key
);
1144 *client_sign_key
= (guchar
*)g_strndup((gchar
*)key
, 16);
1145 SIGNKEY(exported_session_key
, FALSE
, key
);
1146 *server_sign_key
= (guchar
*)g_strndup((gchar
*)key
, 16);
1147 SEALKEY(neg_flags
, exported_session_key
, TRUE
, key
);
1148 *client_seal_key
= (guchar
*)g_strndup((gchar
*)key
, 16);
1149 SEALKEY(neg_flags
, exported_session_key
, FALSE
, key
);
1150 *server_seal_key
= (guchar
*)g_strndup((gchar
*)key
, 16);
1154 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1155 the client SHOULD provide a MIC:
1156 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1157 - then in the Value field, set bit 0x2 to 1.
1158 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1159 and the Value field bit 0x2 to 1.
1160 - Populate the MIC field with the MIC.
1163 /* Connection-oriented:
1164 Set MIC to HMAC_MD5(ExportedSessionKey,
1165 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1167 Set MIC to HMAC_MD5(ExportedSessionKey,
1168 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1171 /* on the server-side:
1172 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1173 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1174 Set MIC to HMAC_MD5(ExportedSessionKey,
1175 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1177 Set ExportedSessionKey to KeyExchangeKey
1178 Set MIC to HMAC_MD5(KeyExchangeKey,
1179 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1182 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1183 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1184 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1185 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1186 an AV_PAIR structure whose two fields:
1187 - AvId == MsvAvFlags
1188 - Value bit 0x2 == 1
1189 @supported NT, 2000, XP
1190 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1191 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1192 the server time, then the server SHOULD return a failure.
1195 Set MIC to HMAC_MD5(ResponseKeyNT,
1196 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1199 /* authenticate message initialization */
1200 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
1201 tmsg
->type
= GUINT32_TO_LE(3);
1203 /* Initial offset */
1204 offset
= sizeof(struct authenticate_message
);
1205 tmp
= ((char*) tmsg
) + offset
;
1207 #define _FILL_SMB_HEADER(header) \
1208 tmsg->header.offset = GUINT32_TO_LE(offset); \
1209 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1212 #define _APPEND_STRING(header, src) \
1213 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1214 _FILL_SMB_HEADER(header)
1215 #define _APPEND_DATA(header, src, srclen) \
1217 memcpy(tmp, (src), len); \
1218 _FILL_SMB_HEADER(header)
1221 _APPEND_STRING(domain
, domain
);
1224 _APPEND_STRING(user
, user
);
1227 _APPEND_STRING(host
, hostname
);
1231 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1232 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1233 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1235 _APPEND_DATA(lm_resp
, lm_challenge_response
, NTLMSSP_LM_RESP_LEN
);
1238 _APPEND_DATA(nt_resp
, nt_challenge_response
, ntlmssp_nt_resp_len
);
1241 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
))
1243 _APPEND_DATA(session_key
, encrypted_random_session_key
, NTLMSSP_SESSION_KEY_LEN
);
1247 tmsg
->session_key
.offset
= GUINT32_TO_LE(offset
);
1248 tmsg
->session_key
.len
= tmsg
->session_key
.maxlen
= 0;
1252 #ifdef _SIPE_COMPILING_TESTS
1253 memcpy(&(tmsg
->ver
), &test_version
, sizeof(struct version
));
1255 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_VERSION
)) {
1256 tmsg
->ver
.product_major_version
= 5; /* 5.1.2600 (Windows XP SP2) */
1257 tmsg
->ver
.product_minor_version
= 1;
1258 tmsg
->ver
.product_build
= GUINT16_FROM_LE(2600);
1259 tmsg
->ver
.ntlm_revision_current
= 0x0F; /* NTLMSSP_REVISION_W2K3 */
1263 /* Set Negotiate Flags */
1264 tmsg
->flags
= GUINT32_TO_LE(neg_flags
);
1267 out_buff
->value
= tmsg
;
1268 out_buff
->length
= msglen
;
1270 return SIP_SEC_E_OK
;
1274 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1277 sip_sec_ntlm_gen_negotiate(SipSecBuffer
*out_buff
)
1281 int msglen
= sizeof(struct negotiate_message
);
1282 struct negotiate_message
*tmsg
= g_malloc0(msglen
);
1284 /* negotiate message initialization */
1285 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
1286 tmsg
->type
= GUINT32_TO_LE(1);
1288 /* Set Negotiate Flags */
1289 tmsg
->flags
= GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN
);
1292 offset
= sizeof(struct negotiate_message
);
1293 tmsg
->domain
.offset
= GUINT32_TO_LE(offset
);
1294 tmsg
->domain
.len
= tmsg
->domain
.maxlen
= len
= 0;
1298 tmsg
->host
.offset
= GUINT32_TO_LE(offset
);
1299 tmsg
->host
.len
= tmsg
->host
.maxlen
= len
= 0;
1302 tmsg
->ver
.product_major_version
= 5; /* 5.1.2600 (Windows XP SP2) */
1303 tmsg
->ver
.product_minor_version
= 1;
1304 tmsg
->ver
.product_build
= GUINT16_FROM_LE(2600);
1305 tmsg
->ver
.ntlm_revision_current
= 0x0F; /* NTLMSSP_REVISION_W2K3 */
1307 out_buff
->value
= tmsg
;
1308 out_buff
->length
= msglen
;
1312 sip_sec_ntlm_sipe_signature_make (guint32 flags
, const char *msg
, guint32 random_pad
, unsigned char *sign_key
, unsigned char *seal_key
)
1314 gchar
*res
= MAC(flags
, msg
,strlen(msg
), sign_key
,16, seal_key
,16, random_pad
, 100);
1315 purple_debug_info("sipe", "NTLM calculated MAC: %s\n", res
);
1320 sip_sec_ntlm_verify_signature (char * a
, char * b
)
1322 return g_ascii_strncasecmp(a
, b
, 16*2) == 0;
1326 /* Describe NTLM messages functions */
1328 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1329 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1332 sip_sec_ntlm_negotiate_flags_describe(guint32 flags
)
1334 GString
* str
= g_string_new(NULL
);
1336 flags
= GUINT32_FROM_LE(flags
);
1338 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_UNICODE
, "NTLMSSP_NEGOTIATE_UNICODE");
1339 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM
, "NTLMSSP_NEGOTIATE_OEM");
1340 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_REQUEST_TARGET
, "NTLMSSP_REQUEST_TARGET");
1341 APPEND_NEG_FLAG(str
, flags
, r9
, "r9");
1342 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_SIGN
, "NTLMSSP_NEGOTIATE_SIGN");
1343 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_SEAL
, "NTLMSSP_NEGOTIATE_SEAL");
1344 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_DATAGRAM
, "NTLMSSP_NEGOTIATE_DATAGRAM");
1345 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_LM_KEY
, "NTLMSSP_NEGOTIATE_LM_KEY");
1346 APPEND_NEG_FLAG(str
, flags
, r8
, "r8");
1347 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_NTLM
, "NTLMSSP_NEGOTIATE_NTLM");
1348 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_NT_ONLY
, "NTLMSSP_NEGOTIATE_NT_ONLY");
1349 APPEND_NEG_FLAG(str
, flags
, anonymous
, "anonymous");
1350 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1351 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1352 APPEND_NEG_FLAG(str
, flags
, r7
, "r7");
1353 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_ALWAYS_SIGN
, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1354 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_TARGET_TYPE_DOMAIN
, "NTLMSSP_TARGET_TYPE_DOMAIN");
1355 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_TARGET_TYPE_SERVER
, "NTLMSSP_TARGET_TYPE_SERVER");
1356 APPEND_NEG_FLAG(str
, flags
, r6
, "r6");
1357 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1358 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_IDENTIFY
, "NTLMSSP_NEGOTIATE_IDENTIFY");
1359 APPEND_NEG_FLAG(str
, flags
, r5
, "r5");
1360 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_REQUEST_NON_NT_SESSION_KEY
, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1361 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_TARGET_INFO
, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1362 APPEND_NEG_FLAG(str
, flags
, r4
, "r4");
1363 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_VERSION
, "NTLMSSP_NEGOTIATE_VERSION");
1364 APPEND_NEG_FLAG(str
, flags
, r3
, "r3");
1365 APPEND_NEG_FLAG(str
, flags
, r2
, "r2");
1366 APPEND_NEG_FLAG(str
, flags
, r1
, "r1");
1367 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_128
, "NTLMSSP_NEGOTIATE_128");
1368 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1369 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_56
, "NTLMSSP_NEGOTIATE_56");
1371 return g_string_free(str
, FALSE
);
1375 sip_sec_ntlm_describe_version(struct version
*ver
) {
1376 GString
* str
= g_string_new(NULL
);
1377 gchar
*ver_desc
= "";
1378 gchar
*ntlm_revision_desc
= "";
1380 if (ver
->product_major_version
== 6) {
1381 ver_desc
= "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1382 } else if (ver
->product_major_version
== 5 && ver
->product_minor_version
== 2) {
1383 ver_desc
= "Windows Server 2003";
1384 } else if (ver
->product_major_version
== 5 && ver
->product_minor_version
== 1) {
1385 ver_desc
= "Windows XP SP2";
1388 if (ver
->ntlm_revision_current
== 0x0F) {
1389 ntlm_revision_desc
= "NTLMSSP_REVISION_W2K3";
1390 } else if (ver
->ntlm_revision_current
== 0x0A) {
1391 ntlm_revision_desc
= "NTLMSSP_REVISION_W2K3_RC1";
1394 g_string_append_printf(str
, "\tproduct: %d.%d.%d (%s)\n",
1395 ver
->product_major_version
, ver
->product_minor_version
, ver
->product_build
, ver_desc
);
1396 g_string_append_printf(str
, "\tntlm_revision_current: 0x%02X (%s)\n", ver
->ntlm_revision_current
, ntlm_revision_desc
);
1398 return g_string_free(str
, FALSE
);
1402 sip_sec_ntlm_describe_smb_header(struct smb_header
*header
,
1405 GString
* str
= g_string_new(NULL
);
1407 g_string_append_printf(str
, "\t%s.len : %d\n", name
, GUINT16_FROM_LE(header
->len
));
1408 g_string_append_printf(str
, "\t%s.maxlen: %d\n", name
, GUINT16_FROM_LE(header
->maxlen
));
1409 g_string_append_printf(str
, "\t%s.offset: %d\n", name
, GUINT32_FROM_LE(header
->offset
));
1411 return g_string_free(str
, FALSE
);
1415 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message
*cmsg
)
1417 GString
* str
= g_string_new(NULL
);
1420 g_string_append(str
, (tmp
= sip_sec_ntlm_negotiate_flags_describe(cmsg
->flags
)));
1423 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->domain
), "domain")));
1426 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->host
), "host")));
1429 tmp
= sip_sec_ntlm_describe_version(&(cmsg
->ver
));
1430 g_string_append(str
, tmp
);
1433 if (cmsg
->domain
.len
&& cmsg
->domain
.offset
) {
1434 gchar
*domain
= g_strndup(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->domain
.offset
)), GUINT16_FROM_LE(cmsg
->domain
.len
));
1435 g_string_append_printf(str
, "\tdomain: %s\n", domain
);
1439 if (cmsg
->host
.len
&& cmsg
->host
.offset
) {
1440 gchar
*host
= g_strndup(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->host
.offset
)), GUINT16_FROM_LE(cmsg
->host
.len
));
1441 g_string_append_printf(str
, "\thost: %s\n", host
);
1445 return g_string_free(str
, FALSE
);
1449 describe_av_pairs(GString
* str
, const void *av
)
1451 #define AV_DESC(av_name) \
1453 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1454 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1460 case MsvAvNbComputerName
:
1461 AV_DESC("MsvAvNbComputerName");
1463 case MsvAvNbDomainName
:
1464 AV_DESC("MsvAvNbDomainName");
1466 case MsvAvDnsComputerName
:
1467 AV_DESC("MsvAvDnsComputerName");
1469 case MsvAvDnsDomainName
:
1470 AV_DESC("MsvAvDnsDomainName");
1472 case MsvAvDnsTreeName
:
1473 AV_DESC("MsvAvDnsTreeName");
1479 /* to meet sparc's alignment requirement */
1480 memcpy(&flags
, av_value
, sizeof(guint32
));
1481 g_string_append_printf(str
, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags
));
1484 case MsvAvTimestamp
:
1491 /* to meet sparc's alignment requirement */
1492 memcpy(&time_val
, av_value
, sizeof(time_val
));
1493 time_t_val
= TIME_VAL_TO_T(time_val
);
1496 buff
.value
= av_value
;
1497 g_string_append_printf(str
, "\t%s: %s - %s", "MsvAvTimestamp", (tmp
= bytes_to_hex_str(&buff
)),
1498 asctime(gmtime(&time_t_val
)));
1502 case MsAvRestrictions
:
1503 g_string_append_printf(str
, "\t%s\n", "MsAvRestrictions");
1505 case MsvAvTargetName
:
1506 AV_DESC("MsvAvTargetName");
1508 case MsvChannelBindings
:
1509 g_string_append_printf(str
, "\t%s\n", "MsvChannelBindings");
1516 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message
*cmsg
)
1518 GString
* str
= g_string_new(NULL
);
1522 g_string_append(str
, (tmp
= sip_sec_ntlm_negotiate_flags_describe(cmsg
->flags
)));
1525 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->lm_resp
), "lm_resp")));
1528 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->nt_resp
), "nt_resp")));
1531 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->domain
), "domain")));
1534 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->user
), "user")));
1537 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->host
), "host")));
1540 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->session_key
), "session_key")));
1543 tmp
= sip_sec_ntlm_describe_version(&(cmsg
->ver
));
1544 g_string_append(str
, tmp
);
1549 //buff.value = cmsg->mic;
1550 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = bytes_to_hex_str(&buff)));
1553 if (cmsg
->lm_resp
.len
&& cmsg
->lm_resp
.offset
) {
1554 buff
.length
= GUINT16_FROM_LE(cmsg
->lm_resp
.len
);
1555 buff
.value
= (gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->lm_resp
.offset
);
1556 g_string_append_printf(str
, "\t%s: %s\n", "lm_resp", (tmp
= bytes_to_hex_str(&buff
)));
1560 if (cmsg
->nt_resp
.len
&& cmsg
->nt_resp
.offset
) {
1561 guint16 nt_resp_len_full
= GUINT16_FROM_LE(cmsg
->nt_resp
.len
);
1562 int nt_resp_len
= nt_resp_len_full
;
1564 buff
.length
= nt_resp_len_full
;
1565 buff
.value
= (gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->nt_resp
.offset
);
1566 g_string_append_printf(str
, "\t%s: %s\n", "nt_resp raw", (tmp
= bytes_to_hex_str(&buff
)));
1569 if (nt_resp_len
> 24) { /* NTLMv2 */
1573 buff
.length
= nt_resp_len
;
1574 buff
.value
= (gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->nt_resp
.offset
);
1575 g_string_append_printf(str
, "\t%s: %s\n", "nt_resp", (tmp
= bytes_to_hex_str(&buff
)));
1578 if (nt_resp_len_full
> 24) { /* NTLMv2 */
1581 const gchar
*temp
= (gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->nt_resp
.offset
) + 16;
1582 const guint response_version
= *((guchar
*)temp
);
1583 const guint hi_response_version
= *((guchar
*)(temp
+1));
1586 const gchar
*client_challenge
= temp
+ 16;
1587 const gchar
*target_info
= temp
+ 28;
1588 guint16 target_info_len
= nt_resp_len_full
- 16 - 32;
1590 buff
.length
= target_info_len
;
1591 buff
.value
= (gchar
*)target_info
;
1592 g_string_append_printf(str
, "\t%s: %s\n", "target_info raw", (tmp
= bytes_to_hex_str(&buff
)));
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
);
1603 buff
.value
= (gchar
*)&time_val
;
1604 g_string_append_printf(str
, "\t%s: %s - %s", "time", (tmp
= bytes_to_hex_str(&buff
)),
1605 asctime(gmtime(&time_t_val
)));
1609 buff
.value
= (gchar
*)client_challenge
;
1610 g_string_append_printf(str
, "\t%s: %s\n", "client_challenge", (tmp
= bytes_to_hex_str(&buff
)));
1613 describe_av_pairs(str
, target_info
);
1615 g_string_append_printf(str
, "\t%s\n", "----------- end of nt_resp v2 -----------");
1619 if (cmsg
->domain
.len
&& cmsg
->domain
.offset
) {
1620 gchar
*domain
= unicode_strconvcopy_back(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->domain
.offset
)), GUINT16_FROM_LE(cmsg
->domain
.len
));
1621 g_string_append_printf(str
, "\t%s: %s\n", "domain", domain
);
1625 if (cmsg
->user
.len
&& cmsg
->user
.offset
) {
1626 gchar
*user
= unicode_strconvcopy_back(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->user
.offset
)), GUINT16_FROM_LE(cmsg
->user
.len
));
1627 g_string_append_printf(str
, "\t%s: %s\n", "user", user
);
1631 if (cmsg
->host
.len
&& cmsg
->host
.offset
) {
1632 gchar
*host
= unicode_strconvcopy_back(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->host
.offset
)), GUINT16_FROM_LE(cmsg
->host
.len
));
1633 g_string_append_printf(str
, "\t%s: %s\n", "host", host
);
1637 if (cmsg
->session_key
.len
&& cmsg
->session_key
.offset
) {
1638 buff
.length
= GUINT16_FROM_LE(cmsg
->session_key
.len
);
1639 buff
.value
= (gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->session_key
.offset
);
1640 g_string_append_printf(str
, "\t%s: %s\n", "session_key", (tmp
= bytes_to_hex_str(&buff
)));
1644 return g_string_free(str
, FALSE
);
1648 sip_sec_ntlm_challenge_message_describe(struct challenge_message
*cmsg
)
1650 GString
* str
= g_string_new(NULL
);
1654 g_string_append(str
, (tmp
= sip_sec_ntlm_negotiate_flags_describe(cmsg
->flags
)));
1657 /* nonce (server_challenge) */
1659 buff
.value
= cmsg
->nonce
;
1660 g_string_append_printf(str
, "\t%s: %s\n", "server_challenge", (tmp
= bytes_to_hex_str(&buff
)));
1663 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->target_name
), "target_name")));
1666 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->target_info
), "target_info")));
1669 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_version(&(cmsg
->ver
))));
1672 if (cmsg
->target_name
.len
&& cmsg
->target_name
.offset
) {
1673 gchar
*target_name
= unicode_strconvcopy_back(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->target_name
.offset
)), GUINT16_FROM_LE(cmsg
->target_name
.len
));
1674 g_string_append_printf(str
, "\ttarget_name: %s\n", target_name
);
1675 g_free(target_name
);
1678 if (cmsg
->target_info
.len
&& cmsg
->target_info
.offset
) {
1679 void *target_info
= (gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->target_info
.offset
);
1680 guint16 target_info_len
= GUINT16_FROM_LE(cmsg
->target_info
.len
);
1683 buff
.length
= target_info_len
;
1684 buff
.value
= (gchar
*)target_info
;
1685 g_string_append_printf(str
, "\t%s: %s\n", "target_info raw", (tmp
= bytes_to_hex_str(&buff
)));
1688 describe_av_pairs(str
, target_info
);
1691 return g_string_free(str
, FALSE
);
1695 sip_sec_ntlm_message_describe(SipSecBuffer buff
)
1697 struct ntlm_message
*msg
;
1700 if (buff
.length
== 0 || buff
.value
== NULL
|| buff
.length
< 12) return NULL
;
1703 if(!sipe_strequal("NTLMSSP", (char*)msg
)) return NULL
;
1705 switch (GUINT32_FROM_LE(msg
->type
)) {
1706 case 1: res
= sip_sec_ntlm_negotiate_message_describe((struct negotiate_message
*)msg
);
1708 case 2: res
= sip_sec_ntlm_challenge_message_describe((struct challenge_message
*)msg
);
1710 case 3: res
= sip_sec_ntlm_authenticate_message_describe((struct authenticate_message
*)msg
);
1717 /* sip-sec-mech.h API implementation for NTLM */
1719 /* Security context for NTLM */
1720 typedef struct _context_ntlm
{
1721 struct sip_sec_context common
;
1726 guchar
*client_sign_key
;
1727 guchar
*server_sign_key
;
1728 guchar
*client_seal_key
;
1729 guchar
*server_seal_key
;
1735 sip_sec_acquire_cred__ntlm(SipSecContext context
,
1737 const char *username
,
1738 const char *password
)
1740 context_ntlm ctx
= (context_ntlm
)context
;
1742 /* NTLM requires a domain, username & password */
1743 if (!domain
|| !username
|| !password
)
1744 return SIP_SEC_E_INTERNAL_ERROR
;
1746 ctx
->domain
= g_strdup(domain
);
1747 ctx
->username
= g_strdup(username
);
1748 ctx
->password
= g_strdup(password
);
1750 return SIP_SEC_E_OK
;
1754 sip_sec_init_sec_context__ntlm(SipSecContext context
,
1755 SipSecBuffer in_buff
,
1756 SipSecBuffer
*out_buff
,
1757 SIPE_UNUSED_PARAMETER
const char *service_name
)
1759 context_ntlm ctx
= (context_ntlm
) context
;
1761 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1764 if (ctx
->step
== 1) {
1765 if (!context
->is_connection_based
) {
1766 out_buff
->length
= 0;
1767 out_buff
->value
= NULL
;
1769 sip_sec_ntlm_gen_negotiate(out_buff
);
1771 return SIP_SEC_I_CONTINUE_NEEDED
;
1775 guchar
*client_sign_key
= NULL
;
1776 guchar
*server_sign_key
= NULL
;
1777 guchar
*client_seal_key
= NULL
;
1778 guchar
*server_seal_key
= NULL
;
1779 guchar
*server_challenge
= NULL
;
1780 guint64 time_val
= 0;
1781 guchar
*target_info
= NULL
;
1782 int target_info_len
= 0;
1786 if (!in_buff
.value
|| !in_buff
.length
) {
1787 return SIP_SEC_E_INTERNAL_ERROR
;
1790 sip_sec_ntlm_parse_challenge(in_buff
,
1791 context
->is_connection_based
,
1793 &server_challenge
, /* 8 bytes */
1798 res
= sip_sec_ntlm_gen_authenticate(
1805 (tmp
= g_ascii_strup(sipe_get_host_name(), -1)),
1811 context
->is_connection_based
,
1814 g_free(server_challenge
);
1815 g_free(target_info
);
1818 if (res
!= SIP_SEC_E_OK
) {
1819 g_free(client_sign_key
);
1820 g_free(server_sign_key
);
1821 g_free(client_seal_key
);
1822 g_free(server_seal_key
);
1826 g_free(ctx
->client_sign_key
);
1827 ctx
->client_sign_key
= client_sign_key
;
1829 g_free(ctx
->server_sign_key
);
1830 ctx
->server_sign_key
= server_sign_key
;
1832 g_free(ctx
->client_seal_key
);
1833 ctx
->client_seal_key
= client_seal_key
;
1835 g_free(ctx
->server_seal_key
);
1836 ctx
->server_seal_key
= server_seal_key
;
1839 return SIP_SEC_E_OK
;
1844 * @param message a NULL terminated string to sign
1848 sip_sec_make_signature__ntlm(SipSecContext context
,
1849 const char *message
,
1850 SipSecBuffer
*signature
)
1852 /* FIXME? We always use a random_pad of 0 */
1853 gchar
*signature_hex
= sip_sec_ntlm_sipe_signature_make(((context_ntlm
) context
)->flags
,
1856 ((context_ntlm
) context
)->client_sign_key
,
1857 ((context_ntlm
) context
)->client_seal_key
);
1859 hex_str_to_bytes(signature_hex
, signature
);
1860 g_free(signature_hex
);
1862 return SIP_SEC_E_OK
;
1866 * @param message a NULL terminated string to check signature of
1867 * @return SIP_SEC_E_OK on success
1870 sip_sec_verify_signature__ntlm(SipSecContext context
,
1871 const char *message
,
1872 SipSecBuffer signature
)
1874 guint32 random_pad
= GUINT32_FROM_LE(((guint32
*) signature
.value
)[1]);
1875 char *signature_hex
= bytes_to_hex_str(&signature
);
1876 gchar
*signature_calc
= sip_sec_ntlm_sipe_signature_make(((context_ntlm
) context
)->flags
,
1879 ((context_ntlm
) context
)->server_sign_key
,
1880 ((context_ntlm
) context
)->server_seal_key
);
1883 if (sip_sec_ntlm_verify_signature(signature_calc
, signature_hex
)) {
1886 res
= SIP_SEC_E_INTERNAL_ERROR
;
1888 g_free(signature_calc
);
1889 g_free(signature_hex
);
1894 sip_sec_destroy_sec_context__ntlm(SipSecContext context
)
1896 context_ntlm ctx
= (context_ntlm
) context
;
1898 g_free(ctx
->domain
);
1899 g_free(ctx
->username
);
1900 g_free(ctx
->password
);
1901 g_free(ctx
->client_sign_key
);
1902 g_free(ctx
->server_sign_key
);
1903 g_free(ctx
->client_seal_key
);
1904 g_free(ctx
->server_seal_key
);
1909 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type
)
1911 context_ntlm context
= g_malloc0(sizeof(struct _context_ntlm
));
1912 if (!context
) return(NULL
);
1914 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__ntlm
;
1915 context
->common
.init_context_func
= sip_sec_init_sec_context__ntlm
;
1916 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__ntlm
;
1917 context
->common
.make_signature_func
= sip_sec_make_signature__ntlm
;
1918 context
->common
.verify_signature_func
= sip_sec_verify_signature__ntlm
;
1920 return((SipSecContext
) context
);
1923 void sip_sec_init__ntlm(void)
1925 #ifdef HAVE_LANGINFO_CODESET
1926 const char *sys_cp
= nl_langinfo(CODESET
);
1928 const char *sys_cp
= SIPE_DEFAULT_CODESET
;
1929 #endif /* HAVE_LANGINFO_CODESET */
1931 /* fall back to utf-8 */
1932 if (!sys_cp
) sys_cp
= "UTF-8";
1934 convert_from_utf16le
= g_iconv_open(sys_cp
, "UTF-16LE");
1935 if (convert_from_utf16le
== (GIConv
)-1) {
1936 purple_debug_error("sipe", "g_iconv_open from UTF-16LE to %s failed\n",
1940 convert_to_utf16le
= g_iconv_open("UTF-16LE", sys_cp
);
1941 if (convert_from_utf16le
== (GIConv
)-1) {
1942 purple_debug_error("sipe", "g_iconv_open from %s to UTF-16LE failed\n",
1947 void sip_sec_destroy__ntlm(void)
1949 g_iconv_close(convert_to_utf16le
);
1950 g_iconv_close(convert_from_utf16le
);