NTLM: fix pointer error in previous commit
[siplcs.git] / src / core / sip-sec-ntlm.c
blob55582bde61b4bfad1ae9dbe8c35bc56f6482d315
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2009, 2010 pier11 <pier11@operamail.com>
7 * Copyright (C) 2008 Novell, Inc.
8 * Modify 2007, Anibal Avelar <avelar@gmail.com>
9 * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
11 * Implemented with reference to the follow documentation:
12 * - http://davenport.sourceforge.net/ntlm.html
13 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
14 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * Byte order policy:
34 * - NTLM messages (byte streams) should be in LE (Little-Endian) byte order.
35 * - internal int16, int32, int64 should contain proper values.
36 * For example: 01 00 00 00 LE should be translated to (int32)1
37 * - When reading/writing from/to NTLM message appropriate conversion should
38 * be taken to properly present integer values. glib's "Byte Order Macros"
39 * should be used for that, for example GUINT32_FROM_LE
40 * - All calculations should be made in dedicated local variables (system-endian),
41 * not in NTLM (LE) structures.
44 #include <glib.h>
45 #include <glib/gprintf.h>
46 #include <stdio.h>
47 #include <errno.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include "debug.h"
52 #ifndef _WIN32
53 #include <sys/types.h>
54 #ifdef __sun__
55 #include <sys/sockio.h>
56 #endif
57 #else /* _WIN32 */
58 #include "libc_interface.h"
59 #ifdef _DLL
60 #define _WS2TCPIP_H_
61 #define _WINSOCK2API_
62 #define _LIBC_INTERNAL_
63 #endif /* _DLL */
64 #include "network.h"
65 #include "internal.h"
66 #endif /* _WIN32 */
68 #ifdef HAVE_LANGINFO_CODESET
69 #include <langinfo.h>
70 #endif /* HAVE_LANGINFO_CODESET */
72 #include "util.h"
73 #include "cipher.h"
75 #include "sipe.h"
76 #include "sipe-utils.h"
77 #include "sip-sec-mech.h"
78 #include "sip-sec-ntlm.h"
80 /* [MS-NLMP] */
81 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
82 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
83 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
84 #define r9 0x00000008 /* r9 */
85 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
86 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
87 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
88 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
89 #define r8 0x00000100 /* r8 */
90 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
91 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
92 #define anonymous 0x00000800 /* J */
93 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
94 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
95 #define r7 0x00004000 /* r7 */
96 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
97 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
98 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
99 #define r6 0x00040000 /* r6 */
100 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
101 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
102 #define r5 0x00200000 /* r5 */
103 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
104 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
105 #define r4 0x01000000 /* r4 */
106 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
107 #define r3 0x04000000 /* r3 */
108 #define r2 0x08000000 /* r2 */
109 #define r1 0x10000000 /* r1 */
110 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
111 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
112 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
114 /* AvId */
115 #define MsvAvEOL 0
116 #define MsvAvNbComputerName 1
117 #define MsvAvNbDomainName 2
118 #define MsvAvDnsComputerName 3
119 #define MsvAvDnsDomainName 4
120 /** @since Windows XP */
121 #define MsvAvDnsTreeName 5
122 /** @since Windows XP */
123 #define MsvAvFlags 6
124 /** @since Windows Vista */
125 #define MsvAvTimestamp 7
126 /** @since Windows Vista */
127 #define MsAvRestrictions 8
128 /** @since Windows 7 */
129 #define MsvAvTargetName 9
130 /** @since Windows 7 */
131 #define MsvChannelBindings 10
133 /* time_t <-> (guint64) time_val conversion */
134 #define TIME_VAL_FACTOR 10000000
135 #define TIME_VAL_OFFSET 116444736000000000LL
136 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
137 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
140 * NTLMv1 is no longer used except in tests. R.I.P.
142 * It remains in this file only for documentary purposes
144 #ifdef _SIPE_COMPILING_TESTS
145 static gboolean use_ntlm_v2 = FALSE;
146 #endif
148 /* Common negotiate flags */
149 #define NEGOTIATE_FLAGS_CONN \
150 NTLMSSP_NEGOTIATE_UNICODE | \
151 NTLMSSP_NEGOTIATE_56 | \
152 NTLMSSP_NEGOTIATE_128 | \
153 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
154 NTLMSSP_NEGOTIATE_NTLM | \
155 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
156 NTLMSSP_NEGOTIATE_KEY_EXCH | \
157 NTLMSSP_REQUEST_TARGET
159 /* Negotiate flags required in connectionless NTLM */
160 #define NEGOTIATE_FLAGS \
161 ( NEGOTIATE_FLAGS_CONN | \
162 NTLMSSP_NEGOTIATE_SIGN | \
163 NTLMSSP_NEGOTIATE_DATAGRAM )
165 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
166 #define NTLMSSP_LM_RESP_LEN 24
167 #define NTLMSSP_SESSION_KEY_LEN 16
168 #define MD4_DIGEST_LEN 16
169 #define MD5_DIGEST_LEN 16
171 #define IS_FLAG(flags, flag) ((flags & flag) == flag)
173 struct av_pair {
174 guint16 av_id;
175 guint16 av_len;
176 /* value */
179 /* to meet sparc's alignment requirement */
180 #define ALIGN_AV \
181 memcpy(&av_aligned, av, sizeof(av_aligned)); \
182 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
183 av_len = GUINT16_FROM_LE(av_aligned.av_len)
184 #define ALIGN_AV_LOOP_START \
185 struct av_pair av_aligned; \
186 guint16 av_id; \
187 guint16 av_len; \
188 ALIGN_AV; \
189 while (av_id != MsvAvEOL) { \
190 gchar *av_value = ((gchar *)av) + \
191 sizeof(struct av_pair); \
192 switch (av_id)
193 #define ALIGN_AV_LOOP_END \
194 av = av_value + av_len; \
195 ALIGN_AV; \
198 /* 8 bytes */
199 struct version {
200 guint8 product_major_version;
201 guint8 product_minor_version;
202 guint16 product_build;
203 guint8 zero2[3];
204 guint8 ntlm_revision_current;
207 /* 8 bytes */
208 struct smb_header {
209 guint16 len;
210 guint16 maxlen;
211 guint32 offset;
214 struct ntlm_message {
215 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
216 guint32 type; /* 0x00000003 */
219 struct negotiate_message {
220 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
221 guint32 type; /* 0x00000001 */
222 guint32 flags; /* 0xb203 */
223 struct smb_header domain;
224 struct smb_header host;
225 struct version ver;
226 /* payload
227 * - DomainName (always ASCII)
228 * - WorkstationName (always ASCII)
232 struct challenge_message {
233 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
234 guint32 type; /* 0x00000002 */
235 struct smb_header target_name;
236 guint32 flags; /* 0x8201 */
237 guint8 nonce[8];
238 guint8 zero1[8];
239 struct smb_header target_info;
240 struct version ver;
241 /* payload
242 * - TargetName (negotiated encoding)
243 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
247 struct authenticate_message {
248 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
249 guint32 type; /* 0x00000003 */
250 /** LmChallengeResponseFields */
251 struct smb_header lm_resp;
252 /** NtChallengeResponseFields */
253 struct smb_header nt_resp;
254 /** DomainNameFields */
255 struct smb_header domain;
256 /** UserNameFields */
257 struct smb_header user;
258 /** WorkstationFields */
259 struct smb_header host;
260 /** EncryptedRandomSessionKeyFields */
261 struct smb_header session_key;
262 guint32 flags;
263 struct version ver;
264 //guint8 mic[16];
265 /* payload
266 * - LmChallengeResponse
267 * - NtChallengeResponse
268 * - DomainName (negotiated encoding)
269 * - UserName (negotiated encoding)
270 * - Workstation (negotiated encoding)
271 * - EncryptedRandomSessionKey
275 #ifndef HAVE_LANGINFO_CODESET
276 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
277 #endif
279 /* Private Methods */
281 /* Utility Functions */
283 static int
284 unicode_strconvcopy_dir(gchar *dest, const gchar *source, int remlen, gsize source_len, gboolean to_16LE)
286 GIConv fd;
287 gchar *inbuf = (gchar *) source;
288 gchar *outbuf = dest;
289 gsize inbytes = source_len;
290 gsize outbytes = remlen;
291 #ifdef HAVE_LANGINFO_CODESET
292 char *sys_cp = nl_langinfo(CODESET);
293 #else
294 char *sys_cp = SIPE_DEFAULT_CODESET;
295 #endif /* HAVE_LANGINFO_CODESET */
297 /* fall back to utf-8 */
298 if (!sys_cp) sys_cp = "UTF-8";
300 fd = to_16LE ? g_iconv_open("UTF-16LE", sys_cp) : g_iconv_open(sys_cp, "UTF-16LE");
301 if( fd == (GIConv)-1 ) {
302 purple_debug_error( "sipe", "iconv_open returned -1, cannot continue\n" );
304 g_iconv(fd, &inbuf, &inbytes, &outbuf, &outbytes);
305 g_iconv_close(fd);
306 return (remlen - outbytes);
309 static int
310 unicode_strconvcopy(gchar *dest, const gchar *source, int remlen)
312 return unicode_strconvcopy_dir(dest, source, remlen, strlen(source), TRUE);
315 /* UTF-16LE to native encoding
316 * Must be g_free'd after use */
317 static gchar *
318 unicode_strconvcopy_back(const gchar *source,
319 int len)
321 char *res = NULL;
322 int dest_len = 2 * len;
323 gchar *dest = g_new0(gchar, dest_len);
325 dest_len = unicode_strconvcopy_dir(dest, source, dest_len, len, FALSE);
326 res = g_strndup(dest, dest_len);
327 g_free(dest);
329 return res;
332 /* crc32 source copy from gg's common.c */
333 static guint32 crc32_table[256];
334 static int crc32_initialized = 0;
336 static void crc32_make_table()
338 guint32 h = 1;
339 unsigned int i, j;
341 memset(crc32_table, 0, sizeof(crc32_table));
343 for (i = 128; i; i >>= 1) {
344 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
346 for (j = 0; j < 256; j += 2 * i)
347 crc32_table[i + j] = crc32_table[j] ^ h;
350 crc32_initialized = 1;
353 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
355 if (!crc32_initialized)
356 crc32_make_table();
358 if (!buf || len < 0)
359 return crc;
361 crc ^= 0xffffffffL;
363 while (len--)
364 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
366 return crc ^ 0xffffffffL;
369 static guint32
370 CRC32 (const char *msg, int len)
372 guint32 crc = 0L;//crc32(0L, Z_NULL, 0);
373 crc = crc32(crc, (guint8 *) msg, len);
374 //char * ptr = (char*) &crc;
375 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
376 return crc;
379 /* Cyphers */
381 #ifdef _SIPE_COMPILING_TESTS
382 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
384 key[0] = key_56[0];
385 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
386 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
387 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
388 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
389 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
390 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
391 key[7] = (key_56[6] << 1) & 0xFF;
394 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
396 PurpleCipher *cipher;
397 PurpleCipherContext *context;
398 size_t outlen;
400 cipher = purple_ciphers_find_cipher("des");
401 context = purple_cipher_context_new(cipher, NULL);
402 purple_cipher_context_set_key(context, (guchar*)key);
403 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
404 purple_cipher_context_destroy(context);
406 #endif
408 #ifdef _SIPE_COMPILING_TESTS
409 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
410 static void
411 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
413 unsigned char key[8];
414 setup_des_key(k, key);
415 des_ecb_encrypt(d, results, key);
418 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
419 static void
420 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
422 unsigned char keys[21];
424 /* Copy the first 16 bytes */
425 memcpy(keys, k, 16);
427 /* Zero out the last 5 bytes of the key */
428 memset(keys + 16, 0, 5);
430 DES(keys, d, results);
431 DES(keys + 7, d, results + 8);
432 DES(keys + 14, d, results + 16);
434 #endif
436 static void
437 RC4K (const unsigned char * k, unsigned long key_len, const unsigned char * d, int len, unsigned char * result)
439 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
440 purple_cipher_context_set_option(context, "key_len", (gpointer)key_len);
441 purple_cipher_context_set_key(context, k);
442 purple_cipher_context_encrypt(context, (const guchar *)d, len, result, NULL);
443 purple_cipher_context_destroy(context);
446 /* out 16 bytes */
447 static void
448 MD4 (const unsigned char * d, int len, unsigned char * result)
450 PurpleCipher * cipher = purple_ciphers_find_cipher("md4");
451 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
452 purple_cipher_context_append(context, (guchar*)d, len);
453 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
454 purple_cipher_context_destroy(context);
457 /* out 16 bytes */
458 static void
459 MD5 (const unsigned char * d, int len, unsigned char * result)
461 PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
462 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
463 purple_cipher_context_append(context, (guchar*)d, len);
464 purple_cipher_context_digest(context, MD5_DIGEST_LEN, (guchar*)result, NULL);
465 purple_cipher_context_destroy(context);
468 /* out 16 bytes */
470 static void
471 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
473 int i;
474 unsigned char ibuff[64 + data_len];
475 unsigned char obuff[64 + 16];
477 if (key_len > 64)
478 key_len = 64;
480 for (i = 0; i < key_len; i++) {
481 ibuff[i] = key[i] ^ 0x36;
482 obuff[i] = key[i] ^ 0x5c;
484 for (i = key_len; i < 64; i++) {
485 ibuff[i] = 0x36;
486 obuff[i] = 0x5c;
489 memcpy(ibuff+64, data, data_len);
491 MD5 (ibuff, 64 + data_len, obuff+64);
492 MD5 (obuff, 64 + 16, result);
494 #define HMAC_MD5 HMACT64
497 /* out 16 bytes */
498 static void
499 HMAC_MD5 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
501 PurpleCipher *cipher = purple_ciphers_find_cipher("hmac");
502 PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL);
504 purple_cipher_context_set_option(context, "hash", "md5");
505 purple_cipher_context_set_key_with_len(context, (guchar *)key, (key_len));
507 purple_cipher_context_append(context, (guchar *)data, data_len);
508 purple_cipher_context_digest(context, 16, (guchar*)result, NULL);
509 purple_cipher_context_destroy(context);
512 /* NTLM Core Methods */
514 static void
515 NONCE(unsigned char *buffer, int num)
517 int i;
518 for (i = 0; i < num; i++) {
519 buffer[i] = (rand() & 0xff);
523 #ifdef _SIPE_COMPILING_TESTS
524 static void
525 Z(unsigned char *buffer, int num)
527 memset(buffer, 0, num);
529 #endif
531 #ifdef _SIPE_COMPILING_TESTS
532 static void
533 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
535 /* "KGS!@#$%" */
536 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
537 unsigned char uppercase_password[14];
538 int i;
540 int len = strlen(password);
541 if (len > 14) {
542 len = 14;
545 // Uppercase password
546 for (i = 0; i < len; i++) {
547 uppercase_password[i] = g_ascii_toupper(password[i]);
550 // Zero the rest
551 for (; i < 14; i++) {
552 uppercase_password[i] = 0;
555 DES (uppercase_password, magic, result);
556 DES (uppercase_password + 7, magic, result + 8);
558 #endif
561 Define NTOWFv1(Passwd, User, UserDom) as
562 MD4(UNICODE(Passwd))
563 EndDefine
565 /* out 16 bytes */
566 static void
567 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
569 int len_u = 2 * strlen(password); // utf16 should not be more
570 unsigned char unicode_password[len_u];
572 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
573 MD4 (unicode_password, len_u, result);
577 Define NTOWFv2(Passwd, User, UserDom) as
578 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
579 EndDefine
581 /* out 16 bytes */
582 void
583 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
585 unsigned char response_key_nt_v1 [16];
586 int len_user = user ? strlen(user) : 0;
587 int len_domain = domain ? strlen(domain) : 0;
588 unsigned char user_upper[len_user + 1];
589 int len_user_u = 2 * len_user; // utf16 should not be more
590 int len_domain_u = 2 * len_domain; // utf16 should not be more
591 unsigned char buff[(len_user + len_domain)*2];
592 int i;
594 /* Uppercase user */
595 for (i = 0; i < len_user; i++) {
596 user_upper[i] = g_ascii_toupper(user[i]);
598 user_upper[len_user] = 0;
600 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
601 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
603 NTOWFv1(password, user, domain, response_key_nt_v1);
605 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
608 static void
609 compute_response(const guint32 neg_flags,
610 const unsigned char *response_key_nt,
611 const unsigned char *response_key_lm,
612 const guint8 *server_challenge,
613 const guint8 *client_challenge,
614 const guint64 time_val,
615 const guint8 *target_info,
616 int target_info_len,
617 unsigned char *lm_challenge_response,
618 unsigned char *nt_challenge_response,
619 unsigned char *session_base_key)
621 #ifdef _SIPE_COMPILING_TESTS
622 if (use_ntlm_v2)
624 #endif
626 Responserversion - The 1-byte response version. Currently set to 1.
627 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
628 Time - The 8-byte little-endian time in GMT.
629 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
630 ClientChallenge - The 8-byte challenge message generated by the client.
631 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
633 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
634 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
635 Time, //8bytes - 8
636 ClientChallenge, //8bytes - 16
637 Z(4), //4bytes - 24
638 ServerName, //variable - 28
639 Z(4)) //4bytes - 28+target_info_len
640 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
641 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
642 Set LmChallengeResponse to ConcatenationOf(
643 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
644 ClientChallenge )
645 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
646 EndDefine
648 guint8 tmp [16];
649 guint8 nt_proof_str [16];
651 /* client_challenge (8) & temp (temp_len) buff */
652 int temp_len = 8+8+8+4+target_info_len+4;
653 guint8 temp2 [8 + temp_len];
654 memset(temp2, 0, 8 + temp_len); /* init to 0 */
655 temp2[8+0] = 1;
656 temp2[8+1] = 1;
657 *((guint64 *)(temp2+8+8)) = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
658 memcpy(temp2+8+16, client_challenge, 8);
659 memcpy(temp2+8+28, target_info, target_info_len);
661 /* NTProofStr */
662 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
663 memcpy(temp2, server_challenge, 8);
664 HMAC_MD5(response_key_nt, 16, temp2, 8+temp_len, nt_proof_str);
666 /* NtChallengeResponse */
667 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
668 memcpy(nt_challenge_response, nt_proof_str, 16);
669 memcpy(nt_challenge_response+16, temp2+8, temp_len);
671 /* SessionBaseKey */
672 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
673 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
675 /* lm_challenge_response */
676 memcpy(tmp, server_challenge, 8);
677 memcpy(tmp+8, client_challenge, 8);
678 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
679 memcpy(lm_challenge_response+16, client_challenge, 8);
681 #ifndef _SIPE_COMPILING_TESTS
682 /* Not used in NTLMv2 */
683 (void)neg_flags;
684 #else
686 else
688 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
689 // @TODO do not even reference nt_challenge_response
690 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
691 DESL (response_key_lm, server_challenge, lm_challenge_response);
692 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
693 unsigned char prehash [16];
694 unsigned char hash [16];
696 /* nt_challenge_response */
697 memcpy(prehash, server_challenge, 8);
698 memcpy(prehash + 8, client_challenge, 8);
699 MD5 (prehash, 16, hash);
700 DESL (response_key_nt, hash, nt_challenge_response);
702 /* lm_challenge_response */
703 memcpy(lm_challenge_response, client_challenge, 8);
704 Z (lm_challenge_response+8, 16);
705 } else {
706 DESL (response_key_nt, server_challenge, nt_challenge_response);
707 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
708 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
709 } else {
710 DESL (response_key_lm, server_challenge, lm_challenge_response);
714 /* Session Key */
715 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
717 #endif
720 static void
721 KXKEY ( guint32 flags,
722 const unsigned char * session_base_key,
723 const unsigned char * lm_challenge_resonse,
724 const guint8 * server_challenge, /* 8-bytes, nonce */
725 unsigned char * key_exchange_key)
727 #ifdef _SIPE_COMPILING_TESTS
728 if (use_ntlm_v2)
730 #else
731 /* Not used in NTLMv2 */
732 (void)flags;
733 (void)lm_challenge_resonse;
734 (void)server_challenge;
735 #endif
736 memcpy(key_exchange_key, session_base_key, 16);
737 #ifdef _SIPE_COMPILING_TESTS
739 else
741 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
742 // Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
743 // Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
744 // EndDefine
745 guint8 tmp[16];
746 memcpy(tmp, server_challenge, 8);
747 memcpy(tmp+8, lm_challenge_resonse, 8);
748 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
749 } else {
750 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
751 memcpy(key_exchange_key, session_base_key, 16);
754 #endif
758 If (Mode equals "Client")
759 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
760 "session key to client-to-server signing key magic constant"))
761 Else
762 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
763 "session key to server-to-client signing key magic constant"))
764 Endif
766 static void
767 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
769 char * magic = client
770 ? "session key to client-to-server signing key magic constant"
771 : "session key to server-to-client signing key magic constant";
773 int len = strlen(magic) + 1;
774 unsigned char md5_input [16 + len];
775 memcpy(md5_input, random_session_key, 16);
776 memcpy(md5_input + 16, magic, len);
778 MD5 (md5_input, len + 16, result);
782 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
783 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
784 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
785 Set SealKey to RandomSessionKey
786 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
787 Set SealKey to RandomSessionKey[0..6]
788 Else
789 Set SealKey to RandomSessionKey[0..4]
790 Endif
792 If (Mode equals "Client")
793 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
794 Else
795 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
796 Endif
798 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
799 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
800 Else
801 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
802 Endif
803 EndDefine
805 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
806 static void
807 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
809 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
811 char * magic = client
812 ? "session key to client-to-server sealing key magic constant"
813 : "session key to server-to-client sealing key magic constant";
815 int len = strlen(magic) + 1;
816 unsigned char md5_input [16 + len];
817 int key_len;
819 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
820 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key (Extended session security)\n");
821 key_len = 16;
822 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
823 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key (Extended session security)\n");
824 key_len = 7;
825 } else {
826 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key (Extended session security)\n");
827 key_len = 5;
830 memcpy(md5_input, random_session_key, key_len);
831 memcpy(md5_input + key_len, magic, len);
833 MD5 (md5_input, key_len + len, result);
835 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
837 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
838 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key\n");
839 memcpy(result, random_session_key, 7);
840 result[7] = 0xA0;
841 } else {
842 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key\n");
843 memcpy(result, random_session_key, 5);
844 result[5] = 0xE5;
845 result[6] = 0x38;
846 result[7] = 0xB0;
849 else
851 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key\n");
852 memcpy(result, random_session_key, 16);
857 = for Extended Session Security =
858 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
859 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
860 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
862 = if Extended Session Security is NOT negotiated =
863 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
864 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
865 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
866 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
868 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
870 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
871 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
873 /** MAC(Handle, SigningKey, SeqNum, Message) */
874 static gchar *
875 MAC (guint32 flags,
876 const char *buf,
877 int buf_len,
878 unsigned char *sign_key,
879 unsigned long sign_key_len,
880 unsigned char *seal_key,
881 unsigned long seal_key_len,
882 guint32 random_pad,
883 guint32 sequence)
885 guchar result [16];
886 guint32 *res_ptr;
887 gchar signature [33];
888 int i, j;
890 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
892 Define MAC(Handle, SigningKey, SeqNum, Message) as
893 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
894 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
895 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
896 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
897 Set SeqNum to SeqNum + 1
898 EndDefine
900 /* If a key exchange key is negotiated
901 Define MAC(Handle, SigningKey, SeqNum, Message) as
902 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
903 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
904 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
905 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
906 Set SeqNum to SeqNum + 1
907 EndDefine
910 unsigned char seal_key_ [16];
911 guchar hmac[16];
912 guchar tmp[4 + buf_len];
914 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
915 RC4Init(Handle, SealingKey')
917 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
918 unsigned char tmp2 [16+4];
920 memcpy(tmp2, seal_key, seal_key_len);
921 *((guint32 *)(tmp2+16)) = GUINT32_TO_LE(sequence);
922 MD5 (tmp2, 16+4, seal_key_);
923 } else {
924 memcpy(seal_key_, seal_key, seal_key_len);
927 purple_debug_info("sipe", "NTLM MAC(): Extented Session Security\n");
929 res_ptr = (guint32 *)result;
930 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
931 res_ptr[3] = GUINT32_TO_LE(sequence);
933 res_ptr = (guint32 *)tmp;
934 res_ptr[0] = GUINT32_TO_LE(sequence);
935 memcpy(tmp+4, buf, buf_len);
937 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
939 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
940 purple_debug_info("sipe", "NTLM MAC(): Key Exchange\n");
941 RC4K(seal_key_, seal_key_len, hmac, 8, result+4);
942 } else {
943 purple_debug_info("sipe", "NTLM MAC(): *NO* Key Exchange\n");
944 memcpy(result+4, hmac, 8);
946 } else {
947 /* The content of the first 4 bytes is irrelevant */
948 guint32 plaintext [] = {
949 GUINT32_TO_LE(0),
950 GUINT32_TO_LE(CRC32(buf, strlen(buf))),
951 GUINT32_TO_LE(sequence)
952 }; // 4, 4, 4 bytes
954 purple_debug_info("sipe", "NTLM MAC(): *NO* Extented Session Security\n");
956 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, result+4);
957 //RC4K(seal_key, 8, (const guchar *)plaintext, 12, result+4);
959 res_ptr = (guint32 *)result;
960 // Highest four bytes are the Version
961 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
963 // Replace the first four bytes of the ciphertext with the random_pad
964 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
967 for (i = 0, j = 0; i < 16; i++, j+=2) {
968 g_sprintf(&signature[j], "%02X", result[i]);
971 return g_strdup(signature);
974 /* End Core NTLM Methods */
977 * @param server_challenge must be g_free()'d after use if requested
978 * @param target_info must be g_free()'d after use if requested
980 static void
981 purple_ntlm_parse_challenge(SipSecBuffer in_buff,
982 gboolean is_connection_based,
983 guint32 *flags,
984 guchar **server_challenge, /* 8 bytes */
985 guint64 *time_val,
986 guchar **target_info,
987 int *target_info_len)
989 guint32 our_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
990 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
991 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
993 /* server challenge (nonce) */
994 if (server_challenge) {
995 *server_challenge = (guchar *)g_new0(gchar, 8);
996 memcpy(*server_challenge, cmsg->nonce, 8);
999 /* flags */
1000 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", host_flags, (host_flags & our_flags) == our_flags);
1001 if (flags) {
1002 *flags = host_flags;
1005 /* target_info */
1006 if (cmsg->target_info.len && cmsg->target_info.offset) {
1007 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1008 void *av = content;
1009 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
1011 ALIGN_AV_LOOP_START
1013 /* @since Vista */
1014 case MsvAvTimestamp:
1015 if (time_val) {
1016 guint64 tmp;
1018 /* to meet sparc's alignment requirement */
1019 memcpy(&tmp, av_value, sizeof(tmp));
1020 *time_val = GUINT64_FROM_LE(tmp);
1022 break;
1024 ALIGN_AV_LOOP_END;
1026 if (target_info_len) {
1027 *target_info_len = len;
1029 if (target_info) {
1030 *target_info = (guchar *)g_new0(gchar, len);
1031 memcpy(*target_info, content, len);
1036 static void
1037 purple_ntlm_gen_authenticate(guchar **client_sign_key,
1038 guchar **server_sign_key,
1039 guchar **client_seal_key,
1040 guchar **server_seal_key,
1041 const gchar *user,
1042 const gchar *password,
1043 const gchar *hostname,
1044 const gchar *domain,
1045 const guint8 *server_challenge, /* nonce */
1046 const guint64 time_val,
1047 const guint8 *target_info,
1048 int target_info_len,
1049 gboolean is_connection_based,
1050 SipSecBuffer *out_buff,
1051 guint32 *flags)
1053 guint32 neg_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
1054 int ntlmssp_nt_resp_len =
1055 #ifdef _SIPE_COMPILING_TESTS
1056 use_ntlm_v2 ?
1057 #endif
1058 (16 + (32+target_info_len))
1059 #ifdef _SIPE_COMPILING_TESTS
1060 : NTLMSSP_LM_RESP_LEN
1061 #endif
1063 int msglen = sizeof(struct authenticate_message)
1064 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1065 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1066 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1067 struct authenticate_message *tmsg = g_malloc0(msglen);
1068 char *tmp;
1069 int remlen;
1070 guint32 offset;
1071 guint16 len;
1072 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1073 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1074 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1075 unsigned char nt_challenge_response [ntlmssp_nt_resp_len]; /* variable or 24 */
1076 unsigned char session_base_key [16];
1077 unsigned char key_exchange_key [16];
1078 unsigned char exported_session_key[16];
1079 unsigned char encrypted_random_session_key [16];
1080 unsigned char key [16];
1081 unsigned char client_challenge [8];
1083 NONCE (client_challenge, 8);
1085 #ifdef _SIPE_COMPILING_TESTS
1086 if (use_ntlm_v2) {
1087 #endif
1088 NTOWFv2 (password, user, domain, response_key_nt);
1089 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1090 #ifdef _SIPE_COMPILING_TESTS
1091 } else {
1092 NTOWFv1 (password, user, domain, response_key_nt);
1093 LMOWFv1 (password, user, domain, response_key_lm);
1095 #endif
1097 compute_response(neg_flags,
1098 response_key_nt,
1099 response_key_lm,
1100 server_challenge,
1101 client_challenge,
1102 time_val ? time_val : TIME_T_TO_VAL(time(NULL)),
1103 target_info,
1104 target_info_len,
1105 lm_challenge_response, /* out */
1106 nt_challenge_response, /* out */
1107 session_base_key); /* out */
1109 /* same as session_base_key for
1110 * - NTLNv1 w/o Ext.Sess.Sec and
1111 * - NTLMv2
1113 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1115 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1116 NONCE (exported_session_key, 16); // random master key
1117 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1118 } else {
1119 memcpy(exported_session_key, key_exchange_key, 16);
1122 /* p.46
1123 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1124 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1126 SIGNKEY(exported_session_key, TRUE, key);
1127 *client_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1128 SIGNKEY(exported_session_key, FALSE, key);
1129 *server_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1130 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1131 *client_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1132 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1133 *server_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1135 /* @since Vista
1136 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1137 the client SHOULD provide a MIC:
1138 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1139 - then in the Value field, set bit 0x2 to 1.
1140 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1141 and the Value field bit 0x2 to 1.
1142 - Populate the MIC field with the MIC.
1145 /* Connection-oriented:
1146 Set MIC to HMAC_MD5(ExportedSessionKey,
1147 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1148 Connectionless:
1149 Set MIC to HMAC_MD5(ExportedSessionKey,
1150 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1153 /* on the server-side:
1154 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1155 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1156 Set MIC to HMAC_MD5(ExportedSessionKey,
1157 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1158 Else
1159 Set ExportedSessionKey to KeyExchangeKey
1160 Set MIC to HMAC_MD5(KeyExchangeKey,
1161 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1162 =====
1163 @since Vista
1164 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1165 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1166 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1167 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1168 an AV_PAIR structure whose two fields:
1169 - AvId == MsvAvFlags
1170 - Value bit 0x2 == 1
1171 @supported NT, 2000, XP
1172 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1173 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1174 the server time, then the server SHOULD return a failure.
1176 Connectionless:
1177 Set MIC to HMAC_MD5(ResponseKeyNT,
1178 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1181 /* authenticate message initialization */
1182 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1183 tmsg->type = GUINT32_TO_LE(3);
1185 /* Set Negotiate Flags */
1186 tmsg->flags = GUINT32_TO_LE(neg_flags);
1188 /* Domain */
1189 tmsg->domain.offset = GUINT32_TO_LE(offset = sizeof(struct authenticate_message));
1190 tmp = ((char*) tmsg) + offset;
1191 remlen = ((char *)tmsg)+msglen-tmp;
1192 tmsg->domain.len = tmsg->domain.maxlen = GUINT16_TO_LE(len = unicode_strconvcopy(tmp, domain, remlen));
1193 tmp += len;
1194 remlen = ((char *)tmsg)+msglen-tmp;
1196 /* User */
1197 tmsg->user.offset = GUINT32_TO_LE(offset += len);
1198 tmsg->user.len = tmsg->user.maxlen = GUINT16_TO_LE(len = unicode_strconvcopy(tmp, user, remlen));
1199 tmp += len;
1200 remlen = ((char *)tmsg)+msglen-tmp;
1202 /* Host */
1203 tmsg->host.offset = GUINT32_TO_LE(offset += len);
1204 tmsg->host.len = tmsg->host.maxlen = GUINT16_TO_LE(len = unicode_strconvcopy(tmp, hostname, remlen));
1205 tmp += len;
1207 /* LM */
1208 /* @since Windows 7
1209 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1210 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1211 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1213 tmsg->lm_resp.offset = GUINT32_TO_LE(offset += len);
1214 tmsg->lm_resp.len = tmsg->lm_resp.maxlen = GUINT16_TO_LE(len = NTLMSSP_LM_RESP_LEN);
1215 memcpy(tmp, lm_challenge_response, len);
1216 tmp += len;
1218 /* NT */
1219 tmsg->nt_resp.offset = GUINT32_TO_LE(offset += len);
1220 tmsg->nt_resp.len = tmsg->nt_resp.maxlen = GUINT16_TO_LE(len = ntlmssp_nt_resp_len);
1221 memcpy(tmp, nt_challenge_response, len);
1222 tmp += len;
1224 /* Session Key */
1225 tmsg->session_key.offset = GUINT32_TO_LE(offset += len);
1226 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1228 tmsg->session_key.len = tmsg->session_key.maxlen = GUINT16_TO_LE(len = NTLMSSP_SESSION_KEY_LEN);
1229 memcpy(tmp, encrypted_random_session_key, len);
1230 tmp += len;
1232 else
1234 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1237 *flags = neg_flags;
1239 tmp = purple_base64_encode(exported_session_key, 16);
1240 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE session key: %s\n", tmp);
1241 g_free(tmp);
1243 out_buff->value = tmsg;
1244 out_buff->length = msglen;
1248 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1250 static void
1251 purple_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1253 guint32 offset;
1254 guint16 len;
1255 int msglen = sizeof(struct negotiate_message);
1256 struct negotiate_message *tmsg = g_malloc0(msglen);
1258 /* negotiate message initialization */
1259 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1260 tmsg->type = GUINT32_TO_LE(1);
1262 /* Set Negotiate Flags */
1263 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1265 /* Domain */
1266 tmsg->domain.offset = GUINT32_TO_LE(offset = sizeof(struct negotiate_message));
1267 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1269 /* Host */
1270 tmsg->host.offset = GUINT32_TO_LE(offset += len);
1271 tmsg->host.len = tmsg->host.maxlen = len = 0;
1273 /* Version */
1274 //tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1275 //tmsg->ver.product_minor_version = 1;
1276 //tmsg->ver.product_build = 2600;
1277 //tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1279 out_buff->value = tmsg;
1280 out_buff->length = msglen;
1283 static gchar *
1284 purple_ntlm_sipe_signature_make (guint32 flags, const char *msg, guint32 random_pad, unsigned char *sign_key, unsigned char *seal_key)
1286 gchar *res = MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100);
1287 //purple_debug_info("sipe", "NTLM calculated MAC: %s\n", res);
1288 return res;
1291 static gboolean
1292 purple_ntlm_verify_signature (char * a, char * b)
1294 return g_ascii_strncasecmp(a, b, 16*2) == 0;
1298 /* Describe NTLM messages functions */
1300 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1301 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1303 static gchar *
1304 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1306 GString* str = g_string_new(NULL);
1308 flags = GUINT32_FROM_LE(flags);
1310 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1311 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1312 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1313 APPEND_NEG_FLAG(str, flags, r9, "r9");
1314 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1315 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1316 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1317 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1318 APPEND_NEG_FLAG(str, flags, r8, "r8");
1319 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1320 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1321 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1322 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1323 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1324 APPEND_NEG_FLAG(str, flags, r7, "r7");
1325 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1326 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1327 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1328 APPEND_NEG_FLAG(str, flags, r6, "r6");
1329 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1330 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1331 APPEND_NEG_FLAG(str, flags, r5, "r5");
1332 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1333 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1334 APPEND_NEG_FLAG(str, flags, r4, "r4");
1335 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1336 APPEND_NEG_FLAG(str, flags, r3, "r3");
1337 APPEND_NEG_FLAG(str, flags, r2, "r2");
1338 APPEND_NEG_FLAG(str, flags, r1, "r1");
1339 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1340 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1341 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1343 return g_string_free(str, FALSE);
1346 static gchar *
1347 sip_sec_ntlm_describe_version(struct version *ver) {
1348 GString* str = g_string_new(NULL);
1349 gchar *ver_desc = "";
1350 gchar *ntlm_revision_desc = "";
1352 if (ver->product_major_version == 6) {
1353 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1354 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1355 ver_desc = "Windows Server 2003";
1356 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1357 ver_desc = "Windows XP SP2";
1360 if (ver->ntlm_revision_current == 0x0F) {
1361 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1362 } else if (ver->ntlm_revision_current == 0x0A) {
1363 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1366 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1367 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1368 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1370 return g_string_free(str, FALSE);
1373 static gchar *
1374 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1375 const char* name)
1377 GString* str = g_string_new(NULL);
1379 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1380 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1381 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1383 return g_string_free(str, FALSE);
1386 static gchar *
1387 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1389 GString* str = g_string_new(NULL);
1390 char *tmp;
1392 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1393 g_free(tmp);
1395 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1396 g_free(tmp);
1398 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1399 g_free(tmp);
1401 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1402 g_string_append(str, tmp);
1403 g_free(tmp);
1405 if (cmsg->domain.len && cmsg->domain.offset) {
1406 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1407 g_string_append_printf(str, "\tdomain: %s\n", domain);
1408 g_free(domain);
1411 if (cmsg->host.len && cmsg->host.offset) {
1412 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1413 g_string_append_printf(str, "\thost: %s\n", host);
1414 g_free(host);
1417 return g_string_free(str, FALSE);
1420 static void
1421 describe_av_pairs(GString* str, const void *av)
1423 #define AV_DESC(av_name) \
1425 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1426 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1427 g_free(tmp); \
1430 ALIGN_AV_LOOP_START
1432 case MsvAvNbComputerName:
1433 AV_DESC("MsvAvNbComputerName");
1434 break;
1435 case MsvAvNbDomainName:
1436 AV_DESC("MsvAvNbDomainName");
1437 break;
1438 case MsvAvDnsComputerName:
1439 AV_DESC("MsvAvDnsComputerName");
1440 break;
1441 case MsvAvDnsDomainName:
1442 AV_DESC("MsvAvDnsDomainName");
1443 break;
1444 case MsvAvDnsTreeName:
1445 AV_DESC("MsvAvDnsTreeName");
1446 break;
1447 case MsvAvFlags:
1449 guint32 flags;
1451 /* to meet sparc's alignment requirement */
1452 memcpy(&flags, av_value, sizeof(guint32));
1453 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1455 break;
1456 case MsvAvTimestamp:
1458 SipSecBuffer buff;
1459 char *tmp;
1460 guint64 time_val;
1461 time_t time_t_val;
1463 /* to meet sparc's alignment requirement */
1464 memcpy(&time_val, av_value, sizeof(time_val));
1465 time_t_val = TIME_VAL_TO_T(time_val);
1467 buff.length = 8;
1468 buff.value = av_value;
1469 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = bytes_to_hex_str(&buff)),
1470 asctime(gmtime(&time_t_val)));
1471 g_free(tmp);
1473 break;
1474 case MsAvRestrictions:
1475 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1476 break;
1477 case MsvAvTargetName:
1478 AV_DESC("MsvAvTargetName");
1479 break;
1480 case MsvChannelBindings:
1481 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1482 break;
1484 ALIGN_AV_LOOP_END;
1487 static gchar *
1488 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1490 GString* str = g_string_new(NULL);
1491 char *tmp;
1492 SipSecBuffer buff;
1494 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1495 g_free(tmp);
1497 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1498 g_free(tmp);
1500 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1501 g_free(tmp);
1503 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1504 g_free(tmp);
1506 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1507 g_free(tmp);
1509 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1510 g_free(tmp);
1512 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1513 g_free(tmp);
1515 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1516 g_string_append(str, tmp);
1517 g_free(tmp);
1519 /* mic */
1520 //buff.length = 16;
1521 //buff.value = cmsg->mic;
1522 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = bytes_to_hex_str(&buff)));
1523 //g_free(tmp);
1525 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1526 buff.length = GUINT16_FROM_LE(cmsg->lm_resp.len);
1527 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1528 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = bytes_to_hex_str(&buff)));
1529 g_free(tmp);
1532 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1533 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1534 int nt_resp_len = nt_resp_len_full;
1536 buff.length = nt_resp_len_full;
1537 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1538 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = bytes_to_hex_str(&buff)));
1539 g_free(tmp);
1541 if (nt_resp_len > 24) { /* NTLMv2 */
1542 nt_resp_len = 16;
1545 buff.length = nt_resp_len;
1546 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1547 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = bytes_to_hex_str(&buff)));
1548 g_free(tmp);
1550 if (nt_resp_len_full > 24) { /* NTLMv2 */
1551 char *tmp;
1552 SipSecBuffer buff;
1553 const gchar *temp = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1554 const int response_version = *((guchar*)temp);
1555 const int hi_response_version = *((guchar*)(temp+1));
1556 guint64 time_val;
1557 time_t time_t_val;
1558 const gchar *client_challenge = temp + 16;
1559 const gchar *target_info = temp + 28;
1560 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1562 buff.length = target_info_len;
1563 buff.value = (gchar *)target_info;
1564 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = bytes_to_hex_str(&buff)));
1565 g_free(tmp);
1567 /* This is not int64 aligned on sparc */
1568 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1569 time_t_val = TIME_VAL_TO_T(time_val);
1571 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1572 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1574 buff.length = 8;
1575 buff.value = (gchar*)&time_val;
1576 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = bytes_to_hex_str(&buff)),
1577 asctime(gmtime(&time_t_val)));
1578 g_free(tmp);
1580 buff.length = 8;
1581 buff.value = (gchar*)client_challenge;
1582 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = bytes_to_hex_str(&buff)));
1583 g_free(tmp);
1585 describe_av_pairs(str, target_info);
1587 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1591 if (cmsg->domain.len && cmsg->domain.offset) {
1592 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1593 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1594 g_free(domain);
1597 if (cmsg->user.len && cmsg->user.offset) {
1598 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1599 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1600 g_free(user);
1603 if (cmsg->host.len && cmsg->host.offset) {
1604 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1605 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1606 g_free(host);
1609 if (cmsg->session_key.len && cmsg->session_key.offset) {
1610 buff.length = GUINT16_FROM_LE(cmsg->session_key.len);
1611 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1612 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = bytes_to_hex_str(&buff)));
1613 g_free(tmp);
1616 return g_string_free(str, FALSE);
1619 static gchar *
1620 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1622 GString* str = g_string_new(NULL);
1623 char *tmp;
1624 SipSecBuffer buff;
1626 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1627 g_free(tmp);
1629 /* nonce (server_challenge) */
1630 buff.length = 8;
1631 buff.value = cmsg->nonce;
1632 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = bytes_to_hex_str(&buff)));
1633 g_free(tmp);
1635 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1636 g_free(tmp);
1638 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1639 g_free(tmp);
1641 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1642 g_free(tmp);
1644 if (cmsg->target_name.len && cmsg->target_name.offset) {
1645 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1646 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1647 g_free(target_name);
1650 if (cmsg->target_info.len && cmsg->target_info.offset) {
1651 void *target_info = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1652 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1653 SipSecBuffer buff;
1655 buff.length = target_info_len;
1656 buff.value = (gchar *)target_info;
1657 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = bytes_to_hex_str(&buff)));
1658 g_free(tmp);
1660 describe_av_pairs(str, target_info);
1663 return g_string_free(str, FALSE);
1666 gchar *
1667 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1669 struct ntlm_message *msg;
1670 gchar *res = NULL;
1672 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1674 msg = buff.value;
1675 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1677 switch (GUINT32_FROM_LE(msg->type)) {
1678 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1679 break;
1680 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1681 break;
1682 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1683 break;
1686 return res;
1689 /* sip-sec-mech.h API implementation for NTLM */
1691 /* Security context for NTLM */
1692 typedef struct _context_ntlm {
1693 struct sip_sec_context common;
1694 char* domain;
1695 char *username;
1696 char *password;
1697 int step;
1698 guchar *client_sign_key;
1699 guchar *server_sign_key;
1700 guchar *client_seal_key;
1701 guchar *server_seal_key;
1702 guint32 flags;
1703 } *context_ntlm;
1706 static sip_uint32
1707 sip_sec_acquire_cred__ntlm(SipSecContext context,
1708 const char *domain,
1709 const char *username,
1710 const char *password)
1712 context_ntlm ctx = (context_ntlm)context;
1714 /* NTLM requires a domain, username & password */
1715 if (!domain || !username || !password)
1716 return SIP_SEC_E_INTERNAL_ERROR;
1718 ctx->domain = g_strdup(domain);
1719 ctx->username = g_strdup(username);
1720 ctx->password = g_strdup(password);
1722 return SIP_SEC_E_OK;
1725 static sip_uint32
1726 sip_sec_init_sec_context__ntlm(SipSecContext context,
1727 SipSecBuffer in_buff,
1728 SipSecBuffer *out_buff,
1729 SIPE_UNUSED_PARAMETER const char *service_name)
1731 context_ntlm ctx = (context_ntlm) context;
1733 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1735 ctx->step++;
1736 if (ctx->step == 1) {
1737 if (!context->is_connection_based) {
1738 out_buff->length = 0;
1739 out_buff->value = NULL;
1740 } else {
1741 purple_ntlm_gen_negotiate(out_buff);
1743 return SIP_SEC_I_CONTINUE_NEEDED;
1745 } else {
1746 guchar *client_sign_key;
1747 guchar *server_sign_key;
1748 guchar *client_seal_key;
1749 guchar *server_seal_key;
1750 guchar *server_challenge = NULL;
1751 guint64 time_val = 0;
1752 guchar *target_info = NULL;
1753 int target_info_len = 0;
1754 guint32 flags;
1755 gchar *tmp;
1757 if (!in_buff.value || !in_buff.length) {
1758 return SIP_SEC_E_INTERNAL_ERROR;
1761 purple_ntlm_parse_challenge(in_buff,
1762 context->is_connection_based,
1763 &flags,
1764 &server_challenge, /* 8 bytes */
1765 &time_val,
1766 &target_info,
1767 &target_info_len);
1769 purple_ntlm_gen_authenticate(&client_sign_key,
1770 &server_sign_key,
1771 &client_seal_key,
1772 &server_seal_key,
1773 ctx->username,
1774 ctx->password,
1775 (tmp = g_ascii_strup(sipe_get_host_name(), -1)),
1776 ctx->domain,
1777 server_challenge,
1778 time_val,
1779 target_info,
1780 target_info_len,
1781 context->is_connection_based,
1782 out_buff,
1783 &flags);
1784 g_free(server_challenge);
1785 g_free(target_info);
1786 g_free(tmp);
1788 g_free(ctx->client_sign_key);
1789 ctx->client_sign_key = client_sign_key;
1791 g_free(ctx->server_sign_key);
1792 ctx->server_sign_key = server_sign_key;
1794 g_free(ctx->client_seal_key);
1795 ctx->client_seal_key = client_seal_key;
1797 g_free(ctx->server_seal_key);
1798 ctx->server_seal_key = server_seal_key;
1800 ctx->flags = flags;
1801 return SIP_SEC_E_OK;
1806 * @param message a NULL terminated string to sign
1809 static sip_uint32
1810 sip_sec_make_signature__ntlm(SipSecContext context,
1811 const char *message,
1812 SipSecBuffer *signature)
1814 /* FIXME? We always use a random_pad of 0 */
1815 gchar *signature_hex = purple_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1816 message,
1818 ((context_ntlm) context)->client_sign_key,
1819 ((context_ntlm) context)->client_seal_key);
1821 hex_str_to_bytes(signature_hex, signature);
1822 g_free(signature_hex);
1824 return SIP_SEC_E_OK;
1828 * @param message a NULL terminated string to check signature of
1829 * @return SIP_SEC_E_OK on success
1831 static sip_uint32
1832 sip_sec_verify_signature__ntlm(SipSecContext context,
1833 const char *message,
1834 SipSecBuffer signature)
1836 guint32 random_pad = GUINT32_FROM_LE(((guint32 *) signature.value)[1]);
1837 char *signature_hex = bytes_to_hex_str(&signature);
1838 gchar *signature_calc = purple_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1839 message,
1840 random_pad,
1841 ((context_ntlm) context)->server_sign_key,
1842 ((context_ntlm) context)->server_seal_key);
1843 sip_uint32 res;
1845 if (purple_ntlm_verify_signature(signature_calc, signature_hex)) {
1846 res = SIP_SEC_E_OK;
1847 } else {
1848 res = SIP_SEC_E_INTERNAL_ERROR;
1850 g_free(signature_calc);
1851 g_free(signature_hex);
1852 return(res);
1855 static void
1856 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1858 context_ntlm ctx = (context_ntlm) context;
1860 g_free(ctx->domain);
1861 g_free(ctx->username);
1862 g_free(ctx->password);
1863 g_free(ctx->client_sign_key);
1864 g_free(ctx->server_sign_key);
1865 g_free(ctx->client_seal_key);
1866 g_free(ctx->server_seal_key);
1867 g_free(ctx);
1870 SipSecContext
1871 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1873 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1874 if (!context) return(NULL);
1876 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1877 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1878 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1879 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1880 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1882 return((SipSecContext) context);
1887 Local Variables:
1888 mode: c
1889 c-file-style: "bsd"
1890 indent-tabs-mode: t
1891 tab-width: 8
1892 End: