update files in preparation for next release
[siplcs.git] / src / core / sip-sec-ntlm.c
blob00745b789e6329d93e7bd943dcd13e84a23f593b
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2010-12 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2009, 2010 pier11 <pier11@operamail.com>
8 * Copyright (C) 2008 Novell, Inc.
9 * Modify 2007, Anibal Avelar <avelar@gmail.com>
10 * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
12 * Implemented with reference to the follow documentation:
13 * - http://davenport.sourceforge.net/ntlm.html
14 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
15 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 * Byte order policy:
35 * - NTLM messages (byte streams) should be in LE (Little-Endian) byte order.
36 * - internal int16, int32, int64 should contain proper values.
37 * For example: 01 00 00 00 LE should be translated to (int32)1
38 * - When reading/writing from/to NTLM message appropriate conversion should
39 * be taken to properly present integer values. glib's "Byte Order Macros"
40 * should be used for that, for example GUINT32_FROM_LE
42 * NOTE: The Byte Order Macros can have side effects!
43 * Do *NOT* make any calculations inside the macros!
45 * - All calculations should be made in dedicated local variables (system-endian),
46 * not in NTLM (LE) structures.
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
53 #include <stdlib.h>
54 #include <string.h>
55 #include <time.h>
57 #include <glib.h>
59 #ifdef HAVE_LANGINFO_CODESET
60 #include <langinfo.h>
61 #endif /* HAVE_LANGINFO_CODESET */
63 #include "sipe-common.h"
64 #include "sip-sec.h"
65 #include "sip-sec-mech.h"
66 #include "sip-sec-ntlm.h"
67 #include "sipe-backend.h"
68 #include "sipe-crypt.h"
69 #include "sipe-digest.h"
70 #include "sipe-utils.h"
72 #include "md4.h"
74 /* [MS-NLMP] */
75 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
76 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
77 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
78 #define r9 0x00000008 /* r9 */
79 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
80 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
81 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
82 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
83 #define r8 0x00000100 /* r8 */
84 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
85 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
86 #define anonymous 0x00000800 /* J */
87 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
88 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
89 #define r7 0x00004000 /* r7 */
90 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
91 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
92 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
93 #define r6 0x00040000 /* r6 */
94 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
95 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
96 #define r5 0x00200000 /* r5 */
97 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
98 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
99 #define r4 0x01000000 /* r4 */
100 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
101 #define r3 0x04000000 /* r3 */
102 #define r2 0x08000000 /* r2 */
103 #define r1 0x10000000 /* r1 */
104 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
105 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
106 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
108 /* AvId */
109 #define MsvAvEOL 0
110 #define MsvAvNbComputerName 1
111 #define MsvAvNbDomainName 2
112 #define MsvAvDnsComputerName 3
113 #define MsvAvDnsDomainName 4
114 /** @since Windows XP */
115 #define MsvAvDnsTreeName 5
116 /** @since Windows XP */
117 #define MsvAvFlags 6
118 /** @since Windows Vista */
119 #define MsvAvTimestamp 7
120 /** @since Windows Vista */
121 #define MsAvRestrictions 8
122 /** @since Windows 7 */
123 #define MsvAvTargetName 9
124 /** @since Windows 7 */
125 #define MsvChannelBindings 10
127 /* time_t <-> (guint64) time_val conversion */
128 #define TIME_VAL_FACTOR 10000000
129 #define TIME_VAL_OFFSET 116444736000000000LL
130 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
131 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
133 /* 8 bytes */
134 /* LE (Little Endian) byte order */
135 struct version {
136 guint8 product_major_version;
137 guint8 product_minor_version;
138 guint16 product_build;
139 guint8 zero2[3];
140 guint8 ntlm_revision_current;
144 * NTLMv1 is no longer used except in tests. R.I.P.
146 * It remains in this file only for documentary purposes
148 #ifdef _SIPE_COMPILING_TESTS
149 static gboolean use_ntlm_v2 = FALSE;
151 guint64 test_time_val = 0; /* actual time in implementation */
152 guchar test_client_challenge [8]; /* random in implementation */
153 guchar test_random_session_key[16]; /* random in implementation */
154 struct version test_version; /* hard-coded in implementation */
155 #endif
157 /* Minimum set of common features we need to work. */
158 /* we operate in NTLMv2 mode */
159 #define NEGOTIATE_FLAGS_COMMON_MIN \
160 ( NTLMSSP_NEGOTIATE_UNICODE | \
161 NTLMSSP_NEGOTIATE_NTLM | \
162 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
163 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
164 NTLMSSP_NEGOTIATE_TARGET_INFO \
167 /* Negotiate flags for connection-based mode. Nice to have but optional. */
168 #define NEGOTIATE_FLAGS_CONN \
169 ( NEGOTIATE_FLAGS_COMMON_MIN | \
170 NTLMSSP_NEGOTIATE_VERSION | \
171 NTLMSSP_NEGOTIATE_128 | \
172 NTLMSSP_NEGOTIATE_56 | \
173 NTLMSSP_REQUEST_TARGET \
176 /* Extra negotiate flags required in connectionless NTLM */
177 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
178 ( NTLMSSP_NEGOTIATE_SIGN | \
179 NTLMSSP_NEGOTIATE_DATAGRAM | \
180 NTLMSSP_NEGOTIATE_IDENTIFY | \
181 NTLMSSP_NEGOTIATE_KEY_EXCH \
184 /* Negotiate flags required in connectionless NTLM */
185 #define NEGOTIATE_FLAGS_CONNLESS \
186 ( NEGOTIATE_FLAGS_CONN | \
187 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
190 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
191 #define NTLMSSP_LM_RESP_LEN 24
192 #define NTLMSSP_SESSION_KEY_LEN 16
194 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
196 /* 4 bytes */
197 /* LE (Little Endian) byte order */
198 struct av_pair {
199 guint16 av_id;
200 guint16 av_len;
201 /* value */
204 /* to meet sparc's alignment requirement */
205 #define ALIGN_AV \
206 memcpy(&av_aligned, av, sizeof(av_aligned)); \
207 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
208 av_len = GUINT16_FROM_LE(av_aligned.av_len)
209 #define ALIGN_AV_LOOP_START \
210 struct av_pair av_aligned; \
211 guint16 av_id; \
212 guint16 av_len; \
213 ALIGN_AV; \
214 while (av_id != MsvAvEOL) { \
215 gchar *av_value = ((gchar *)av) + \
216 sizeof(struct av_pair); \
217 switch (av_id)
218 #define ALIGN_AV_LOOP_END \
219 av = av_value + av_len; \
220 ALIGN_AV; \
223 /* 8 bytes */
224 /* LE (Little Endian) byte order */
225 struct smb_header {
226 guint16 len;
227 guint16 maxlen;
228 guint32 offset;
231 /* LE (Little Endian) byte order */
232 struct ntlm_message {
233 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
234 guint32 type; /* 0x00000003 */
237 /* LE (Little Endian) byte order */
238 struct negotiate_message {
239 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
240 guint32 type; /* 0x00000001 */
241 guint32 flags; /* 0xb203 */
242 struct smb_header domain;
243 struct smb_header host;
244 struct version ver;
245 /* payload
246 * - DomainName (always ASCII)
247 * - WorkstationName (always ASCII)
251 /* LE (Little Endian) byte order */
252 struct challenge_message {
253 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
254 guint32 type; /* 0x00000002 */
255 struct smb_header target_name;
256 guint32 flags; /* 0x8201 */
257 guint8 nonce[8];
258 guint8 zero1[8];
259 struct smb_header target_info;
260 struct version ver;
261 /* payload
262 * - TargetName (negotiated encoding)
263 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
267 /* LE (Little Endian) byte order */
268 struct authenticate_message {
269 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
270 guint32 type; /* 0x00000003 */
271 /** LmChallengeResponseFields */
272 struct smb_header lm_resp;
273 /** NtChallengeResponseFields */
274 struct smb_header nt_resp;
275 /** DomainNameFields */
276 struct smb_header domain;
277 /** UserNameFields */
278 struct smb_header user;
279 /** WorkstationFields */
280 struct smb_header host;
281 /** EncryptedRandomSessionKeyFields */
282 struct smb_header session_key;
283 guint32 flags;
284 struct version ver;
285 //guint8 mic[16];
286 /* payload
287 * - LmChallengeResponse
288 * - NtChallengeResponse
289 * - DomainName (negotiated encoding)
290 * - UserName (negotiated encoding)
291 * - Workstation (negotiated encoding)
292 * - EncryptedRandomSessionKey
296 #ifndef HAVE_LANGINFO_CODESET
297 #ifdef __sun__
298 static char SIPE_DEFAULT_CODESET[] = "US-ASCII";
299 #else
300 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
301 #endif
302 #endif
304 /* Private Methods */
306 /* Utility Functions */
307 static GIConv convert_from_utf16le = (GIConv)-1;
308 static GIConv convert_to_utf16le = (GIConv)-1;
310 static gsize
311 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
313 gsize inbytes = strlen(source);
314 gsize outbytes = remlen;
315 if (remlen)
316 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
317 return(remlen - outbytes);
320 /* UTF-16LE to native encoding
321 * Must be g_free'd after use */
322 static gchar *
323 unicode_strconvcopy_back(const gchar *source, gsize len)
325 gsize outbytes = 2 * len;
326 gchar *dest = g_new0(gchar, outbytes + 1);
327 gchar *outbuf = dest;
328 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
329 return dest;
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;
373 crc = crc32(crc, (guint8 *) msg, len);
374 return crc;
377 /* Cyphers */
379 #ifdef _SIPE_COMPILING_TESTS
380 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
382 key[0] = key_56[0];
383 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
384 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
385 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
386 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
387 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
388 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
389 key[7] = (key_56[6] << 1) & 0xFF;
392 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
393 static void
394 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
396 unsigned char key[8];
397 setup_des_key(k, key);
398 sipe_crypt_des(key, d, 8, results);
401 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
402 static void
403 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
405 unsigned char keys[21];
407 /* Copy the first 16 bytes */
408 memcpy(keys, k, 16);
410 /* Zero out the last 5 bytes of the key */
411 memset(keys + 16, 0, 5);
413 DES(keys, d, results);
414 DES(keys + 7, d, results + 8);
415 DES(keys + 14, d, results + 16);
417 #endif
419 #define RC4K(key, key_len, plain, plain_len, encrypted) \
420 sipe_crypt_rc4((key), (key_len), (plain), (plain_len), (encrypted))
422 /* out 16 bytes */
423 static void MD4(const guchar *data, gsize length, guchar *digest)
426 * From Firefox's complementing implementation for NSS.
427 * NSS doesn't include MD4, because it is considered weak.
429 md4sum(data, length, digest);
432 /* out 16 bytes */
433 #define MD5(d, len, result) sipe_digest_md5((d), (len), (result))
435 /* out 16 bytes */
437 static void
438 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
440 int i;
441 unsigned char ibuff[64 + data_len];
442 unsigned char obuff[64 + 16];
444 if (key_len > 64)
445 key_len = 64;
447 for (i = 0; i < key_len; i++) {
448 ibuff[i] = key[i] ^ 0x36;
449 obuff[i] = key[i] ^ 0x5c;
451 for (i = key_len; i < 64; i++) {
452 ibuff[i] = 0x36;
453 obuff[i] = 0x5c;
456 memcpy(ibuff+64, data, data_len);
458 MD5 (ibuff, 64 + data_len, obuff+64);
459 MD5 (obuff, 64 + 16, result);
461 #define HMAC_MD5 HMACT64
464 /* out 16 bytes */
465 #define HMAC_MD5(key, key_len, data, data_len, result) \
466 sipe_digest_hmac_md5((key), (key_len), (data), (data_len), (result))
468 /* NTLM Core Methods */
470 static void
471 NONCE(unsigned char *buffer, int num)
473 int i;
474 for (i = 0; i < num; i++) {
475 buffer[i] = (rand() & 0xff);
479 #ifdef _SIPE_COMPILING_TESTS
480 static void
481 Z(unsigned char *buffer, int num)
483 memset(buffer, 0, num);
486 static void
487 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
489 /* "KGS!@#$%" */
490 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
491 unsigned char uppercase_password[14];
492 int i;
494 int len = strlen(password);
495 if (len > 14) {
496 len = 14;
499 // Uppercase password
500 for (i = 0; i < len; i++) {
501 uppercase_password[i] = g_ascii_toupper(password[i]);
504 // Zero the rest
505 for (; i < 14; i++) {
506 uppercase_password[i] = 0;
509 DES (uppercase_password, magic, result);
510 DES (uppercase_password + 7, magic, result + 8);
512 #endif
515 Define NTOWFv1(Passwd, User, UserDom) as
516 MD4(UNICODE(Passwd))
517 EndDefine
519 /* out 16 bytes */
520 static void
521 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
523 int len_u = 2 * strlen(password); // utf16 should not be more
524 unsigned char *unicode_password = g_malloc(len_u);
526 /* well, if allocation failed the rest will crash & burn soon anyway... */
527 if (unicode_password) {
528 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
529 MD4 (unicode_password, len_u, result);
530 g_free(unicode_password);
535 Define NTOWFv2(Passwd, User, UserDom) as
536 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
537 EndDefine
539 /* out 16 bytes */
540 static void
541 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
543 unsigned char response_key_nt_v1 [16];
544 int len_user = user ? strlen(user) : 0;
545 int len_domain = domain ? strlen(domain) : 0;
546 int len_user_u = 2 * len_user; // utf16 should not be more
547 int len_domain_u = 2 * len_domain; // utf16 should not be more
548 unsigned char *user_upper = g_malloc(len_user + 1);
549 unsigned char *buff = g_malloc((len_user + len_domain)*2);
550 int i;
552 /* Uppercase user */
553 for (i = 0; i < len_user; i++) {
554 user_upper[i] = g_ascii_toupper(user[i]);
556 user_upper[len_user] = 0;
558 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
559 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
561 NTOWFv1(password, user, domain, response_key_nt_v1);
563 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
565 g_free(buff);
566 g_free(user_upper);
569 static void
570 compute_response(const guint32 neg_flags,
571 const unsigned char *response_key_nt,
572 const unsigned char *response_key_lm,
573 const guint8 *server_challenge,
574 const guint8 *client_challenge,
575 const guint64 time_val,
576 const guint8 *target_info,
577 int target_info_len,
578 unsigned char *lm_challenge_response,
579 unsigned char *nt_challenge_response,
580 unsigned char *session_base_key)
582 #ifdef _SIPE_COMPILING_TESTS
583 if (use_ntlm_v2)
585 #endif
587 Responserversion - The 1-byte response version. Currently set to 1.
588 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
589 Time - The 8-byte little-endian time in GMT.
590 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
591 ClientChallenge - The 8-byte challenge message generated by the client.
592 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
594 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
595 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
596 Time, //8bytes - 8
597 ClientChallenge, //8bytes - 16
598 Z(4), //4bytes - 24
599 ServerName, //variable - 28
600 Z(4)) //4bytes - 28+target_info_len
601 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
602 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
603 Set LmChallengeResponse to ConcatenationOf(
604 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
605 ClientChallenge )
606 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
607 EndDefine
609 guint8 tmp [16];
610 guint8 nt_proof_str [16];
612 /* client_challenge (8) & temp (temp_len) buff */
613 unsigned int temp_len = 8+8+8+4+target_info_len+4;
614 guint64 *temp2 = g_malloc0(8 + temp_len);
615 ((guint8 *) temp2)[8+0] = 1;
616 ((guint8 *) temp2)[8+1] = 1;
617 temp2[2] = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
618 memcpy(((guint8 *) temp2)+8+16, client_challenge, 8);
619 memcpy(((guint8 *) temp2)+8+28, target_info, target_info_len);
621 /* NTProofStr */
622 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
623 memcpy(temp2, server_challenge, 8);
624 HMAC_MD5(response_key_nt, 16, (guint8*)temp2, 8+temp_len, nt_proof_str);
626 /* NtChallengeResponse */
627 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
628 memcpy(nt_challenge_response, nt_proof_str, 16);
629 memcpy(nt_challenge_response+16, temp2+1, temp_len);
630 g_free(temp2);
632 /* SessionBaseKey */
633 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
634 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
636 /* lm_challenge_response */
637 memcpy(tmp, server_challenge, 8);
638 memcpy(tmp+8, client_challenge, 8);
639 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
640 memcpy(lm_challenge_response+16, client_challenge, 8);
642 #ifndef _SIPE_COMPILING_TESTS
643 /* Not used in NTLMv2 */
644 (void)neg_flags;
645 #else
647 else
649 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
650 // @TODO do not even reference nt_challenge_response
651 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
652 DESL (response_key_lm, server_challenge, lm_challenge_response);
653 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
654 unsigned char prehash [16];
655 unsigned char hash [16];
657 /* nt_challenge_response */
658 memcpy(prehash, server_challenge, 8);
659 memcpy(prehash + 8, client_challenge, 8);
660 MD5 (prehash, 16, hash);
661 DESL (response_key_nt, hash, nt_challenge_response);
663 /* lm_challenge_response */
664 memcpy(lm_challenge_response, client_challenge, 8);
665 Z (lm_challenge_response+8, 16);
666 } else {
667 DESL (response_key_nt, server_challenge, nt_challenge_response);
668 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
669 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
670 } else {
671 DESL (response_key_lm, server_challenge, lm_challenge_response);
675 /* Session Key */
676 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
678 #endif
681 static void
682 KXKEY ( guint32 flags,
683 const unsigned char * session_base_key,
684 const unsigned char * lm_challenge_resonse,
685 const guint8 * server_challenge, /* 8-bytes, nonce */
686 unsigned char * key_exchange_key)
688 #ifdef _SIPE_COMPILING_TESTS
689 if (use_ntlm_v2)
691 #else
692 /* Not used in NTLMv2 */
693 (void)flags;
694 (void)lm_challenge_resonse;
695 (void)server_challenge;
696 #endif
697 memcpy(key_exchange_key, session_base_key, 16);
698 #ifdef _SIPE_COMPILING_TESTS
700 else
702 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
703 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
704 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
705 EndDefine
707 guint8 tmp[16];
708 memcpy(tmp, server_challenge, 8);
709 memcpy(tmp+8, lm_challenge_resonse, 8);
710 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
711 } else {
712 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
713 memcpy(key_exchange_key, session_base_key, 16);
716 #endif
720 If (Mode equals "Client")
721 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
722 "session key to client-to-server signing key magic constant"))
723 Else
724 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
725 "session key to server-to-client signing key magic constant"))
726 Endif
728 static void
729 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
731 char * magic = client
732 ? "session key to client-to-server signing key magic constant"
733 : "session key to server-to-client signing key magic constant";
735 int len = strlen(magic) + 1;
736 unsigned char *md5_input = g_malloc(16 + len);
737 memcpy(md5_input, random_session_key, 16);
738 memcpy(md5_input + 16, magic, len);
740 MD5 (md5_input, len + 16, result);
741 g_free(md5_input);
745 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
746 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
747 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
748 Set SealKey to RandomSessionKey
749 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
750 Set SealKey to RandomSessionKey[0..6]
751 Else
752 Set SealKey to RandomSessionKey[0..4]
753 Endif
755 If (Mode equals "Client")
756 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
757 Else
758 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
759 Endif
761 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
762 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
763 Else
764 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
765 Endif
766 EndDefine
768 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
769 static void
770 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
772 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
774 char * magic = client
775 ? "session key to client-to-server sealing key magic constant"
776 : "session key to server-to-client sealing key magic constant";
778 int len = strlen(magic) + 1;
779 unsigned char *md5_input = g_malloc(16 + len);
780 int key_len;
782 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
783 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
784 key_len = 16;
785 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
786 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
787 key_len = 7;
788 } else {
789 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
790 key_len = 5;
793 memcpy(md5_input, random_session_key, key_len);
794 memcpy(md5_input + key_len, magic, len);
796 MD5 (md5_input, key_len + len, result);
797 g_free(md5_input);
799 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
801 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
802 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
803 memcpy(result, random_session_key, 7);
804 result[7] = 0xA0;
805 } else {
806 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
807 memcpy(result, random_session_key, 5);
808 result[5] = 0xE5;
809 result[6] = 0x38;
810 result[7] = 0xB0;
813 else
815 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
816 memcpy(result, random_session_key, 16);
821 = for Extended Session Security =
822 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
823 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
824 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
826 = if Extended Session Security is NOT negotiated =
827 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
828 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
829 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
830 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
832 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
834 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
835 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
837 /** MAC(Handle, SigningKey, SeqNum, Message) */
838 /* out 16 bytes */
839 static void
840 MAC (guint32 flags,
841 const char *buf,
842 unsigned int buf_len,
843 unsigned char *sign_key,
844 unsigned long sign_key_len,
845 unsigned char *seal_key,
846 unsigned long seal_key_len,
847 guint32 random_pad,
848 guint32 sequence,
849 guint32 *result)
851 guint32 *res_ptr;
853 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
855 Define MAC(Handle, SigningKey, SeqNum, Message) as
856 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
857 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
858 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
859 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
860 Set SeqNum to SeqNum + 1
861 EndDefine
863 /* If a key exchange key is negotiated
864 Define MAC(Handle, SigningKey, SeqNum, Message) as
865 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
866 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
867 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
868 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
869 Set SeqNum to SeqNum + 1
870 EndDefine
873 unsigned char seal_key_ [16];
874 guchar hmac[16];
875 guint32 *tmp = g_malloc(4 + buf_len);
877 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
878 RC4Init(Handle, SealingKey')
880 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
881 guint32 tmp2[4+1];
883 memcpy(tmp2, seal_key, seal_key_len);
884 tmp2[4] = GUINT32_TO_LE(sequence);
885 MD5 ((guchar *)tmp2, sizeof(tmp2), seal_key_);
886 } else {
887 memcpy(seal_key_, seal_key, seal_key_len);
890 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extented Session Security");
892 res_ptr = result;
893 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
894 res_ptr[3] = GUINT32_TO_LE(sequence);
896 res_ptr = tmp;
897 res_ptr[0] = GUINT32_TO_LE(sequence);
898 memcpy(tmp+1, buf, buf_len);
900 HMAC_MD5(sign_key, sign_key_len, (guchar *)tmp, 4 + buf_len, hmac);
901 g_free(tmp);
903 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
904 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
905 RC4K(seal_key_, seal_key_len, hmac, 8, (guchar *)(result+1));
906 } else {
907 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
908 memcpy(result+1, hmac, 8);
910 } else {
911 /* The content of the first 4 bytes is irrelevant */
912 guint32 crc = CRC32(buf, strlen(buf));
913 guint32 plaintext [] = {
914 GUINT32_TO_LE(0),
915 GUINT32_TO_LE(crc),
916 GUINT32_TO_LE(sequence)
917 }; // 4, 4, 4 bytes
919 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extented Session Security");
921 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, (guchar *)(result+1));
923 res_ptr = result;
924 // Highest four bytes are the Version
925 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
927 // Replace the first four bytes of the ciphertext with the random_pad
928 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
932 /* End Core NTLM Methods */
935 * @param flags (out) flags received from server
936 * @param server_challenge must be g_free()'d after use if requested
937 * @param target_info must be g_free()'d after use if requested
939 static void
940 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
941 guint32 *flags,
942 guchar **server_challenge, /* 8 bytes */
943 guint64 *time_val,
944 guchar **target_info,
945 int *target_info_len)
947 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
948 struct challenge_message *cmsg = (void *)in_buff.value;
949 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
951 /* server challenge (nonce) */
952 if (server_challenge) {
953 *server_challenge = g_memdup(cmsg->nonce, 8);
956 /* flags */
957 if (flags) {
958 *flags = host_flags;
961 /* target_info */
962 if (cmsg->target_info.len && cmsg->target_info.offset) {
963 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
964 void *av = content;
965 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
967 ALIGN_AV_LOOP_START
969 /* @since Vista */
970 case MsvAvTimestamp:
971 if (time_val) {
972 guint64 tmp;
974 /* to meet sparc's alignment requirement */
975 memcpy(&tmp, av_value, sizeof(tmp));
976 *time_val = GUINT64_FROM_LE(tmp);
978 break;
980 ALIGN_AV_LOOP_END;
982 if (target_info_len) {
983 *target_info_len = len;
985 if (target_info) {
986 *target_info = g_memdup(content, len);
992 * @param client_sign_key (out) must be g_free()'d after use
993 * @param server_sign_key (out) must be g_free()'d after use
994 * @param client_seal_key (out) must be g_free()'d after use
995 * @param server_seal_key (out) must be g_free()'d after use
996 * @param flags (in, out) negotiated flags
998 static sip_uint32
999 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
1000 guchar **server_sign_key,
1001 guchar **client_seal_key,
1002 guchar **server_seal_key,
1003 const gchar *user,
1004 const gchar *password,
1005 const gchar *hostname,
1006 const gchar *domain,
1007 const guint8 *server_challenge, /* nonce */
1008 const guint64 time_val,
1009 const guint8 *target_info,
1010 int target_info_len,
1011 gboolean is_connection_based,
1012 SipSecBuffer *out_buff,
1013 guint32 *flags)
1015 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
1016 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1017 int ntlmssp_nt_resp_len =
1018 #ifdef _SIPE_COMPILING_TESTS
1019 use_ntlm_v2 ?
1020 #endif
1021 (16 + (32+target_info_len))
1022 #ifdef _SIPE_COMPILING_TESTS
1023 : NTLMSSP_LM_RESP_LEN
1024 #endif
1026 gsize msglen = sizeof(struct authenticate_message)
1027 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1028 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1029 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1030 struct authenticate_message *tmsg;
1031 char *tmp;
1032 guint32 offset;
1033 guint16 len;
1034 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1035 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1036 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1037 unsigned char *nt_challenge_response = g_malloc(ntlmssp_nt_resp_len); /* variable or 24 */
1038 unsigned char session_base_key [16];
1039 unsigned char key_exchange_key [16];
1040 unsigned char exported_session_key[16];
1041 unsigned char encrypted_random_session_key [16];
1042 unsigned char key [16];
1043 unsigned char client_challenge [8];
1044 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1046 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1047 !(is_connection_based || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)) ||
1048 !nt_challenge_response) /* Coverity thinks ntlmssp_nt_resp_len could be 0 */
1050 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1051 g_free(nt_challenge_response);
1052 return SIP_SEC_E_INTERNAL_ERROR;
1055 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1056 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1059 tmsg = g_malloc0(msglen);
1061 NONCE (client_challenge, 8);
1063 #ifdef _SIPE_COMPILING_TESTS
1064 memcpy(client_challenge, test_client_challenge, 8);
1065 time_vl = test_time_val ? test_time_val : time_vl;
1067 if (use_ntlm_v2) {
1069 #endif
1070 NTOWFv2 (password, user, domain, response_key_nt);
1071 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1072 #ifdef _SIPE_COMPILING_TESTS
1073 } else {
1074 NTOWFv1 (password, user, domain, response_key_nt);
1075 LMOWFv1 (password, user, domain, response_key_lm);
1077 #endif
1079 compute_response(neg_flags,
1080 response_key_nt,
1081 response_key_lm,
1082 server_challenge,
1083 client_challenge,
1084 time_vl,
1085 target_info,
1086 target_info_len,
1087 lm_challenge_response, /* out */
1088 nt_challenge_response, /* out */
1089 session_base_key); /* out */
1091 /* same as session_base_key for
1092 * - NTLNv1 w/o Ext.Sess.Sec and
1093 * - NTLMv2
1095 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1097 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1098 NONCE (exported_session_key, 16); // random master key
1099 #ifdef _SIPE_COMPILING_TESTS
1100 memcpy(exported_session_key, test_random_session_key, 16);
1101 #endif
1102 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1103 } else {
1104 memcpy(exported_session_key, key_exchange_key, 16);
1107 tmp = buff_to_hex_str(exported_session_key, 16);
1108 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp);
1109 g_free(tmp);
1111 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1112 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1114 /* p.46
1115 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1116 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1118 SIGNKEY(exported_session_key, TRUE, key);
1119 *client_sign_key = g_memdup(key, 16);
1120 SIGNKEY(exported_session_key, FALSE, key);
1121 *server_sign_key = g_memdup(key, 16);
1122 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1123 *client_seal_key = g_memdup(key, 16);
1124 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1125 *server_seal_key = g_memdup(key, 16);
1128 /* @TODO: */
1129 /* @since Vista
1130 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1131 the client SHOULD provide a MIC:
1132 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1133 - then in the Value field, set bit 0x2 to 1.
1134 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1135 and the Value field bit 0x2 to 1.
1136 - Populate the MIC field with the MIC.
1139 /* Connection-oriented:
1140 Set MIC to HMAC_MD5(ExportedSessionKey,
1141 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1142 Connectionless:
1143 Set MIC to HMAC_MD5(ExportedSessionKey,
1144 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1147 /* on the server-side:
1148 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1149 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1150 Set MIC to HMAC_MD5(ExportedSessionKey,
1151 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1152 Else
1153 Set ExportedSessionKey to KeyExchangeKey
1154 Set MIC to HMAC_MD5(KeyExchangeKey,
1155 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1156 =====
1157 @since Vista
1158 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1159 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1160 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1161 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1162 an AV_PAIR structure whose two fields:
1163 - AvId == MsvAvFlags
1164 - Value bit 0x2 == 1
1165 @supported NT, 2000, XP
1166 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1167 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1168 the server time, then the server SHOULD return a failure.
1170 Connectionless:
1171 Set MIC to HMAC_MD5(ResponseKeyNT,
1172 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1175 /* authenticate message initialization */
1176 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1177 tmsg->type = GUINT32_TO_LE(3);
1179 /* Initial offset */
1180 offset = sizeof(struct authenticate_message);
1181 tmp = ((char*) tmsg) + offset;
1183 #define _FILL_SMB_HEADER(header) \
1184 tmsg->header.offset = GUINT32_TO_LE(offset); \
1185 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1186 tmp += len; \
1187 offset += len
1188 #define _APPEND_STRING(header, src) \
1189 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1190 _FILL_SMB_HEADER(header)
1191 #define _APPEND_DATA(header, src, srclen) \
1192 len = (srclen); \
1193 memcpy(tmp, (src), len); \
1194 _FILL_SMB_HEADER(header)
1196 /* Domain */
1197 _APPEND_STRING(domain, domain);
1199 /* User */
1200 _APPEND_STRING(user, user);
1202 /* Host */
1203 _APPEND_STRING(host, hostname);
1205 /* LM */
1206 /* @since Windows 7
1207 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1208 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1209 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1211 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1213 /* NT */
1214 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1216 /* Session Key */
1217 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1219 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1221 else
1223 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1224 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1227 /* Version */
1228 #ifdef _SIPE_COMPILING_TESTS
1229 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1230 #else
1231 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1232 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1233 tmsg->ver.product_minor_version = 1;
1234 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1235 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1237 #endif
1239 /* Set Negotiate Flags */
1240 tmsg->flags = GUINT32_TO_LE(neg_flags);
1241 *flags = neg_flags;
1243 out_buff->value = (guint8 *)tmsg;
1244 out_buff->length = msglen;
1246 g_free(nt_challenge_response);
1248 return SIP_SEC_E_OK;
1252 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1254 static void
1255 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1257 guint32 offset;
1258 guint16 len;
1259 int msglen = sizeof(struct negotiate_message);
1260 struct negotiate_message *tmsg = g_malloc0(msglen);
1262 /* negotiate message initialization */
1263 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1264 tmsg->type = GUINT32_TO_LE(1);
1266 /* Set Negotiate Flags */
1267 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1269 /* Domain */
1270 offset = sizeof(struct negotiate_message);
1271 tmsg->domain.offset = GUINT32_TO_LE(offset);
1272 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1274 /* Host */
1275 offset += len;
1276 tmsg->host.offset = GUINT32_TO_LE(offset);
1277 tmsg->host.len = tmsg->host.maxlen = len = 0;
1279 /* Version */
1280 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1281 tmsg->ver.product_minor_version = 1;
1282 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1283 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1285 out_buff->value = (guint8 *)tmsg;
1286 out_buff->length = msglen;
1289 static void
1290 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1291 const char *msg,
1292 guint32 random_pad,
1293 unsigned char *sign_key,
1294 unsigned char *seal_key,
1295 guint32 *result)
1297 char *res;
1299 MAC(flags, msg, strlen(msg), sign_key, 16, seal_key, 16, random_pad, 100, result);
1301 res = buff_to_hex_str((guint8 *)result, 16);
1302 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res);
1303 g_free(res);
1307 /* Describe NTLM messages functions */
1309 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1310 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1312 static gchar *
1313 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1315 GString* str = g_string_new(NULL);
1317 flags = GUINT32_FROM_LE(flags);
1319 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1320 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1321 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1322 APPEND_NEG_FLAG(str, flags, r9, "r9");
1323 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1324 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1325 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1326 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1327 APPEND_NEG_FLAG(str, flags, r8, "r8");
1328 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1329 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1330 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1331 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1332 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1333 APPEND_NEG_FLAG(str, flags, r7, "r7");
1334 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1335 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1336 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1337 APPEND_NEG_FLAG(str, flags, r6, "r6");
1338 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1339 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1340 APPEND_NEG_FLAG(str, flags, r5, "r5");
1341 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1342 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1343 APPEND_NEG_FLAG(str, flags, r4, "r4");
1344 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1345 APPEND_NEG_FLAG(str, flags, r3, "r3");
1346 APPEND_NEG_FLAG(str, flags, r2, "r2");
1347 APPEND_NEG_FLAG(str, flags, r1, "r1");
1348 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1349 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1350 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1352 return g_string_free(str, FALSE);
1355 static gchar *
1356 sip_sec_ntlm_describe_version(struct version *ver) {
1357 GString* str = g_string_new(NULL);
1358 gchar *ver_desc = "";
1359 gchar *ntlm_revision_desc = "";
1361 if (ver->product_major_version == 6) {
1362 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1363 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1364 ver_desc = "Windows Server 2003";
1365 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1366 ver_desc = "Windows XP SP2";
1369 if (ver->ntlm_revision_current == 0x0F) {
1370 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1371 } else if (ver->ntlm_revision_current == 0x0A) {
1372 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1375 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1376 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1377 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1379 return g_string_free(str, FALSE);
1382 static gchar *
1383 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1384 const char* name)
1386 GString* str = g_string_new(NULL);
1388 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1389 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1390 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1392 return g_string_free(str, FALSE);
1395 static gchar *
1396 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1398 GString* str = g_string_new(NULL);
1399 char *tmp;
1401 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1402 g_free(tmp);
1404 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1405 g_free(tmp);
1407 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1408 g_free(tmp);
1410 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1411 g_string_append(str, tmp);
1412 g_free(tmp);
1414 if (cmsg->domain.len && cmsg->domain.offset) {
1415 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1416 g_string_append_printf(str, "\tdomain: %s\n", domain);
1417 g_free(domain);
1420 if (cmsg->host.len && cmsg->host.offset) {
1421 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1422 g_string_append_printf(str, "\thost: %s\n", host);
1423 g_free(host);
1426 return g_string_free(str, FALSE);
1429 static void
1430 describe_av_pairs(GString* str, const void *av)
1432 #define AV_DESC(av_name) \
1434 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1435 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1436 g_free(tmp); \
1439 ALIGN_AV_LOOP_START
1441 case MsvAvNbComputerName:
1442 AV_DESC("MsvAvNbComputerName");
1443 break;
1444 case MsvAvNbDomainName:
1445 AV_DESC("MsvAvNbDomainName");
1446 break;
1447 case MsvAvDnsComputerName:
1448 AV_DESC("MsvAvDnsComputerName");
1449 break;
1450 case MsvAvDnsDomainName:
1451 AV_DESC("MsvAvDnsDomainName");
1452 break;
1453 case MsvAvDnsTreeName:
1454 AV_DESC("MsvAvDnsTreeName");
1455 break;
1456 case MsvAvFlags:
1458 guint32 flags;
1460 /* to meet sparc's alignment requirement */
1461 memcpy(&flags, av_value, sizeof(guint32));
1462 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1464 break;
1465 case MsvAvTimestamp:
1467 char *tmp;
1468 guint64 time_val;
1469 time_t time_t_val;
1471 /* to meet sparc's alignment requirement */
1472 memcpy(&time_val, av_value, sizeof(time_val));
1473 time_t_val = TIME_VAL_TO_T(time_val);
1475 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1476 asctime(gmtime(&time_t_val)));
1477 g_free(tmp);
1479 break;
1480 case MsAvRestrictions:
1481 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1482 break;
1483 case MsvAvTargetName:
1484 AV_DESC("MsvAvTargetName");
1485 break;
1486 case MsvChannelBindings:
1487 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1488 break;
1490 ALIGN_AV_LOOP_END;
1493 static gchar *
1494 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1496 GString* str = g_string_new(NULL);
1497 char *tmp;
1498 gsize value_len;
1499 guint8 *value;
1501 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1502 g_free(tmp);
1504 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1505 g_free(tmp);
1507 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1508 g_free(tmp);
1510 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1511 g_free(tmp);
1513 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1514 g_free(tmp);
1516 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1517 g_free(tmp);
1519 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1520 g_free(tmp);
1522 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1523 g_string_append(str, tmp);
1524 g_free(tmp);
1526 /* mic */
1527 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1528 //g_free(tmp);
1530 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1531 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1532 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1533 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1534 g_free(tmp);
1537 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1538 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1539 int nt_resp_len = nt_resp_len_full;
1541 value_len = nt_resp_len_full;
1542 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1543 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1544 g_free(tmp);
1546 if (nt_resp_len > 24) { /* NTLMv2 */
1547 nt_resp_len = 16;
1550 value_len = nt_resp_len;
1551 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1552 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1553 g_free(tmp);
1555 if (nt_resp_len_full > 24) { /* NTLMv2 */
1556 /* Work around Debian/x86_64 compiler bug */
1557 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1558 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1559 const guint8 *temp = (guint8 *)cmsg + offset;
1560 const guint response_version = temp[0];
1561 const guint hi_response_version = temp[1];
1562 const guint8 *client_challenge = temp + 16;
1563 const guint8 *target_info = temp + 28;
1564 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1565 guint64 time_val;
1566 time_t time_t_val;
1567 char *tmp;
1569 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1570 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1571 g_free(tmp);
1573 /* This is not int64 aligned on sparc */
1574 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1575 time_t_val = TIME_VAL_TO_T(time_val);
1577 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1578 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1580 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1581 asctime(gmtime(&time_t_val)));
1582 g_free(tmp);
1584 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1585 g_free(tmp);
1587 describe_av_pairs(str, target_info);
1589 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1593 if (cmsg->domain.len && cmsg->domain.offset) {
1594 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1595 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1596 g_free(domain);
1599 if (cmsg->user.len && cmsg->user.offset) {
1600 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1601 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1602 g_free(user);
1605 if (cmsg->host.len && cmsg->host.offset) {
1606 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1607 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1608 g_free(host);
1611 if (cmsg->session_key.len && cmsg->session_key.offset) {
1612 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1613 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1614 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1615 g_free(tmp);
1618 return g_string_free(str, FALSE);
1621 static gchar *
1622 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1624 GString* str = g_string_new(NULL);
1625 char *tmp;
1627 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1628 g_free(tmp);
1630 /* nonce (server_challenge) */
1631 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1632 g_free(tmp);
1634 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1635 g_free(tmp);
1637 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1638 g_free(tmp);
1640 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1641 g_free(tmp);
1643 if (cmsg->target_name.len && cmsg->target_name.offset) {
1644 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1645 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1646 g_free(target_name);
1649 if (cmsg->target_info.len && cmsg->target_info.offset) {
1650 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1651 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1653 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1654 g_free(tmp);
1656 describe_av_pairs(str, target_info);
1659 return g_string_free(str, FALSE);
1662 static void
1663 sip_sec_ntlm_message_describe(SipSecBuffer *buff,
1664 const gchar *type)
1666 struct ntlm_message *msg;
1667 gchar *res = NULL;
1669 if (buff->length == 0 || buff->value == NULL || buff->length < 12) return;
1671 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1672 msg = (void *)buff->value;
1673 if(!sipe_strequal("NTLMSSP", (char*)msg)) return;
1675 switch (GUINT32_FROM_LE(msg->type)) {
1676 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1677 break;
1678 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1679 break;
1680 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1681 break;
1684 SIPE_DEBUG_INFO("sip_sec_ntlm_message_describe: %s message is:\n%s",
1685 type, res);
1686 g_free(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 username & password. Domain may be empty */
1715 if (!domain || is_empty(username) || is_empty(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 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
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 sip_sec_ntlm_gen_negotiate(out_buff);
1742 sip_sec_ntlm_message_describe(out_buff, "Negotiate");
1744 return SIP_SEC_I_CONTINUE_NEEDED;
1746 } else {
1747 sip_uint32 res;
1748 guchar *client_sign_key = NULL;
1749 guchar *server_sign_key = NULL;
1750 guchar *client_seal_key = NULL;
1751 guchar *server_seal_key = NULL;
1752 guchar *server_challenge = NULL;
1753 guint64 time_val = 0;
1754 guchar *target_info = NULL;
1755 int target_info_len = 0;
1756 guint32 flags;
1757 gchar *tmp;
1759 if (!in_buff.value || !in_buff.length) {
1760 return SIP_SEC_E_INTERNAL_ERROR;
1763 sip_sec_ntlm_message_describe(&in_buff, "Challenge");
1765 sip_sec_ntlm_parse_challenge(in_buff,
1766 &flags,
1767 &server_challenge, /* 8 bytes */
1768 &time_val,
1769 &target_info,
1770 &target_info_len);
1772 res = sip_sec_ntlm_gen_authenticate(
1773 &client_sign_key,
1774 &server_sign_key,
1775 &client_seal_key,
1776 &server_seal_key,
1777 ctx->username,
1778 ctx->password,
1779 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1780 ctx->domain,
1781 server_challenge,
1782 time_val,
1783 target_info,
1784 target_info_len,
1785 context->is_connection_based,
1786 out_buff,
1787 &flags);
1788 g_free(server_challenge);
1789 g_free(target_info);
1790 g_free(tmp);
1792 if (res != SIP_SEC_E_OK) {
1793 g_free(client_sign_key);
1794 g_free(server_sign_key);
1795 g_free(client_seal_key);
1796 g_free(server_seal_key);
1797 return res;
1800 sip_sec_ntlm_message_describe(out_buff, "Authenticate");
1802 g_free(ctx->client_sign_key);
1803 ctx->client_sign_key = client_sign_key;
1805 g_free(ctx->server_sign_key);
1806 ctx->server_sign_key = server_sign_key;
1808 g_free(ctx->client_seal_key);
1809 ctx->client_seal_key = client_seal_key;
1811 g_free(ctx->server_seal_key);
1812 ctx->server_seal_key = server_seal_key;
1814 ctx->flags = flags;
1815 return SIP_SEC_E_OK;
1820 * @param message a NULL terminated string to sign
1823 static sip_uint32
1824 sip_sec_make_signature__ntlm(SipSecContext context,
1825 const char *message,
1826 SipSecBuffer *signature)
1828 signature->length = 16;
1829 signature->value = g_malloc0(16);
1831 /* FIXME? We always use a random_pad of 0 */
1832 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1833 message,
1835 ((context_ntlm) context)->client_sign_key,
1836 ((context_ntlm) context)->client_seal_key,
1837 /* SipSecBuffer.value is g_malloc()'d:
1838 * use (void *) to remove guint8 alignment
1840 (void *)signature->value);
1841 return SIP_SEC_E_OK;
1845 * @param message a NULL terminated string to check signature of
1846 * @return SIP_SEC_E_OK on success
1848 static sip_uint32
1849 sip_sec_verify_signature__ntlm(SipSecContext context,
1850 const char *message,
1851 SipSecBuffer signature)
1853 guint32 mac[4];
1854 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1855 guint32 random_pad = GUINT32_FROM_LE(((guint32 *)((void *)signature.value))[1]);
1857 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1858 message,
1859 random_pad,
1860 ((context_ntlm) context)->server_sign_key,
1861 ((context_ntlm) context)->server_seal_key,
1862 mac);
1863 return(memcmp(signature.value, mac, 16) ?
1864 SIP_SEC_E_INTERNAL_ERROR :
1865 SIP_SEC_E_OK);
1868 static void
1869 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1871 context_ntlm ctx = (context_ntlm) context;
1873 g_free(ctx->domain);
1874 g_free(ctx->username);
1875 g_free(ctx->password);
1876 g_free(ctx->client_sign_key);
1877 g_free(ctx->server_sign_key);
1878 g_free(ctx->client_seal_key);
1879 g_free(ctx->server_seal_key);
1880 g_free(ctx);
1883 SipSecContext
1884 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER guint type)
1886 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1887 if (!context) return(NULL);
1889 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1890 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1891 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1892 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1893 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1895 return((SipSecContext) context);
1898 gboolean sip_sec_password__ntlm(void)
1900 return(TRUE);
1903 void sip_sec_init__ntlm(void)
1905 #ifdef HAVE_LANGINFO_CODESET
1906 const char *sys_cp = nl_langinfo(CODESET);
1907 #else
1908 const char *sys_cp = SIPE_DEFAULT_CODESET;
1909 #endif /* HAVE_LANGINFO_CODESET */
1911 /* fall back to utf-8 */
1912 if (!sys_cp) sys_cp = "UTF-8";
1914 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1915 if (convert_from_utf16le == (GIConv)-1) {
1916 SIPE_DEBUG_ERROR("g_iconv_open from UTF-16LE to %s failed",
1917 sys_cp);
1920 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1921 if (convert_to_utf16le == (GIConv)-1) {
1922 SIPE_DEBUG_ERROR("g_iconv_open from %s to UTF-16LE failed",
1923 sys_cp);
1927 void sip_sec_destroy__ntlm(void)
1929 g_iconv_close(convert_to_utf16le);
1930 g_iconv_close(convert_from_utf16le);
1934 Local Variables:
1935 mode: c
1936 c-file-style: "bsd"
1937 indent-tabs-mode: t
1938 tab-width: 8
1939 End: