tests: test for high-level functions
[siplcs.git] / src / core / sip-sec-ntlm.c
blobada61569ba5c6c8abc4bde025f10e1e1f20f9c42
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2009, 2010 pier11 <pier11@operamail.com>
7 * Copyright (C) 2008 Novell, Inc.
8 * Modify 2007, Anibal Avelar <avelar@gmail.com>
9 * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
11 * Implemented with reference to the follow documentation:
12 * - http://davenport.sourceforge.net/ntlm.html
13 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
14 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * Byte order policy:
34 * - NTLM messages (byte streams) should be in LE (Little-Endian) byte order.
35 * - internal int16, int32, int64 should contain proper values.
36 * For example: 01 00 00 00 LE should be translated to (int32)1
37 * - When reading/writing from/to NTLM message appropriate conversion should
38 * be taken to properly present integer values. glib's "Byte Order Macros"
39 * should be used for that, for example GUINT32_FROM_LE
41 * NOTE: The Byte Order Macros can have side effects!
42 * Do *NOT* make any calculations inside the macros!
44 * - All calculations should be made in dedicated local variables (system-endian),
45 * not in NTLM (LE) structures.
48 #include <glib.h>
49 #include <glib/gprintf.h>
50 #include <stdio.h>
51 #include <errno.h>
52 #include <string.h>
53 #include <stdlib.h>
54 #include "debug.h"
56 #ifndef _WIN32
57 #include <sys/types.h>
58 #ifdef __sun__
59 #include <sys/sockio.h>
60 #endif
61 #else /* _WIN32 */
62 #include "libc_interface.h"
63 #ifdef _DLL
64 #define _WS2TCPIP_H_
65 #define _WINSOCK2API_
66 #define _LIBC_INTERNAL_
67 #endif /* _DLL */
68 #include "network.h"
69 #include "internal.h"
70 #endif /* _WIN32 */
72 #ifdef HAVE_LANGINFO_CODESET
73 #include <langinfo.h>
74 #endif /* HAVE_LANGINFO_CODESET */
76 #include "util.h"
77 #include "cipher.h"
79 #include "sipe.h"
80 #include "sipe-utils.h"
81 #include "sip-sec-mech.h"
82 #include "sip-sec-ntlm.h"
84 /* [MS-NLMP] */
85 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
86 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
87 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
88 #define r9 0x00000008 /* r9 */
89 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
90 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
91 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
92 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
93 #define r8 0x00000100 /* r8 */
94 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
95 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
96 #define anonymous 0x00000800 /* J */
97 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
98 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
99 #define r7 0x00004000 /* r7 */
100 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
101 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
102 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
103 #define r6 0x00040000 /* r6 */
104 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
105 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
106 #define r5 0x00200000 /* r5 */
107 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
108 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
109 #define r4 0x01000000 /* r4 */
110 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
111 #define r3 0x04000000 /* r3 */
112 #define r2 0x08000000 /* r2 */
113 #define r1 0x10000000 /* r1 */
114 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
115 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
116 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
118 /* AvId */
119 #define MsvAvEOL 0
120 #define MsvAvNbComputerName 1
121 #define MsvAvNbDomainName 2
122 #define MsvAvDnsComputerName 3
123 #define MsvAvDnsDomainName 4
124 /** @since Windows XP */
125 #define MsvAvDnsTreeName 5
126 /** @since Windows XP */
127 #define MsvAvFlags 6
128 /** @since Windows Vista */
129 #define MsvAvTimestamp 7
130 /** @since Windows Vista */
131 #define MsAvRestrictions 8
132 /** @since Windows 7 */
133 #define MsvAvTargetName 9
134 /** @since Windows 7 */
135 #define MsvChannelBindings 10
137 /* time_t <-> (guint64) time_val conversion */
138 #define TIME_VAL_FACTOR 10000000
139 #define TIME_VAL_OFFSET 116444736000000000LL
140 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
141 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
143 /* 8 bytes */
144 struct version {
145 guint8 product_major_version;
146 guint8 product_minor_version;
147 guint16 product_build;
148 guint8 zero2[3];
149 guint8 ntlm_revision_current;
153 * NTLMv1 is no longer used except in tests. R.I.P.
155 * It remains in this file only for documentary purposes
157 #ifdef _SIPE_COMPILING_TESTS
158 static gboolean use_ntlm_v2 = FALSE;
160 guint64 test_time_val = 0; /* actual time in implementation */
161 guchar test_client_challenge [8]; /* random in implementation */
162 guchar test_random_session_key[16]; /* random in implementation */
163 struct version test_version; /* optional, not set in in implementation */
164 #endif
166 /* Common negotiate flags */
167 #define NEGOTIATE_FLAGS_CONN \
168 NTLMSSP_NEGOTIATE_UNICODE | \
169 NTLMSSP_NEGOTIATE_56 | \
170 NTLMSSP_NEGOTIATE_128 | \
171 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
172 NTLMSSP_NEGOTIATE_NTLM | \
173 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
174 NTLMSSP_NEGOTIATE_KEY_EXCH | \
175 NTLMSSP_REQUEST_TARGET
177 /* Negotiate flags required in connectionless NTLM */
178 #define NEGOTIATE_FLAGS \
179 ( NEGOTIATE_FLAGS_CONN | \
180 NTLMSSP_NEGOTIATE_SIGN | \
181 NTLMSSP_NEGOTIATE_DATAGRAM )
183 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
184 #define NTLMSSP_LM_RESP_LEN 24
185 #define NTLMSSP_SESSION_KEY_LEN 16
186 #define MD4_DIGEST_LEN 16
187 #define MD5_DIGEST_LEN 16
189 #define IS_FLAG(flags, flag) ((flags & flag) == flag)
191 struct av_pair {
192 guint16 av_id;
193 guint16 av_len;
194 /* value */
197 /* to meet sparc's alignment requirement */
198 #define ALIGN_AV \
199 memcpy(&av_aligned, av, sizeof(av_aligned)); \
200 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
201 av_len = GUINT16_FROM_LE(av_aligned.av_len)
202 #define ALIGN_AV_LOOP_START \
203 struct av_pair av_aligned; \
204 guint16 av_id; \
205 guint16 av_len; \
206 ALIGN_AV; \
207 while (av_id != MsvAvEOL) { \
208 gchar *av_value = ((gchar *)av) + \
209 sizeof(struct av_pair); \
210 switch (av_id)
211 #define ALIGN_AV_LOOP_END \
212 av = av_value + av_len; \
213 ALIGN_AV; \
216 /* 8 bytes */
217 struct smb_header {
218 guint16 len;
219 guint16 maxlen;
220 guint32 offset;
223 struct ntlm_message {
224 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
225 guint32 type; /* 0x00000003 */
228 struct negotiate_message {
229 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
230 guint32 type; /* 0x00000001 */
231 guint32 flags; /* 0xb203 */
232 struct smb_header domain;
233 struct smb_header host;
234 struct version ver;
235 /* payload
236 * - DomainName (always ASCII)
237 * - WorkstationName (always ASCII)
241 struct challenge_message {
242 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
243 guint32 type; /* 0x00000002 */
244 struct smb_header target_name;
245 guint32 flags; /* 0x8201 */
246 guint8 nonce[8];
247 guint8 zero1[8];
248 struct smb_header target_info;
249 struct version ver;
250 /* payload
251 * - TargetName (negotiated encoding)
252 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
256 struct authenticate_message {
257 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
258 guint32 type; /* 0x00000003 */
259 /** LmChallengeResponseFields */
260 struct smb_header lm_resp;
261 /** NtChallengeResponseFields */
262 struct smb_header nt_resp;
263 /** DomainNameFields */
264 struct smb_header domain;
265 /** UserNameFields */
266 struct smb_header user;
267 /** WorkstationFields */
268 struct smb_header host;
269 /** EncryptedRandomSessionKeyFields */
270 struct smb_header session_key;
271 guint32 flags;
272 struct version ver;
273 //guint8 mic[16];
274 /* payload
275 * - LmChallengeResponse
276 * - NtChallengeResponse
277 * - DomainName (negotiated encoding)
278 * - UserName (negotiated encoding)
279 * - Workstation (negotiated encoding)
280 * - EncryptedRandomSessionKey
284 #ifndef HAVE_LANGINFO_CODESET
285 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
286 #endif
288 /* Private Methods */
290 /* Utility Functions */
292 static int
293 unicode_strconvcopy_dir(gchar *dest, const gchar *source, int remlen, gsize source_len, gboolean to_16LE)
295 GIConv fd;
296 gchar *inbuf = (gchar *) source;
297 gchar *outbuf = dest;
298 gsize inbytes = source_len;
299 gsize outbytes = remlen;
300 #ifdef HAVE_LANGINFO_CODESET
301 char *sys_cp = nl_langinfo(CODESET);
302 #else
303 char *sys_cp = SIPE_DEFAULT_CODESET;
304 #endif /* HAVE_LANGINFO_CODESET */
306 /* fall back to utf-8 */
307 if (!sys_cp) sys_cp = "UTF-8";
309 fd = to_16LE ? g_iconv_open("UTF-16LE", sys_cp) : g_iconv_open(sys_cp, "UTF-16LE");
310 if( fd == (GIConv)-1 ) {
311 purple_debug_error( "sipe", "iconv_open returned -1, cannot continue\n" );
313 g_iconv(fd, &inbuf, &inbytes, &outbuf, &outbytes);
314 g_iconv_close(fd);
315 return (remlen - outbytes);
318 static int
319 unicode_strconvcopy(gchar *dest, const gchar *source, int remlen)
321 return unicode_strconvcopy_dir(dest, source, remlen, strlen(source), TRUE);
324 /* UTF-16LE to native encoding
325 * Must be g_free'd after use */
326 static gchar *
327 unicode_strconvcopy_back(const gchar *source,
328 int len)
330 char *res = NULL;
331 int dest_len = 2 * len;
332 gchar *dest = g_new0(gchar, dest_len);
334 dest_len = unicode_strconvcopy_dir(dest, source, dest_len, len, FALSE);
335 res = g_strndup(dest, dest_len);
336 g_free(dest);
338 return res;
341 /* crc32 source copy from gg's common.c */
342 static guint32 crc32_table[256];
343 static int crc32_initialized = 0;
345 static void crc32_make_table()
347 guint32 h = 1;
348 unsigned int i, j;
350 memset(crc32_table, 0, sizeof(crc32_table));
352 for (i = 128; i; i >>= 1) {
353 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
355 for (j = 0; j < 256; j += 2 * i)
356 crc32_table[i + j] = crc32_table[j] ^ h;
359 crc32_initialized = 1;
362 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
364 if (!crc32_initialized)
365 crc32_make_table();
367 if (!buf || len < 0)
368 return crc;
370 crc ^= 0xffffffffL;
372 while (len--)
373 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
375 return crc ^ 0xffffffffL;
378 static guint32
379 CRC32 (const char *msg, int len)
381 guint32 crc = 0L;//crc32(0L, Z_NULL, 0);
382 crc = crc32(crc, (guint8 *) msg, len);
383 //char * ptr = (char*) &crc;
384 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
385 return crc;
388 /* Cyphers */
390 #ifdef _SIPE_COMPILING_TESTS
391 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
393 key[0] = key_56[0];
394 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
395 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
396 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
397 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
398 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
399 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
400 key[7] = (key_56[6] << 1) & 0xFF;
403 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
405 PurpleCipher *cipher;
406 PurpleCipherContext *context;
407 size_t outlen;
409 cipher = purple_ciphers_find_cipher("des");
410 context = purple_cipher_context_new(cipher, NULL);
411 purple_cipher_context_set_key(context, (guchar*)key);
412 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
413 purple_cipher_context_destroy(context);
415 #endif
417 #ifdef _SIPE_COMPILING_TESTS
418 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
419 static void
420 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
422 unsigned char key[8];
423 setup_des_key(k, key);
424 des_ecb_encrypt(d, results, key);
427 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
428 static void
429 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
431 unsigned char keys[21];
433 /* Copy the first 16 bytes */
434 memcpy(keys, k, 16);
436 /* Zero out the last 5 bytes of the key */
437 memset(keys + 16, 0, 5);
439 DES(keys, d, results);
440 DES(keys + 7, d, results + 8);
441 DES(keys + 14, d, results + 16);
443 #endif
445 static void
446 RC4K (const unsigned char * k, unsigned long key_len, const unsigned char * d, int len, unsigned char * result)
448 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
449 purple_cipher_context_set_option(context, "key_len", (gpointer)key_len);
450 purple_cipher_context_set_key(context, k);
451 purple_cipher_context_encrypt(context, (const guchar *)d, len, result, NULL);
452 purple_cipher_context_destroy(context);
455 /* out 16 bytes */
456 static void
457 MD4 (const unsigned char * d, int len, unsigned char * result)
459 PurpleCipher * cipher = purple_ciphers_find_cipher("md4");
460 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
461 purple_cipher_context_append(context, (guchar*)d, len);
462 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
463 purple_cipher_context_destroy(context);
466 /* out 16 bytes */
467 static void
468 MD5 (const unsigned char * d, int len, unsigned char * result)
470 PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
471 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
472 purple_cipher_context_append(context, (guchar*)d, len);
473 purple_cipher_context_digest(context, MD5_DIGEST_LEN, (guchar*)result, NULL);
474 purple_cipher_context_destroy(context);
477 /* out 16 bytes */
479 static void
480 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
482 int i;
483 unsigned char ibuff[64 + data_len];
484 unsigned char obuff[64 + 16];
486 if (key_len > 64)
487 key_len = 64;
489 for (i = 0; i < key_len; i++) {
490 ibuff[i] = key[i] ^ 0x36;
491 obuff[i] = key[i] ^ 0x5c;
493 for (i = key_len; i < 64; i++) {
494 ibuff[i] = 0x36;
495 obuff[i] = 0x5c;
498 memcpy(ibuff+64, data, data_len);
500 MD5 (ibuff, 64 + data_len, obuff+64);
501 MD5 (obuff, 64 + 16, result);
503 #define HMAC_MD5 HMACT64
506 /* out 16 bytes */
507 static void
508 HMAC_MD5 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
510 PurpleCipher *cipher = purple_ciphers_find_cipher("hmac");
511 PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL);
513 purple_cipher_context_set_option(context, "hash", "md5");
514 purple_cipher_context_set_key_with_len(context, (guchar *)key, (key_len));
516 purple_cipher_context_append(context, (guchar *)data, data_len);
517 purple_cipher_context_digest(context, 16, (guchar*)result, NULL);
518 purple_cipher_context_destroy(context);
521 /* NTLM Core Methods */
523 static void
524 NONCE(unsigned char *buffer, int num)
526 int i;
527 for (i = 0; i < num; i++) {
528 buffer[i] = (rand() & 0xff);
532 #ifdef _SIPE_COMPILING_TESTS
533 static void
534 Z(unsigned char *buffer, int num)
536 memset(buffer, 0, num);
538 #endif
540 #ifdef _SIPE_COMPILING_TESTS
541 static void
542 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
544 /* "KGS!@#$%" */
545 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
546 unsigned char uppercase_password[14];
547 int i;
549 int len = strlen(password);
550 if (len > 14) {
551 len = 14;
554 // Uppercase password
555 for (i = 0; i < len; i++) {
556 uppercase_password[i] = g_ascii_toupper(password[i]);
559 // Zero the rest
560 for (; i < 14; i++) {
561 uppercase_password[i] = 0;
564 DES (uppercase_password, magic, result);
565 DES (uppercase_password + 7, magic, result + 8);
567 #endif
570 Define NTOWFv1(Passwd, User, UserDom) as
571 MD4(UNICODE(Passwd))
572 EndDefine
574 /* out 16 bytes */
575 static void
576 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
578 int len_u = 2 * strlen(password); // utf16 should not be more
579 unsigned char unicode_password[len_u];
581 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
582 MD4 (unicode_password, len_u, result);
586 Define NTOWFv2(Passwd, User, UserDom) as
587 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
588 EndDefine
590 /* out 16 bytes */
591 void
592 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
594 unsigned char response_key_nt_v1 [16];
595 int len_user = user ? strlen(user) : 0;
596 int len_domain = domain ? strlen(domain) : 0;
597 unsigned char user_upper[len_user + 1];
598 int len_user_u = 2 * len_user; // utf16 should not be more
599 int len_domain_u = 2 * len_domain; // utf16 should not be more
600 unsigned char buff[(len_user + len_domain)*2];
601 int i;
603 /* Uppercase user */
604 for (i = 0; i < len_user; i++) {
605 user_upper[i] = g_ascii_toupper(user[i]);
607 user_upper[len_user] = 0;
609 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
610 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
612 NTOWFv1(password, user, domain, response_key_nt_v1);
614 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
617 static void
618 compute_response(const guint32 neg_flags,
619 const unsigned char *response_key_nt,
620 const unsigned char *response_key_lm,
621 const guint8 *server_challenge,
622 const guint8 *client_challenge,
623 const guint64 time_val,
624 const guint8 *target_info,
625 int target_info_len,
626 unsigned char *lm_challenge_response,
627 unsigned char *nt_challenge_response,
628 unsigned char *session_base_key)
630 #ifdef _SIPE_COMPILING_TESTS
631 if (use_ntlm_v2)
633 #endif
635 Responserversion - The 1-byte response version. Currently set to 1.
636 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
637 Time - The 8-byte little-endian time in GMT.
638 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
639 ClientChallenge - The 8-byte challenge message generated by the client.
640 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
642 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
643 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
644 Time, //8bytes - 8
645 ClientChallenge, //8bytes - 16
646 Z(4), //4bytes - 24
647 ServerName, //variable - 28
648 Z(4)) //4bytes - 28+target_info_len
649 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
650 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
651 Set LmChallengeResponse to ConcatenationOf(
652 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
653 ClientChallenge )
654 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
655 EndDefine
657 guint8 tmp [16];
658 guint8 nt_proof_str [16];
660 /* client_challenge (8) & temp (temp_len) buff */
661 int temp_len = 8+8+8+4+target_info_len+4;
662 guint8 temp2 [8 + temp_len];
663 memset(temp2, 0, 8 + temp_len); /* init to 0 */
664 temp2[8+0] = 1;
665 temp2[8+1] = 1;
666 *((guint64 *)(temp2+8+8)) = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
667 memcpy(temp2+8+16, client_challenge, 8);
668 memcpy(temp2+8+28, target_info, target_info_len);
670 /* NTProofStr */
671 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
672 memcpy(temp2, server_challenge, 8);
673 HMAC_MD5(response_key_nt, 16, temp2, 8+temp_len, nt_proof_str);
675 /* NtChallengeResponse */
676 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
677 memcpy(nt_challenge_response, nt_proof_str, 16);
678 memcpy(nt_challenge_response+16, temp2+8, temp_len);
680 /* SessionBaseKey */
681 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
682 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
684 /* lm_challenge_response */
685 memcpy(tmp, server_challenge, 8);
686 memcpy(tmp+8, client_challenge, 8);
687 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
688 memcpy(lm_challenge_response+16, client_challenge, 8);
690 #ifndef _SIPE_COMPILING_TESTS
691 /* Not used in NTLMv2 */
692 (void)neg_flags;
693 #else
695 else
697 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
698 // @TODO do not even reference nt_challenge_response
699 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
700 DESL (response_key_lm, server_challenge, lm_challenge_response);
701 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
702 unsigned char prehash [16];
703 unsigned char hash [16];
705 /* nt_challenge_response */
706 memcpy(prehash, server_challenge, 8);
707 memcpy(prehash + 8, client_challenge, 8);
708 MD5 (prehash, 16, hash);
709 DESL (response_key_nt, hash, nt_challenge_response);
711 /* lm_challenge_response */
712 memcpy(lm_challenge_response, client_challenge, 8);
713 Z (lm_challenge_response+8, 16);
714 } else {
715 DESL (response_key_nt, server_challenge, nt_challenge_response);
716 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
717 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
718 } else {
719 DESL (response_key_lm, server_challenge, lm_challenge_response);
723 /* Session Key */
724 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
726 #endif
729 static void
730 KXKEY ( guint32 flags,
731 const unsigned char * session_base_key,
732 const unsigned char * lm_challenge_resonse,
733 const guint8 * server_challenge, /* 8-bytes, nonce */
734 unsigned char * key_exchange_key)
736 #ifdef _SIPE_COMPILING_TESTS
737 if (use_ntlm_v2)
739 #else
740 /* Not used in NTLMv2 */
741 (void)flags;
742 (void)lm_challenge_resonse;
743 (void)server_challenge;
744 #endif
745 memcpy(key_exchange_key, session_base_key, 16);
746 #ifdef _SIPE_COMPILING_TESTS
748 else
750 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
751 // Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
752 // Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
753 // EndDefine
754 guint8 tmp[16];
755 memcpy(tmp, server_challenge, 8);
756 memcpy(tmp+8, lm_challenge_resonse, 8);
757 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
758 } else {
759 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
760 memcpy(key_exchange_key, session_base_key, 16);
763 #endif
767 If (Mode equals "Client")
768 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
769 "session key to client-to-server signing key magic constant"))
770 Else
771 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
772 "session key to server-to-client signing key magic constant"))
773 Endif
775 static void
776 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
778 char * magic = client
779 ? "session key to client-to-server signing key magic constant"
780 : "session key to server-to-client signing key magic constant";
782 int len = strlen(magic) + 1;
783 unsigned char md5_input [16 + len];
784 memcpy(md5_input, random_session_key, 16);
785 memcpy(md5_input + 16, magic, len);
787 MD5 (md5_input, len + 16, result);
791 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
792 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
793 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
794 Set SealKey to RandomSessionKey
795 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
796 Set SealKey to RandomSessionKey[0..6]
797 Else
798 Set SealKey to RandomSessionKey[0..4]
799 Endif
801 If (Mode equals "Client")
802 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
803 Else
804 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
805 Endif
807 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
808 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
809 Else
810 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
811 Endif
812 EndDefine
814 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
815 static void
816 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
818 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
820 char * magic = client
821 ? "session key to client-to-server sealing key magic constant"
822 : "session key to server-to-client sealing key magic constant";
824 int len = strlen(magic) + 1;
825 unsigned char md5_input [16 + len];
826 int key_len;
828 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
829 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key (Extended session security)\n");
830 key_len = 16;
831 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
832 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key (Extended session security)\n");
833 key_len = 7;
834 } else {
835 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key (Extended session security)\n");
836 key_len = 5;
839 memcpy(md5_input, random_session_key, key_len);
840 memcpy(md5_input + key_len, magic, len);
842 MD5 (md5_input, key_len + len, result);
844 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
846 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
847 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key\n");
848 memcpy(result, random_session_key, 7);
849 result[7] = 0xA0;
850 } else {
851 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key\n");
852 memcpy(result, random_session_key, 5);
853 result[5] = 0xE5;
854 result[6] = 0x38;
855 result[7] = 0xB0;
858 else
860 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key\n");
861 memcpy(result, random_session_key, 16);
866 = for Extended Session Security =
867 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
868 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
869 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
871 = if Extended Session Security is NOT negotiated =
872 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
873 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
874 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
875 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
877 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
879 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
880 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
882 /** MAC(Handle, SigningKey, SeqNum, Message) */
883 static gchar *
884 MAC (guint32 flags,
885 const char *buf,
886 int buf_len,
887 unsigned char *sign_key,
888 unsigned long sign_key_len,
889 unsigned char *seal_key,
890 unsigned long seal_key_len,
891 guint32 random_pad,
892 guint32 sequence)
894 guchar result [16];
895 guint32 *res_ptr;
896 gchar signature [33];
897 int i, j;
899 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
901 Define MAC(Handle, SigningKey, SeqNum, Message) as
902 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
903 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
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
909 /* If a key exchange key is negotiated
910 Define MAC(Handle, SigningKey, SeqNum, Message) as
911 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
912 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
913 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
914 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
915 Set SeqNum to SeqNum + 1
916 EndDefine
919 unsigned char seal_key_ [16];
920 guchar hmac[16];
921 guchar tmp[4 + buf_len];
923 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
924 RC4Init(Handle, SealingKey')
926 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
927 unsigned char tmp2 [16+4];
929 memcpy(tmp2, seal_key, seal_key_len);
930 *((guint32 *)(tmp2+16)) = GUINT32_TO_LE(sequence);
931 MD5 (tmp2, 16+4, seal_key_);
932 } else {
933 memcpy(seal_key_, seal_key, seal_key_len);
936 purple_debug_info("sipe", "NTLM MAC(): Extented Session Security\n");
938 res_ptr = (guint32 *)result;
939 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
940 res_ptr[3] = GUINT32_TO_LE(sequence);
942 res_ptr = (guint32 *)tmp;
943 res_ptr[0] = GUINT32_TO_LE(sequence);
944 memcpy(tmp+4, buf, buf_len);
946 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
948 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
949 purple_debug_info("sipe", "NTLM MAC(): Key Exchange\n");
950 RC4K(seal_key_, seal_key_len, hmac, 8, result+4);
951 } else {
952 purple_debug_info("sipe", "NTLM MAC(): *NO* Key Exchange\n");
953 memcpy(result+4, hmac, 8);
955 } else {
956 /* The content of the first 4 bytes is irrelevant */
957 guint32 crc = CRC32(buf, strlen(buf));
958 guint32 plaintext [] = {
959 GUINT32_TO_LE(0),
960 GUINT32_TO_LE(crc),
961 GUINT32_TO_LE(sequence)
962 }; // 4, 4, 4 bytes
964 purple_debug_info("sipe", "NTLM MAC(): *NO* Extented Session Security\n");
966 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, result+4);
967 //RC4K(seal_key, 8, (const guchar *)plaintext, 12, result+4);
969 res_ptr = (guint32 *)result;
970 // Highest four bytes are the Version
971 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
973 // Replace the first four bytes of the ciphertext with the random_pad
974 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
977 for (i = 0, j = 0; i < 16; i++, j+=2) {
978 g_sprintf(&signature[j], "%02X", result[i]);
981 return g_strdup(signature);
984 /* End Core NTLM Methods */
987 * @param server_challenge must be g_free()'d after use if requested
988 * @param target_info must be g_free()'d after use if requested
990 static void
991 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
992 gboolean is_connection_based,
993 guint32 *flags,
994 guchar **server_challenge, /* 8 bytes */
995 guint64 *time_val,
996 guchar **target_info,
997 int *target_info_len)
999 guint32 our_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
1000 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
1001 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
1003 /* server challenge (nonce) */
1004 if (server_challenge) {
1005 *server_challenge = g_memdup(cmsg->nonce, 8);
1008 /* flags */
1009 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", host_flags, (host_flags & our_flags) == our_flags);
1010 if (flags) {
1011 *flags = host_flags;
1014 /* target_info */
1015 if (cmsg->target_info.len && cmsg->target_info.offset) {
1016 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1017 void *av = content;
1018 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
1020 ALIGN_AV_LOOP_START
1022 /* @since Vista */
1023 case MsvAvTimestamp:
1024 if (time_val) {
1025 guint64 tmp;
1027 /* to meet sparc's alignment requirement */
1028 memcpy(&tmp, av_value, sizeof(tmp));
1029 *time_val = GUINT64_FROM_LE(tmp);
1031 break;
1033 ALIGN_AV_LOOP_END;
1035 if (target_info_len) {
1036 *target_info_len = len;
1038 if (target_info) {
1039 *target_info = g_memdup(content, len);
1044 static void
1045 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
1046 guchar **server_sign_key,
1047 guchar **client_seal_key,
1048 guchar **server_seal_key,
1049 const gchar *user,
1050 const gchar *password,
1051 const gchar *hostname,
1052 const gchar *domain,
1053 const guint8 *server_challenge, /* nonce */
1054 const guint64 time_val,
1055 const guint8 *target_info,
1056 int target_info_len,
1057 gboolean is_connection_based,
1058 SipSecBuffer *out_buff,
1059 guint32 *flags)
1061 guint32 neg_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
1062 int ntlmssp_nt_resp_len =
1063 #ifdef _SIPE_COMPILING_TESTS
1064 use_ntlm_v2 ?
1065 #endif
1066 (16 + (32+target_info_len))
1067 #ifdef _SIPE_COMPILING_TESTS
1068 : NTLMSSP_LM_RESP_LEN
1069 #endif
1071 gsize msglen = sizeof(struct authenticate_message)
1072 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1073 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1074 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1075 struct authenticate_message *tmsg = g_malloc0(msglen);
1076 char *tmp;
1077 guint32 offset;
1078 guint16 len;
1079 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1080 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1081 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1082 unsigned char nt_challenge_response [ntlmssp_nt_resp_len]; /* variable or 24 */
1083 unsigned char session_base_key [16];
1084 unsigned char key_exchange_key [16];
1085 unsigned char exported_session_key[16];
1086 unsigned char encrypted_random_session_key [16];
1087 unsigned char key [16];
1088 unsigned char client_challenge [8];
1089 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1091 NONCE (client_challenge, 8);
1093 #ifdef _SIPE_COMPILING_TESTS
1094 memcpy(client_challenge, test_client_challenge, 8);
1095 time_vl = test_time_val ? test_time_val : time_vl;
1097 if (use_ntlm_v2) {
1099 #endif
1100 NTOWFv2 (password, user, domain, response_key_nt);
1101 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1102 #ifdef _SIPE_COMPILING_TESTS
1103 } else {
1104 NTOWFv1 (password, user, domain, response_key_nt);
1105 LMOWFv1 (password, user, domain, response_key_lm);
1107 #endif
1109 compute_response(neg_flags,
1110 response_key_nt,
1111 response_key_lm,
1112 server_challenge,
1113 client_challenge,
1114 time_vl,
1115 target_info,
1116 target_info_len,
1117 lm_challenge_response, /* out */
1118 nt_challenge_response, /* out */
1119 session_base_key); /* out */
1121 /* same as session_base_key for
1122 * - NTLNv1 w/o Ext.Sess.Sec and
1123 * - NTLMv2
1125 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1127 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1128 NONCE (exported_session_key, 16); // random master key
1129 #ifdef _SIPE_COMPILING_TESTS
1130 memcpy(exported_session_key, test_random_session_key, 16);
1131 #endif
1132 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1133 } else {
1134 memcpy(exported_session_key, key_exchange_key, 16);
1137 /* p.46
1138 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1139 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1141 SIGNKEY(exported_session_key, TRUE, key);
1142 *client_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1143 SIGNKEY(exported_session_key, FALSE, key);
1144 *server_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1145 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1146 *client_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1147 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1148 *server_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1150 /* @since Vista
1151 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1152 the client SHOULD provide a MIC:
1153 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1154 - then in the Value field, set bit 0x2 to 1.
1155 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1156 and the Value field bit 0x2 to 1.
1157 - Populate the MIC field with the MIC.
1160 /* Connection-oriented:
1161 Set MIC to HMAC_MD5(ExportedSessionKey,
1162 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1163 Connectionless:
1164 Set MIC to HMAC_MD5(ExportedSessionKey,
1165 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1168 /* on the server-side:
1169 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1170 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1171 Set MIC to HMAC_MD5(ExportedSessionKey,
1172 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1173 Else
1174 Set ExportedSessionKey to KeyExchangeKey
1175 Set MIC to HMAC_MD5(KeyExchangeKey,
1176 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1177 =====
1178 @since Vista
1179 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1180 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1181 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1182 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1183 an AV_PAIR structure whose two fields:
1184 - AvId == MsvAvFlags
1185 - Value bit 0x2 == 1
1186 @supported NT, 2000, XP
1187 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1188 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1189 the server time, then the server SHOULD return a failure.
1191 Connectionless:
1192 Set MIC to HMAC_MD5(ResponseKeyNT,
1193 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1196 /* authenticate message initialization */
1197 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1198 tmsg->type = GUINT32_TO_LE(3);
1200 /* Set Negotiate Flags */
1201 tmsg->flags = GUINT32_TO_LE(neg_flags);
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); \
1210 tmp += len; \
1211 offset += 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) \
1216 len = (srclen); \
1217 memcpy(tmp, (src), len); \
1218 _FILL_SMB_HEADER(header)
1220 /* Domain */
1221 _APPEND_STRING(domain, domain);
1223 /* User */
1224 _APPEND_STRING(user, user);
1226 /* Host */
1227 _APPEND_STRING(host, hostname);
1229 /* LM */
1230 /* @since Windows 7
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);
1237 /* NT */
1238 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1240 /* Session Key */
1241 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1243 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1245 else
1247 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1248 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1251 #ifdef _SIPE_COMPILING_TESTS
1252 tmsg->ver.product_major_version = test_version.product_major_version;
1253 tmsg->ver.product_minor_version = test_version.product_minor_version;
1254 tmsg->ver.product_build = test_version.product_build;
1255 memset(tmsg->ver.zero2, 0, 3);
1256 tmsg->ver.ntlm_revision_current = test_version.ntlm_revision_current;
1257 #endif
1259 *flags = neg_flags;
1261 tmp = purple_base64_encode(exported_session_key, 16);
1262 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE session key: %s\n", tmp);
1263 g_free(tmp);
1265 out_buff->value = tmsg;
1266 out_buff->length = msglen;
1270 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1272 static void
1273 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1275 guint32 offset;
1276 guint16 len;
1277 int msglen = sizeof(struct negotiate_message);
1278 struct negotiate_message *tmsg = g_malloc0(msglen);
1280 /* negotiate message initialization */
1281 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1282 tmsg->type = GUINT32_TO_LE(1);
1284 /* Set Negotiate Flags */
1285 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1287 /* Domain */
1288 offset = sizeof(struct negotiate_message);
1289 tmsg->domain.offset = GUINT32_TO_LE(offset);
1290 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1292 /* Host */
1293 offset += len;
1294 tmsg->host.offset = GUINT32_TO_LE(offset);
1295 tmsg->host.len = tmsg->host.maxlen = len = 0;
1297 /* Version */
1298 //tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1299 //tmsg->ver.product_minor_version = 1;
1300 //tmsg->ver.product_build = 2600;
1301 //tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1303 out_buff->value = tmsg;
1304 out_buff->length = msglen;
1307 static gchar *
1308 sip_sec_ntlm_sipe_signature_make (guint32 flags, const char *msg, guint32 random_pad, unsigned char *sign_key, unsigned char *seal_key)
1310 gchar *res = MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100);
1311 purple_debug_info("sipe", "NTLM calculated MAC: %s\n", res);
1312 return res;
1315 static gboolean
1316 sip_sec_ntlm_verify_signature (char * a, char * b)
1318 return g_ascii_strncasecmp(a, b, 16*2) == 0;
1322 /* Describe NTLM messages functions */
1324 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1325 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1327 static gchar *
1328 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1330 GString* str = g_string_new(NULL);
1332 flags = GUINT32_FROM_LE(flags);
1334 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1335 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1336 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1337 APPEND_NEG_FLAG(str, flags, r9, "r9");
1338 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1339 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1340 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1341 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1342 APPEND_NEG_FLAG(str, flags, r8, "r8");
1343 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1344 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1345 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1346 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1347 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1348 APPEND_NEG_FLAG(str, flags, r7, "r7");
1349 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1350 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1351 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1352 APPEND_NEG_FLAG(str, flags, r6, "r6");
1353 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1354 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1355 APPEND_NEG_FLAG(str, flags, r5, "r5");
1356 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1357 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1358 APPEND_NEG_FLAG(str, flags, r4, "r4");
1359 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1360 APPEND_NEG_FLAG(str, flags, r3, "r3");
1361 APPEND_NEG_FLAG(str, flags, r2, "r2");
1362 APPEND_NEG_FLAG(str, flags, r1, "r1");
1363 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1364 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1365 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1367 return g_string_free(str, FALSE);
1370 static gchar *
1371 sip_sec_ntlm_describe_version(struct version *ver) {
1372 GString* str = g_string_new(NULL);
1373 gchar *ver_desc = "";
1374 gchar *ntlm_revision_desc = "";
1376 if (ver->product_major_version == 6) {
1377 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1378 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1379 ver_desc = "Windows Server 2003";
1380 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1381 ver_desc = "Windows XP SP2";
1384 if (ver->ntlm_revision_current == 0x0F) {
1385 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1386 } else if (ver->ntlm_revision_current == 0x0A) {
1387 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1390 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1391 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1392 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1394 return g_string_free(str, FALSE);
1397 static gchar *
1398 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1399 const char* name)
1401 GString* str = g_string_new(NULL);
1403 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1404 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1405 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1407 return g_string_free(str, FALSE);
1410 static gchar *
1411 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1413 GString* str = g_string_new(NULL);
1414 char *tmp;
1416 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1417 g_free(tmp);
1419 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1420 g_free(tmp);
1422 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1423 g_free(tmp);
1425 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1426 g_string_append(str, tmp);
1427 g_free(tmp);
1429 if (cmsg->domain.len && cmsg->domain.offset) {
1430 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1431 g_string_append_printf(str, "\tdomain: %s\n", domain);
1432 g_free(domain);
1435 if (cmsg->host.len && cmsg->host.offset) {
1436 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1437 g_string_append_printf(str, "\thost: %s\n", host);
1438 g_free(host);
1441 return g_string_free(str, FALSE);
1444 static void
1445 describe_av_pairs(GString* str, const void *av)
1447 #define AV_DESC(av_name) \
1449 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1450 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1451 g_free(tmp); \
1454 ALIGN_AV_LOOP_START
1456 case MsvAvNbComputerName:
1457 AV_DESC("MsvAvNbComputerName");
1458 break;
1459 case MsvAvNbDomainName:
1460 AV_DESC("MsvAvNbDomainName");
1461 break;
1462 case MsvAvDnsComputerName:
1463 AV_DESC("MsvAvDnsComputerName");
1464 break;
1465 case MsvAvDnsDomainName:
1466 AV_DESC("MsvAvDnsDomainName");
1467 break;
1468 case MsvAvDnsTreeName:
1469 AV_DESC("MsvAvDnsTreeName");
1470 break;
1471 case MsvAvFlags:
1473 guint32 flags;
1475 /* to meet sparc's alignment requirement */
1476 memcpy(&flags, av_value, sizeof(guint32));
1477 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1479 break;
1480 case MsvAvTimestamp:
1482 SipSecBuffer buff;
1483 char *tmp;
1484 guint64 time_val;
1485 time_t time_t_val;
1487 /* to meet sparc's alignment requirement */
1488 memcpy(&time_val, av_value, sizeof(time_val));
1489 time_t_val = TIME_VAL_TO_T(time_val);
1491 buff.length = 8;
1492 buff.value = av_value;
1493 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = bytes_to_hex_str(&buff)),
1494 asctime(gmtime(&time_t_val)));
1495 g_free(tmp);
1497 break;
1498 case MsAvRestrictions:
1499 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1500 break;
1501 case MsvAvTargetName:
1502 AV_DESC("MsvAvTargetName");
1503 break;
1504 case MsvChannelBindings:
1505 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1506 break;
1508 ALIGN_AV_LOOP_END;
1511 static gchar *
1512 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1514 GString* str = g_string_new(NULL);
1515 char *tmp;
1516 SipSecBuffer buff;
1518 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1519 g_free(tmp);
1521 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1522 g_free(tmp);
1524 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1525 g_free(tmp);
1527 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1528 g_free(tmp);
1530 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1531 g_free(tmp);
1533 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1534 g_free(tmp);
1536 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1537 g_free(tmp);
1539 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1540 g_string_append(str, tmp);
1541 g_free(tmp);
1543 /* mic */
1544 //buff.length = 16;
1545 //buff.value = cmsg->mic;
1546 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = bytes_to_hex_str(&buff)));
1547 //g_free(tmp);
1549 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1550 buff.length = GUINT16_FROM_LE(cmsg->lm_resp.len);
1551 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1552 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = bytes_to_hex_str(&buff)));
1553 g_free(tmp);
1556 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1557 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1558 int nt_resp_len = nt_resp_len_full;
1560 buff.length = nt_resp_len_full;
1561 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1562 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = bytes_to_hex_str(&buff)));
1563 g_free(tmp);
1565 if (nt_resp_len > 24) { /* NTLMv2 */
1566 nt_resp_len = 16;
1569 buff.length = nt_resp_len;
1570 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1571 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = bytes_to_hex_str(&buff)));
1572 g_free(tmp);
1574 if (nt_resp_len_full > 24) { /* NTLMv2 */
1575 char *tmp;
1576 SipSecBuffer buff;
1577 const gchar *temp = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1578 const guint response_version = *((guchar*)temp);
1579 const guint hi_response_version = *((guchar*)(temp+1));
1580 guint64 time_val;
1581 time_t time_t_val;
1582 const gchar *client_challenge = temp + 16;
1583 const gchar *target_info = temp + 28;
1584 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1586 buff.length = target_info_len;
1587 buff.value = (gchar *)target_info;
1588 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = bytes_to_hex_str(&buff)));
1589 g_free(tmp);
1591 /* This is not int64 aligned on sparc */
1592 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1593 time_t_val = TIME_VAL_TO_T(time_val);
1595 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1596 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1598 buff.length = 8;
1599 buff.value = (gchar*)&time_val;
1600 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = bytes_to_hex_str(&buff)),
1601 asctime(gmtime(&time_t_val)));
1602 g_free(tmp);
1604 buff.length = 8;
1605 buff.value = (gchar*)client_challenge;
1606 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = bytes_to_hex_str(&buff)));
1607 g_free(tmp);
1609 describe_av_pairs(str, target_info);
1611 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1615 if (cmsg->domain.len && cmsg->domain.offset) {
1616 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1617 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1618 g_free(domain);
1621 if (cmsg->user.len && cmsg->user.offset) {
1622 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1623 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1624 g_free(user);
1627 if (cmsg->host.len && cmsg->host.offset) {
1628 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1629 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1630 g_free(host);
1633 if (cmsg->session_key.len && cmsg->session_key.offset) {
1634 buff.length = GUINT16_FROM_LE(cmsg->session_key.len);
1635 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1636 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = bytes_to_hex_str(&buff)));
1637 g_free(tmp);
1640 return g_string_free(str, FALSE);
1643 static gchar *
1644 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1646 GString* str = g_string_new(NULL);
1647 char *tmp;
1648 SipSecBuffer buff;
1650 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1651 g_free(tmp);
1653 /* nonce (server_challenge) */
1654 buff.length = 8;
1655 buff.value = cmsg->nonce;
1656 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = bytes_to_hex_str(&buff)));
1657 g_free(tmp);
1659 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1660 g_free(tmp);
1662 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1663 g_free(tmp);
1665 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1666 g_free(tmp);
1668 if (cmsg->target_name.len && cmsg->target_name.offset) {
1669 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1670 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1671 g_free(target_name);
1674 if (cmsg->target_info.len && cmsg->target_info.offset) {
1675 void *target_info = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1676 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1677 SipSecBuffer buff;
1679 buff.length = target_info_len;
1680 buff.value = (gchar *)target_info;
1681 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = bytes_to_hex_str(&buff)));
1682 g_free(tmp);
1684 describe_av_pairs(str, target_info);
1687 return g_string_free(str, FALSE);
1690 gchar *
1691 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1693 struct ntlm_message *msg;
1694 gchar *res = NULL;
1696 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1698 msg = buff.value;
1699 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1701 switch (GUINT32_FROM_LE(msg->type)) {
1702 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1703 break;
1704 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1705 break;
1706 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1707 break;
1710 return res;
1713 /* sip-sec-mech.h API implementation for NTLM */
1715 /* Security context for NTLM */
1716 typedef struct _context_ntlm {
1717 struct sip_sec_context common;
1718 char* domain;
1719 char *username;
1720 char *password;
1721 int step;
1722 guchar *client_sign_key;
1723 guchar *server_sign_key;
1724 guchar *client_seal_key;
1725 guchar *server_seal_key;
1726 guint32 flags;
1727 } *context_ntlm;
1730 static sip_uint32
1731 sip_sec_acquire_cred__ntlm(SipSecContext context,
1732 const char *domain,
1733 const char *username,
1734 const char *password)
1736 context_ntlm ctx = (context_ntlm)context;
1738 /* NTLM requires a domain, username & password */
1739 if (!domain || !username || !password)
1740 return SIP_SEC_E_INTERNAL_ERROR;
1742 ctx->domain = g_strdup(domain);
1743 ctx->username = g_strdup(username);
1744 ctx->password = g_strdup(password);
1746 return SIP_SEC_E_OK;
1749 static sip_uint32
1750 sip_sec_init_sec_context__ntlm(SipSecContext context,
1751 SipSecBuffer in_buff,
1752 SipSecBuffer *out_buff,
1753 SIPE_UNUSED_PARAMETER const char *service_name)
1755 context_ntlm ctx = (context_ntlm) context;
1757 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1759 ctx->step++;
1760 if (ctx->step == 1) {
1761 if (!context->is_connection_based) {
1762 out_buff->length = 0;
1763 out_buff->value = NULL;
1764 } else {
1765 sip_sec_ntlm_gen_negotiate(out_buff);
1767 return SIP_SEC_I_CONTINUE_NEEDED;
1769 } else {
1770 guchar *client_sign_key;
1771 guchar *server_sign_key;
1772 guchar *client_seal_key;
1773 guchar *server_seal_key;
1774 guchar *server_challenge = NULL;
1775 guint64 time_val = 0;
1776 guchar *target_info = NULL;
1777 int target_info_len = 0;
1778 guint32 flags;
1779 gchar *tmp;
1781 if (!in_buff.value || !in_buff.length) {
1782 return SIP_SEC_E_INTERNAL_ERROR;
1785 sip_sec_ntlm_parse_challenge(in_buff,
1786 context->is_connection_based,
1787 &flags,
1788 &server_challenge, /* 8 bytes */
1789 &time_val,
1790 &target_info,
1791 &target_info_len);
1793 sip_sec_ntlm_gen_authenticate(&client_sign_key,
1794 &server_sign_key,
1795 &client_seal_key,
1796 &server_seal_key,
1797 ctx->username,
1798 ctx->password,
1799 (tmp = g_ascii_strup(sipe_get_host_name(), -1)),
1800 ctx->domain,
1801 server_challenge,
1802 time_val,
1803 target_info,
1804 target_info_len,
1805 context->is_connection_based,
1806 out_buff,
1807 &flags);
1808 g_free(server_challenge);
1809 g_free(target_info);
1810 g_free(tmp);
1812 g_free(ctx->client_sign_key);
1813 ctx->client_sign_key = client_sign_key;
1815 g_free(ctx->server_sign_key);
1816 ctx->server_sign_key = server_sign_key;
1818 g_free(ctx->client_seal_key);
1819 ctx->client_seal_key = client_seal_key;
1821 g_free(ctx->server_seal_key);
1822 ctx->server_seal_key = server_seal_key;
1824 ctx->flags = flags;
1825 return SIP_SEC_E_OK;
1830 * @param message a NULL terminated string to sign
1833 static sip_uint32
1834 sip_sec_make_signature__ntlm(SipSecContext context,
1835 const char *message,
1836 SipSecBuffer *signature)
1838 /* FIXME? We always use a random_pad of 0 */
1839 gchar *signature_hex = sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1840 message,
1842 ((context_ntlm) context)->client_sign_key,
1843 ((context_ntlm) context)->client_seal_key);
1845 hex_str_to_bytes(signature_hex, signature);
1846 g_free(signature_hex);
1848 return SIP_SEC_E_OK;
1852 * @param message a NULL terminated string to check signature of
1853 * @return SIP_SEC_E_OK on success
1855 static sip_uint32
1856 sip_sec_verify_signature__ntlm(SipSecContext context,
1857 const char *message,
1858 SipSecBuffer signature)
1860 guint32 random_pad = GUINT32_FROM_LE(((guint32 *) signature.value)[1]);
1861 char *signature_hex = bytes_to_hex_str(&signature);
1862 gchar *signature_calc = sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1863 message,
1864 random_pad,
1865 ((context_ntlm) context)->server_sign_key,
1866 ((context_ntlm) context)->server_seal_key);
1867 sip_uint32 res;
1869 if (sip_sec_ntlm_verify_signature(signature_calc, signature_hex)) {
1870 res = SIP_SEC_E_OK;
1871 } else {
1872 res = SIP_SEC_E_INTERNAL_ERROR;
1874 g_free(signature_calc);
1875 g_free(signature_hex);
1876 return(res);
1879 static void
1880 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1882 context_ntlm ctx = (context_ntlm) context;
1884 g_free(ctx->domain);
1885 g_free(ctx->username);
1886 g_free(ctx->password);
1887 g_free(ctx->client_sign_key);
1888 g_free(ctx->server_sign_key);
1889 g_free(ctx->client_seal_key);
1890 g_free(ctx->server_seal_key);
1891 g_free(ctx);
1894 SipSecContext
1895 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1897 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1898 if (!context) return(NULL);
1900 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1901 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1902 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1903 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1904 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1906 return((SipSecContext) context);
1911 Local Variables:
1912 mode: c
1913 c-file-style: "bsd"
1914 indent-tabs-mode: t
1915 tab-width: 8
1916 End: