Fix #3130915: Failed to authenticate to server
[siplcs.git] / src / core / sip-sec-ntlm.c
blob8540787ba3dc5f0f2e334fb264340406a0d8d778
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2010 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 #include <stdlib.h>
50 #include <string.h>
51 #include <time.h>
53 #include <glib.h>
55 #ifdef HAVE_LANGINFO_CODESET
56 #include <langinfo.h>
57 #endif /* HAVE_LANGINFO_CODESET */
59 #include "sipe-common.h"
60 #include "sip-sec.h"
61 #include "sip-sec-mech.h"
62 #include "sip-sec-ntlm.h"
63 #include "sipe-backend.h"
64 #include "sipe-crypt.h"
65 #include "sipe-digest.h"
66 #include "sipe-utils.h"
68 /* [MS-NLMP] */
69 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
70 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
71 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
72 #define r9 0x00000008 /* r9 */
73 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
74 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
75 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
76 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
77 #define r8 0x00000100 /* r8 */
78 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
79 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
80 #define anonymous 0x00000800 /* J */
81 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
82 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
83 #define r7 0x00004000 /* r7 */
84 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
85 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
86 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
87 #define r6 0x00040000 /* r6 */
88 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
89 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
90 #define r5 0x00200000 /* r5 */
91 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
92 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
93 #define r4 0x01000000 /* r4 */
94 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
95 #define r3 0x04000000 /* r3 */
96 #define r2 0x08000000 /* r2 */
97 #define r1 0x10000000 /* r1 */
98 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
99 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
100 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
102 /* AvId */
103 #define MsvAvEOL 0
104 #define MsvAvNbComputerName 1
105 #define MsvAvNbDomainName 2
106 #define MsvAvDnsComputerName 3
107 #define MsvAvDnsDomainName 4
108 /** @since Windows XP */
109 #define MsvAvDnsTreeName 5
110 /** @since Windows XP */
111 #define MsvAvFlags 6
112 /** @since Windows Vista */
113 #define MsvAvTimestamp 7
114 /** @since Windows Vista */
115 #define MsAvRestrictions 8
116 /** @since Windows 7 */
117 #define MsvAvTargetName 9
118 /** @since Windows 7 */
119 #define MsvChannelBindings 10
121 /* time_t <-> (guint64) time_val conversion */
122 #define TIME_VAL_FACTOR 10000000
123 #define TIME_VAL_OFFSET 116444736000000000LL
124 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
125 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
127 /* 8 bytes */
128 /* LE (Little Endian) byte order */
129 struct version {
130 guint8 product_major_version;
131 guint8 product_minor_version;
132 guint16 product_build;
133 guint8 zero2[3];
134 guint8 ntlm_revision_current;
138 * NTLMv1 is no longer used except in tests. R.I.P.
140 * It remains in this file only for documentary purposes
142 #ifdef _SIPE_COMPILING_TESTS
143 static gboolean use_ntlm_v2 = FALSE;
145 guint64 test_time_val = 0; /* actual time in implementation */
146 guchar test_client_challenge [8]; /* random in implementation */
147 guchar test_random_session_key[16]; /* random in implementation */
148 struct version test_version; /* hard-coded in implementation */
149 #endif
151 /* Minimum set of common features we need to work. */
152 /* we operate in NTLMv2 mode */
153 #define NEGOTIATE_FLAGS_COMMON_MIN \
154 ( NTLMSSP_NEGOTIATE_UNICODE | \
155 NTLMSSP_NEGOTIATE_NTLM | \
156 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
157 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
158 NTLMSSP_NEGOTIATE_TARGET_INFO \
161 /* Negotiate flags for connection-based mode. Nice to have but optional. */
162 #define NEGOTIATE_FLAGS_CONN \
163 ( NEGOTIATE_FLAGS_COMMON_MIN | \
164 NTLMSSP_NEGOTIATE_VERSION | \
165 NTLMSSP_NEGOTIATE_128 | \
166 NTLMSSP_NEGOTIATE_56 | \
167 NTLMSSP_REQUEST_TARGET \
170 /* Extra negotiate flags required in connectionless NTLM */
171 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
172 ( NTLMSSP_NEGOTIATE_SIGN | \
173 NTLMSSP_NEGOTIATE_DATAGRAM | \
174 NTLMSSP_NEGOTIATE_IDENTIFY | \
175 NTLMSSP_NEGOTIATE_KEY_EXCH \
178 /* Negotiate flags required in connectionless NTLM */
179 #define NEGOTIATE_FLAGS_CONNLESS \
180 ( NEGOTIATE_FLAGS_CONN | \
181 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
184 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
185 #define NTLMSSP_LM_RESP_LEN 24
186 #define NTLMSSP_SESSION_KEY_LEN 16
188 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
190 /* 4 bytes */
191 /* LE (Little Endian) byte order */
192 struct av_pair {
193 guint16 av_id;
194 guint16 av_len;
195 /* value */
198 /* to meet sparc's alignment requirement */
199 #define ALIGN_AV \
200 memcpy(&av_aligned, av, sizeof(av_aligned)); \
201 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
202 av_len = GUINT16_FROM_LE(av_aligned.av_len)
203 #define ALIGN_AV_LOOP_START \
204 struct av_pair av_aligned; \
205 guint16 av_id; \
206 guint16 av_len; \
207 ALIGN_AV; \
208 while (av_id != MsvAvEOL) { \
209 gchar *av_value = ((gchar *)av) + \
210 sizeof(struct av_pair); \
211 switch (av_id)
212 #define ALIGN_AV_LOOP_END \
213 av = av_value + av_len; \
214 ALIGN_AV; \
217 /* 8 bytes */
218 /* LE (Little Endian) byte order */
219 struct smb_header {
220 guint16 len;
221 guint16 maxlen;
222 guint32 offset;
225 /* LE (Little Endian) byte order */
226 struct ntlm_message {
227 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
228 guint32 type; /* 0x00000003 */
231 /* LE (Little Endian) byte order */
232 struct negotiate_message {
233 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
234 guint32 type; /* 0x00000001 */
235 guint32 flags; /* 0xb203 */
236 struct smb_header domain;
237 struct smb_header host;
238 struct version ver;
239 /* payload
240 * - DomainName (always ASCII)
241 * - WorkstationName (always ASCII)
245 /* LE (Little Endian) byte order */
246 struct challenge_message {
247 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
248 guint32 type; /* 0x00000002 */
249 struct smb_header target_name;
250 guint32 flags; /* 0x8201 */
251 guint8 nonce[8];
252 guint8 zero1[8];
253 struct smb_header target_info;
254 struct version ver;
255 /* payload
256 * - TargetName (negotiated encoding)
257 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
261 /* LE (Little Endian) byte order */
262 struct authenticate_message {
263 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
264 guint32 type; /* 0x00000003 */
265 /** LmChallengeResponseFields */
266 struct smb_header lm_resp;
267 /** NtChallengeResponseFields */
268 struct smb_header nt_resp;
269 /** DomainNameFields */
270 struct smb_header domain;
271 /** UserNameFields */
272 struct smb_header user;
273 /** WorkstationFields */
274 struct smb_header host;
275 /** EncryptedRandomSessionKeyFields */
276 struct smb_header session_key;
277 guint32 flags;
278 struct version ver;
279 //guint8 mic[16];
280 /* payload
281 * - LmChallengeResponse
282 * - NtChallengeResponse
283 * - DomainName (negotiated encoding)
284 * - UserName (negotiated encoding)
285 * - Workstation (negotiated encoding)
286 * - EncryptedRandomSessionKey
290 #ifndef HAVE_LANGINFO_CODESET
291 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
292 #endif
294 /* Private Methods */
296 /* Utility Functions */
297 static GIConv convert_from_utf16le = (GIConv)-1;
298 static GIConv convert_to_utf16le = (GIConv)-1;
300 static gsize
301 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
303 gsize inbytes = strlen(source);
304 gsize outbytes = remlen;
305 if (remlen)
306 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
307 return(remlen - outbytes);
310 /* UTF-16LE to native encoding
311 * Must be g_free'd after use */
312 static gchar *
313 unicode_strconvcopy_back(const gchar *source, gsize len)
315 gsize outbytes = 2 * len;
316 gchar *dest = g_new0(gchar, outbytes + 1);
317 gchar *outbuf = dest;
318 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
319 return dest;
322 /* crc32 source copy from gg's common.c */
323 static guint32 crc32_table[256];
324 static int crc32_initialized = 0;
326 static void crc32_make_table()
328 guint32 h = 1;
329 unsigned int i, j;
331 memset(crc32_table, 0, sizeof(crc32_table));
333 for (i = 128; i; i >>= 1) {
334 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
336 for (j = 0; j < 256; j += 2 * i)
337 crc32_table[i + j] = crc32_table[j] ^ h;
340 crc32_initialized = 1;
343 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
345 if (!crc32_initialized)
346 crc32_make_table();
348 if (!buf || len < 0)
349 return crc;
351 crc ^= 0xffffffffL;
353 while (len--)
354 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
356 return crc ^ 0xffffffffL;
359 static guint32
360 CRC32 (const char *msg, int len)
362 guint32 crc = 0L;
363 crc = crc32(crc, (guint8 *) msg, len);
364 return crc;
367 /* Cyphers */
369 #ifdef _SIPE_COMPILING_TESTS
370 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
372 key[0] = key_56[0];
373 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
374 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
375 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
376 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
377 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
378 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
379 key[7] = (key_56[6] << 1) & 0xFF;
382 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
383 static void
384 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
386 unsigned char key[8];
387 setup_des_key(k, key);
388 sipe_crypt_des(key, d, 8, results);
391 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
392 static void
393 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
395 unsigned char keys[21];
397 /* Copy the first 16 bytes */
398 memcpy(keys, k, 16);
400 /* Zero out the last 5 bytes of the key */
401 memset(keys + 16, 0, 5);
403 DES(keys, d, results);
404 DES(keys + 7, d, results + 8);
405 DES(keys + 14, d, results + 16);
407 #endif
409 #define RC4K(key, key_len, plain, plain_len, encrypted) \
410 sipe_crypt_rc4((key), (key_len), (plain), (plain_len), (encrypted))
412 /* out 16 bytes */
413 #define MD4(d, len, result) sipe_digest_md4((d), (len), (result))
415 /* out 16 bytes */
416 #define MD5(d, len, result) sipe_digest_md5((d), (len), (result))
418 /* out 16 bytes */
420 static void
421 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
423 int i;
424 unsigned char ibuff[64 + data_len];
425 unsigned char obuff[64 + 16];
427 if (key_len > 64)
428 key_len = 64;
430 for (i = 0; i < key_len; i++) {
431 ibuff[i] = key[i] ^ 0x36;
432 obuff[i] = key[i] ^ 0x5c;
434 for (i = key_len; i < 64; i++) {
435 ibuff[i] = 0x36;
436 obuff[i] = 0x5c;
439 memcpy(ibuff+64, data, data_len);
441 MD5 (ibuff, 64 + data_len, obuff+64);
442 MD5 (obuff, 64 + 16, result);
444 #define HMAC_MD5 HMACT64
447 /* out 16 bytes */
448 #define HMAC_MD5(key, key_len, data, data_len, result) \
449 sipe_digest_hmac_md5((key), (key_len), (data), (data_len), (result))
451 /* NTLM Core Methods */
453 static void
454 NONCE(unsigned char *buffer, int num)
456 int i;
457 for (i = 0; i < num; i++) {
458 buffer[i] = (rand() & 0xff);
462 #ifdef _SIPE_COMPILING_TESTS
463 static void
464 Z(unsigned char *buffer, int num)
466 memset(buffer, 0, num);
469 static void
470 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
472 /* "KGS!@#$%" */
473 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
474 unsigned char uppercase_password[14];
475 int i;
477 int len = strlen(password);
478 if (len > 14) {
479 len = 14;
482 // Uppercase password
483 for (i = 0; i < len; i++) {
484 uppercase_password[i] = g_ascii_toupper(password[i]);
487 // Zero the rest
488 for (; i < 14; i++) {
489 uppercase_password[i] = 0;
492 DES (uppercase_password, magic, result);
493 DES (uppercase_password + 7, magic, result + 8);
495 #endif
498 Define NTOWFv1(Passwd, User, UserDom) as
499 MD4(UNICODE(Passwd))
500 EndDefine
502 /* out 16 bytes */
503 static void
504 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
506 int len_u = 2 * strlen(password); // utf16 should not be more
507 unsigned char *unicode_password = g_malloc(len_u);
509 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
510 MD4 (unicode_password, len_u, result);
511 g_free(unicode_password);
515 Define NTOWFv2(Passwd, User, UserDom) as
516 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
517 EndDefine
519 /* out 16 bytes */
520 void
521 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
523 unsigned char response_key_nt_v1 [16];
524 int len_user = user ? strlen(user) : 0;
525 int len_domain = domain ? strlen(domain) : 0;
526 int len_user_u = 2 * len_user; // utf16 should not be more
527 int len_domain_u = 2 * len_domain; // utf16 should not be more
528 unsigned char *user_upper = g_malloc(len_user + 1);
529 unsigned char *buff = g_malloc((len_user + len_domain)*2);
530 int i;
532 /* Uppercase user */
533 for (i = 0; i < len_user; i++) {
534 user_upper[i] = g_ascii_toupper(user[i]);
536 user_upper[len_user] = 0;
538 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
539 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
541 NTOWFv1(password, user, domain, response_key_nt_v1);
543 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
545 g_free(buff);
546 g_free(user_upper);
549 static void
550 compute_response(const guint32 neg_flags,
551 const unsigned char *response_key_nt,
552 const unsigned char *response_key_lm,
553 const guint8 *server_challenge,
554 const guint8 *client_challenge,
555 const guint64 time_val,
556 const guint8 *target_info,
557 int target_info_len,
558 unsigned char *lm_challenge_response,
559 unsigned char *nt_challenge_response,
560 unsigned char *session_base_key)
562 #ifdef _SIPE_COMPILING_TESTS
563 if (use_ntlm_v2)
565 #endif
567 Responserversion - The 1-byte response version. Currently set to 1.
568 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
569 Time - The 8-byte little-endian time in GMT.
570 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
571 ClientChallenge - The 8-byte challenge message generated by the client.
572 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
574 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
575 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
576 Time, //8bytes - 8
577 ClientChallenge, //8bytes - 16
578 Z(4), //4bytes - 24
579 ServerName, //variable - 28
580 Z(4)) //4bytes - 28+target_info_len
581 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
582 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
583 Set LmChallengeResponse to ConcatenationOf(
584 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
585 ClientChallenge )
586 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
587 EndDefine
589 guint8 tmp [16];
590 guint8 nt_proof_str [16];
592 /* client_challenge (8) & temp (temp_len) buff */
593 int temp_len = 8+8+8+4+target_info_len+4;
594 guint64 *temp2 = g_malloc0(8 + temp_len);
595 ((guint8 *) temp2)[8+0] = 1;
596 ((guint8 *) temp2)[8+1] = 1;
597 temp2[2] = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
598 memcpy(((guint8 *) temp2)+8+16, client_challenge, 8);
599 memcpy(((guint8 *) temp2)+8+28, target_info, target_info_len);
601 /* NTProofStr */
602 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
603 memcpy(temp2, server_challenge, 8);
604 HMAC_MD5(response_key_nt, 16, (guint8*)temp2, 8+temp_len, nt_proof_str);
606 /* NtChallengeResponse */
607 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
608 memcpy(nt_challenge_response, nt_proof_str, 16);
609 memcpy(nt_challenge_response+16, temp2+1, temp_len);
610 g_free(temp2);
612 /* SessionBaseKey */
613 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
614 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
616 /* lm_challenge_response */
617 memcpy(tmp, server_challenge, 8);
618 memcpy(tmp+8, client_challenge, 8);
619 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
620 memcpy(lm_challenge_response+16, client_challenge, 8);
622 #ifndef _SIPE_COMPILING_TESTS
623 /* Not used in NTLMv2 */
624 (void)neg_flags;
625 #else
627 else
629 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
630 // @TODO do not even reference nt_challenge_response
631 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
632 DESL (response_key_lm, server_challenge, lm_challenge_response);
633 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
634 unsigned char prehash [16];
635 unsigned char hash [16];
637 /* nt_challenge_response */
638 memcpy(prehash, server_challenge, 8);
639 memcpy(prehash + 8, client_challenge, 8);
640 MD5 (prehash, 16, hash);
641 DESL (response_key_nt, hash, nt_challenge_response);
643 /* lm_challenge_response */
644 memcpy(lm_challenge_response, client_challenge, 8);
645 Z (lm_challenge_response+8, 16);
646 } else {
647 DESL (response_key_nt, server_challenge, nt_challenge_response);
648 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
649 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
650 } else {
651 DESL (response_key_lm, server_challenge, lm_challenge_response);
655 /* Session Key */
656 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
658 #endif
661 static void
662 KXKEY ( guint32 flags,
663 const unsigned char * session_base_key,
664 const unsigned char * lm_challenge_resonse,
665 const guint8 * server_challenge, /* 8-bytes, nonce */
666 unsigned char * key_exchange_key)
668 #ifdef _SIPE_COMPILING_TESTS
669 if (use_ntlm_v2)
671 #else
672 /* Not used in NTLMv2 */
673 (void)flags;
674 (void)lm_challenge_resonse;
675 (void)server_challenge;
676 #endif
677 memcpy(key_exchange_key, session_base_key, 16);
678 #ifdef _SIPE_COMPILING_TESTS
680 else
682 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
683 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
684 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
685 EndDefine
687 guint8 tmp[16];
688 memcpy(tmp, server_challenge, 8);
689 memcpy(tmp+8, lm_challenge_resonse, 8);
690 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
691 } else {
692 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
693 memcpy(key_exchange_key, session_base_key, 16);
696 #endif
700 If (Mode equals "Client")
701 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
702 "session key to client-to-server signing key magic constant"))
703 Else
704 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
705 "session key to server-to-client signing key magic constant"))
706 Endif
708 static void
709 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
711 char * magic = client
712 ? "session key to client-to-server signing key magic constant"
713 : "session key to server-to-client signing key magic constant";
715 int len = strlen(magic) + 1;
716 unsigned char *md5_input = g_malloc(16 + len);
717 memcpy(md5_input, random_session_key, 16);
718 memcpy(md5_input + 16, magic, len);
720 MD5 (md5_input, len + 16, result);
721 g_free(md5_input);
725 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
726 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
727 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
728 Set SealKey to RandomSessionKey
729 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
730 Set SealKey to RandomSessionKey[0..6]
731 Else
732 Set SealKey to RandomSessionKey[0..4]
733 Endif
735 If (Mode equals "Client")
736 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
737 Else
738 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
739 Endif
741 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
742 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
743 Else
744 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
745 Endif
746 EndDefine
748 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
749 static void
750 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
752 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
754 char * magic = client
755 ? "session key to client-to-server sealing key magic constant"
756 : "session key to server-to-client sealing key magic constant";
758 int len = strlen(magic) + 1;
759 unsigned char *md5_input = g_malloc(16 + len);
760 int key_len;
762 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
763 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
764 key_len = 16;
765 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
766 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
767 key_len = 7;
768 } else {
769 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
770 key_len = 5;
773 memcpy(md5_input, random_session_key, key_len);
774 memcpy(md5_input + key_len, magic, len);
776 MD5 (md5_input, key_len + len, result);
777 g_free(md5_input);
779 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
781 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
782 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
783 memcpy(result, random_session_key, 7);
784 result[7] = 0xA0;
785 } else {
786 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
787 memcpy(result, random_session_key, 5);
788 result[5] = 0xE5;
789 result[6] = 0x38;
790 result[7] = 0xB0;
793 else
795 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
796 memcpy(result, random_session_key, 16);
801 = for Extended Session Security =
802 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
803 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
804 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
806 = if Extended Session Security is NOT negotiated =
807 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
808 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
809 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
810 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
812 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
814 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
815 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
817 /** MAC(Handle, SigningKey, SeqNum, Message) */
818 /* out 16 bytes */
819 static void
820 MAC (guint32 flags,
821 const char *buf,
822 int buf_len,
823 unsigned char *sign_key,
824 unsigned long sign_key_len,
825 unsigned char *seal_key,
826 unsigned long seal_key_len,
827 guint32 random_pad,
828 guint32 sequence,
829 guint32 *result)
831 guint32 *res_ptr;
833 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
835 Define MAC(Handle, SigningKey, SeqNum, Message) as
836 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
837 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
838 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
839 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
840 Set SeqNum to SeqNum + 1
841 EndDefine
843 /* If a key exchange key is negotiated
844 Define MAC(Handle, SigningKey, SeqNum, Message) as
845 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
846 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
847 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
848 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
849 Set SeqNum to SeqNum + 1
850 EndDefine
853 unsigned char seal_key_ [16];
854 guchar hmac[16];
855 guint32 *tmp = g_malloc(4 + buf_len);
857 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
858 RC4Init(Handle, SealingKey')
860 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
861 guint32 tmp2[4+1];
863 memcpy(tmp2, seal_key, seal_key_len);
864 tmp2[4] = GUINT32_TO_LE(sequence);
865 MD5 ((guchar *)tmp2, sizeof(tmp2), seal_key_);
866 } else {
867 memcpy(seal_key_, seal_key, seal_key_len);
870 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extented Session Security");
872 res_ptr = result;
873 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
874 res_ptr[3] = GUINT32_TO_LE(sequence);
876 res_ptr = tmp;
877 res_ptr[0] = GUINT32_TO_LE(sequence);
878 memcpy(tmp+1, buf, buf_len);
880 HMAC_MD5(sign_key, sign_key_len, (guchar *)tmp, 4 + buf_len, hmac);
881 g_free(tmp);
883 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
884 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
885 RC4K(seal_key_, seal_key_len, hmac, 8, (guchar *)(result+1));
886 } else {
887 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
888 memcpy(result+1, hmac, 8);
890 } else {
891 /* The content of the first 4 bytes is irrelevant */
892 guint32 crc = CRC32(buf, strlen(buf));
893 guint32 plaintext [] = {
894 GUINT32_TO_LE(0),
895 GUINT32_TO_LE(crc),
896 GUINT32_TO_LE(sequence)
897 }; // 4, 4, 4 bytes
899 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extented Session Security");
901 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, (guchar *)(result+1));
903 res_ptr = result;
904 // Highest four bytes are the Version
905 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
907 // Replace the first four bytes of the ciphertext with the random_pad
908 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
912 /* End Core NTLM Methods */
915 * @param flags (out) flags received from server
916 * @param server_challenge must be g_free()'d after use if requested
917 * @param target_info must be g_free()'d after use if requested
919 static void
920 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
921 guint32 *flags,
922 guchar **server_challenge, /* 8 bytes */
923 guint64 *time_val,
924 guchar **target_info,
925 int *target_info_len)
927 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
928 struct challenge_message *cmsg = (void *)in_buff.value;
929 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
931 /* server challenge (nonce) */
932 if (server_challenge) {
933 *server_challenge = g_memdup(cmsg->nonce, 8);
936 /* flags */
937 if (flags) {
938 *flags = host_flags;
941 /* target_info */
942 if (cmsg->target_info.len && cmsg->target_info.offset) {
943 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
944 void *av = content;
945 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
947 ALIGN_AV_LOOP_START
949 /* @since Vista */
950 case MsvAvTimestamp:
951 if (time_val) {
952 guint64 tmp;
954 /* to meet sparc's alignment requirement */
955 memcpy(&tmp, av_value, sizeof(tmp));
956 *time_val = GUINT64_FROM_LE(tmp);
958 break;
960 ALIGN_AV_LOOP_END;
962 if (target_info_len) {
963 *target_info_len = len;
965 if (target_info) {
966 *target_info = g_memdup(content, len);
972 * @param client_sign_key (out) must be g_free()'d after use
973 * @param server_sign_key (out) must be g_free()'d after use
974 * @param client_seal_key (out) must be g_free()'d after use
975 * @param server_seal_key (out) must be g_free()'d after use
976 * @param flags (in, out) negotiated flags
978 static sip_uint32
979 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
980 guchar **server_sign_key,
981 guchar **client_seal_key,
982 guchar **server_seal_key,
983 const gchar *user,
984 const gchar *password,
985 const gchar *hostname,
986 const gchar *domain,
987 const guint8 *server_challenge, /* nonce */
988 const guint64 time_val,
989 const guint8 *target_info,
990 int target_info_len,
991 gboolean is_connection_based,
992 SipSecBuffer *out_buff,
993 guint32 *flags)
995 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
996 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
997 int ntlmssp_nt_resp_len =
998 #ifdef _SIPE_COMPILING_TESTS
999 use_ntlm_v2 ?
1000 #endif
1001 (16 + (32+target_info_len))
1002 #ifdef _SIPE_COMPILING_TESTS
1003 : NTLMSSP_LM_RESP_LEN
1004 #endif
1006 gsize msglen = sizeof(struct authenticate_message)
1007 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1008 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1009 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1010 struct authenticate_message *tmsg;
1011 char *tmp;
1012 guint32 offset;
1013 guint16 len;
1014 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1015 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1016 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1017 unsigned char *nt_challenge_response = g_malloc(ntlmssp_nt_resp_len); /* variable or 24 */
1018 unsigned char session_base_key [16];
1019 unsigned char key_exchange_key [16];
1020 unsigned char exported_session_key[16];
1021 unsigned char encrypted_random_session_key [16];
1022 unsigned char key [16];
1023 unsigned char client_challenge [8];
1024 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1026 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1027 !(is_connection_based || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)))
1029 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1030 return SIP_SEC_E_INTERNAL_ERROR;
1033 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1034 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1037 tmsg = g_malloc0(msglen);
1039 NONCE (client_challenge, 8);
1041 #ifdef _SIPE_COMPILING_TESTS
1042 memcpy(client_challenge, test_client_challenge, 8);
1043 time_vl = test_time_val ? test_time_val : time_vl;
1045 if (use_ntlm_v2) {
1047 #endif
1048 NTOWFv2 (password, user, domain, response_key_nt);
1049 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1050 #ifdef _SIPE_COMPILING_TESTS
1051 } else {
1052 NTOWFv1 (password, user, domain, response_key_nt);
1053 LMOWFv1 (password, user, domain, response_key_lm);
1055 #endif
1057 compute_response(neg_flags,
1058 response_key_nt,
1059 response_key_lm,
1060 server_challenge,
1061 client_challenge,
1062 time_vl,
1063 target_info,
1064 target_info_len,
1065 lm_challenge_response, /* out */
1066 nt_challenge_response, /* out */
1067 session_base_key); /* out */
1069 /* same as session_base_key for
1070 * - NTLNv1 w/o Ext.Sess.Sec and
1071 * - NTLMv2
1073 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1075 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1076 NONCE (exported_session_key, 16); // random master key
1077 #ifdef _SIPE_COMPILING_TESTS
1078 memcpy(exported_session_key, test_random_session_key, 16);
1079 #endif
1080 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1081 } else {
1082 memcpy(exported_session_key, key_exchange_key, 16);
1085 tmp = buff_to_hex_str(exported_session_key, 16);
1086 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp);
1087 g_free(tmp);
1089 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1090 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1092 /* p.46
1093 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1094 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1096 SIGNKEY(exported_session_key, TRUE, key);
1097 *client_sign_key = g_memdup(key, 16);
1098 SIGNKEY(exported_session_key, FALSE, key);
1099 *server_sign_key = g_memdup(key, 16);
1100 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1101 *client_seal_key = g_memdup(key, 16);
1102 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1103 *server_seal_key = g_memdup(key, 16);
1106 /* @TODO: */
1107 /* @since Vista
1108 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1109 the client SHOULD provide a MIC:
1110 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1111 - then in the Value field, set bit 0x2 to 1.
1112 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1113 and the Value field bit 0x2 to 1.
1114 - Populate the MIC field with the MIC.
1117 /* Connection-oriented:
1118 Set MIC to HMAC_MD5(ExportedSessionKey,
1119 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1120 Connectionless:
1121 Set MIC to HMAC_MD5(ExportedSessionKey,
1122 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1125 /* on the server-side:
1126 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1127 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1128 Set MIC to HMAC_MD5(ExportedSessionKey,
1129 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1130 Else
1131 Set ExportedSessionKey to KeyExchangeKey
1132 Set MIC to HMAC_MD5(KeyExchangeKey,
1133 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1134 =====
1135 @since Vista
1136 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1137 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1138 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1139 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1140 an AV_PAIR structure whose two fields:
1141 - AvId == MsvAvFlags
1142 - Value bit 0x2 == 1
1143 @supported NT, 2000, XP
1144 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1145 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1146 the server time, then the server SHOULD return a failure.
1148 Connectionless:
1149 Set MIC to HMAC_MD5(ResponseKeyNT,
1150 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1153 /* authenticate message initialization */
1154 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1155 tmsg->type = GUINT32_TO_LE(3);
1157 /* Initial offset */
1158 offset = sizeof(struct authenticate_message);
1159 tmp = ((char*) tmsg) + offset;
1161 #define _FILL_SMB_HEADER(header) \
1162 tmsg->header.offset = GUINT32_TO_LE(offset); \
1163 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1164 tmp += len; \
1165 offset += len
1166 #define _APPEND_STRING(header, src) \
1167 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1168 _FILL_SMB_HEADER(header)
1169 #define _APPEND_DATA(header, src, srclen) \
1170 len = (srclen); \
1171 memcpy(tmp, (src), len); \
1172 _FILL_SMB_HEADER(header)
1174 /* Domain */
1175 _APPEND_STRING(domain, domain);
1177 /* User */
1178 _APPEND_STRING(user, user);
1180 /* Host */
1181 _APPEND_STRING(host, hostname);
1183 /* LM */
1184 /* @since Windows 7
1185 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1186 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1187 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1189 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1191 /* NT */
1192 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1194 /* Session Key */
1195 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1197 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1199 else
1201 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1202 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1205 /* Version */
1206 #ifdef _SIPE_COMPILING_TESTS
1207 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1208 #else
1209 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1210 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1211 tmsg->ver.product_minor_version = 1;
1212 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1213 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1215 #endif
1217 /* Set Negotiate Flags */
1218 tmsg->flags = GUINT32_TO_LE(neg_flags);
1219 *flags = neg_flags;
1221 out_buff->value = (guint8 *)tmsg;
1222 out_buff->length = msglen;
1224 g_free(nt_challenge_response);
1226 return SIP_SEC_E_OK;
1230 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1232 static void
1233 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1235 guint32 offset;
1236 guint16 len;
1237 int msglen = sizeof(struct negotiate_message);
1238 struct negotiate_message *tmsg = g_malloc0(msglen);
1240 /* negotiate message initialization */
1241 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1242 tmsg->type = GUINT32_TO_LE(1);
1244 /* Set Negotiate Flags */
1245 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1247 /* Domain */
1248 offset = sizeof(struct negotiate_message);
1249 tmsg->domain.offset = GUINT32_TO_LE(offset);
1250 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1252 /* Host */
1253 offset += len;
1254 tmsg->host.offset = GUINT32_TO_LE(offset);
1255 tmsg->host.len = tmsg->host.maxlen = len = 0;
1257 /* Version */
1258 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1259 tmsg->ver.product_minor_version = 1;
1260 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1261 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1263 out_buff->value = (guint8 *)tmsg;
1264 out_buff->length = msglen;
1267 static void
1268 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1269 const char *msg,
1270 guint32 random_pad,
1271 unsigned char *sign_key,
1272 unsigned char *seal_key,
1273 guint32 *result)
1275 char *res;
1277 MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100, result);
1279 res = buff_to_hex_str((guint8 *)result, 16);
1280 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res);
1281 g_free(res);
1285 /* Describe NTLM messages functions */
1287 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1288 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1290 static gchar *
1291 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1293 GString* str = g_string_new(NULL);
1295 flags = GUINT32_FROM_LE(flags);
1297 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1298 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1299 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1300 APPEND_NEG_FLAG(str, flags, r9, "r9");
1301 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1302 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1303 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1304 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1305 APPEND_NEG_FLAG(str, flags, r8, "r8");
1306 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1307 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1308 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1309 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1310 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1311 APPEND_NEG_FLAG(str, flags, r7, "r7");
1312 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1313 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1314 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1315 APPEND_NEG_FLAG(str, flags, r6, "r6");
1316 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1317 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1318 APPEND_NEG_FLAG(str, flags, r5, "r5");
1319 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1320 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1321 APPEND_NEG_FLAG(str, flags, r4, "r4");
1322 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1323 APPEND_NEG_FLAG(str, flags, r3, "r3");
1324 APPEND_NEG_FLAG(str, flags, r2, "r2");
1325 APPEND_NEG_FLAG(str, flags, r1, "r1");
1326 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1327 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1328 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1330 return g_string_free(str, FALSE);
1333 static gchar *
1334 sip_sec_ntlm_describe_version(struct version *ver) {
1335 GString* str = g_string_new(NULL);
1336 gchar *ver_desc = "";
1337 gchar *ntlm_revision_desc = "";
1339 if (ver->product_major_version == 6) {
1340 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1341 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1342 ver_desc = "Windows Server 2003";
1343 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1344 ver_desc = "Windows XP SP2";
1347 if (ver->ntlm_revision_current == 0x0F) {
1348 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1349 } else if (ver->ntlm_revision_current == 0x0A) {
1350 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1353 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1354 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1355 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1357 return g_string_free(str, FALSE);
1360 static gchar *
1361 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1362 const char* name)
1364 GString* str = g_string_new(NULL);
1366 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1367 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1368 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1370 return g_string_free(str, FALSE);
1373 static gchar *
1374 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1376 GString* str = g_string_new(NULL);
1377 char *tmp;
1379 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1380 g_free(tmp);
1382 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1383 g_free(tmp);
1385 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1386 g_free(tmp);
1388 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1389 g_string_append(str, tmp);
1390 g_free(tmp);
1392 if (cmsg->domain.len && cmsg->domain.offset) {
1393 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1394 g_string_append_printf(str, "\tdomain: %s\n", domain);
1395 g_free(domain);
1398 if (cmsg->host.len && cmsg->host.offset) {
1399 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1400 g_string_append_printf(str, "\thost: %s\n", host);
1401 g_free(host);
1404 return g_string_free(str, FALSE);
1407 static void
1408 describe_av_pairs(GString* str, const void *av)
1410 #define AV_DESC(av_name) \
1412 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1413 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1414 g_free(tmp); \
1417 ALIGN_AV_LOOP_START
1419 case MsvAvNbComputerName:
1420 AV_DESC("MsvAvNbComputerName");
1421 break;
1422 case MsvAvNbDomainName:
1423 AV_DESC("MsvAvNbDomainName");
1424 break;
1425 case MsvAvDnsComputerName:
1426 AV_DESC("MsvAvDnsComputerName");
1427 break;
1428 case MsvAvDnsDomainName:
1429 AV_DESC("MsvAvDnsDomainName");
1430 break;
1431 case MsvAvDnsTreeName:
1432 AV_DESC("MsvAvDnsTreeName");
1433 break;
1434 case MsvAvFlags:
1436 guint32 flags;
1438 /* to meet sparc's alignment requirement */
1439 memcpy(&flags, av_value, sizeof(guint32));
1440 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1442 break;
1443 case MsvAvTimestamp:
1445 char *tmp;
1446 guint64 time_val;
1447 time_t time_t_val;
1449 /* to meet sparc's alignment requirement */
1450 memcpy(&time_val, av_value, sizeof(time_val));
1451 time_t_val = TIME_VAL_TO_T(time_val);
1453 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1454 asctime(gmtime(&time_t_val)));
1455 g_free(tmp);
1457 break;
1458 case MsAvRestrictions:
1459 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1460 break;
1461 case MsvAvTargetName:
1462 AV_DESC("MsvAvTargetName");
1463 break;
1464 case MsvChannelBindings:
1465 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1466 break;
1468 ALIGN_AV_LOOP_END;
1471 static gchar *
1472 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1474 GString* str = g_string_new(NULL);
1475 char *tmp;
1476 gsize value_len;
1477 guint8 *value;
1479 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1480 g_free(tmp);
1482 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1483 g_free(tmp);
1485 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1486 g_free(tmp);
1488 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1489 g_free(tmp);
1491 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1492 g_free(tmp);
1494 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1495 g_free(tmp);
1497 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1498 g_free(tmp);
1500 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1501 g_string_append(str, tmp);
1502 g_free(tmp);
1504 /* mic */
1505 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1506 //g_free(tmp);
1508 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1509 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1510 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1511 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1512 g_free(tmp);
1515 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1516 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1517 int nt_resp_len = nt_resp_len_full;
1519 value_len = nt_resp_len_full;
1520 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1521 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1522 g_free(tmp);
1524 if (nt_resp_len > 24) { /* NTLMv2 */
1525 nt_resp_len = 16;
1528 value_len = nt_resp_len;
1529 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1530 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1531 g_free(tmp);
1533 if (nt_resp_len_full > 24) { /* NTLMv2 */
1534 /* Work around Debian/x86_64 compiler bug */
1535 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1536 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1537 const guint8 *temp = (guint8 *)cmsg + offset;
1538 const guint response_version = temp[0];
1539 const guint hi_response_version = temp[1];
1540 const guint8 *client_challenge = temp + 16;
1541 const guint8 *target_info = temp + 28;
1542 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1543 guint64 time_val;
1544 time_t time_t_val;
1545 char *tmp;
1547 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1548 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1549 g_free(tmp);
1551 /* This is not int64 aligned on sparc */
1552 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1553 time_t_val = TIME_VAL_TO_T(time_val);
1555 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1556 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1558 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1559 asctime(gmtime(&time_t_val)));
1560 g_free(tmp);
1562 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1563 g_free(tmp);
1565 describe_av_pairs(str, target_info);
1567 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1571 if (cmsg->domain.len && cmsg->domain.offset) {
1572 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1573 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1574 g_free(domain);
1577 if (cmsg->user.len && cmsg->user.offset) {
1578 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1579 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1580 g_free(user);
1583 if (cmsg->host.len && cmsg->host.offset) {
1584 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1585 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1586 g_free(host);
1589 if (cmsg->session_key.len && cmsg->session_key.offset) {
1590 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1591 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1592 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1593 g_free(tmp);
1596 return g_string_free(str, FALSE);
1599 static gchar *
1600 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1602 GString* str = g_string_new(NULL);
1603 char *tmp;
1605 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1606 g_free(tmp);
1608 /* nonce (server_challenge) */
1609 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1610 g_free(tmp);
1612 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1613 g_free(tmp);
1615 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1616 g_free(tmp);
1618 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1619 g_free(tmp);
1621 if (cmsg->target_name.len && cmsg->target_name.offset) {
1622 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1623 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1624 g_free(target_name);
1627 if (cmsg->target_info.len && cmsg->target_info.offset) {
1628 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1629 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1631 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1632 g_free(tmp);
1634 describe_av_pairs(str, target_info);
1637 return g_string_free(str, FALSE);
1640 gchar *
1641 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1643 struct ntlm_message *msg;
1644 gchar *res = NULL;
1646 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1648 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1649 msg = (void *)buff.value;
1650 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1652 switch (GUINT32_FROM_LE(msg->type)) {
1653 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1654 break;
1655 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1656 break;
1657 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1658 break;
1661 return res;
1664 /* sip-sec-mech.h API implementation for NTLM */
1666 /* Security context for NTLM */
1667 typedef struct _context_ntlm {
1668 struct sip_sec_context common;
1669 char* domain;
1670 char *username;
1671 char *password;
1672 int step;
1673 guchar *client_sign_key;
1674 guchar *server_sign_key;
1675 guchar *client_seal_key;
1676 guchar *server_seal_key;
1677 guint32 flags;
1678 } *context_ntlm;
1681 static sip_uint32
1682 sip_sec_acquire_cred__ntlm(SipSecContext context,
1683 const char *domain,
1684 const char *username,
1685 const char *password)
1687 context_ntlm ctx = (context_ntlm)context;
1689 /* NTLM requires a username & password. Domain may be empty */
1690 if (!domain || is_empty(username) || is_empty(password))
1691 return SIP_SEC_E_INTERNAL_ERROR;
1693 ctx->domain = g_strdup(domain);
1694 ctx->username = g_strdup(username);
1695 ctx->password = g_strdup(password);
1697 return SIP_SEC_E_OK;
1700 static sip_uint32
1701 sip_sec_init_sec_context__ntlm(SipSecContext context,
1702 SipSecBuffer in_buff,
1703 SipSecBuffer *out_buff,
1704 SIPE_UNUSED_PARAMETER const char *service_name)
1706 context_ntlm ctx = (context_ntlm) context;
1708 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
1710 ctx->step++;
1711 if (ctx->step == 1) {
1712 if (!context->is_connection_based) {
1713 out_buff->length = 0;
1714 out_buff->value = NULL;
1715 } else {
1716 sip_sec_ntlm_gen_negotiate(out_buff);
1718 return SIP_SEC_I_CONTINUE_NEEDED;
1720 } else {
1721 sip_uint32 res;
1722 guchar *client_sign_key = NULL;
1723 guchar *server_sign_key = NULL;
1724 guchar *client_seal_key = NULL;
1725 guchar *server_seal_key = NULL;
1726 guchar *server_challenge = NULL;
1727 guint64 time_val = 0;
1728 guchar *target_info = NULL;
1729 int target_info_len = 0;
1730 guint32 flags;
1731 gchar *tmp;
1733 if (!in_buff.value || !in_buff.length) {
1734 return SIP_SEC_E_INTERNAL_ERROR;
1737 sip_sec_ntlm_parse_challenge(in_buff,
1738 &flags,
1739 &server_challenge, /* 8 bytes */
1740 &time_val,
1741 &target_info,
1742 &target_info_len);
1744 res = sip_sec_ntlm_gen_authenticate(
1745 &client_sign_key,
1746 &server_sign_key,
1747 &client_seal_key,
1748 &server_seal_key,
1749 ctx->username,
1750 ctx->password,
1751 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1752 ctx->domain,
1753 server_challenge,
1754 time_val,
1755 target_info,
1756 target_info_len,
1757 context->is_connection_based,
1758 out_buff,
1759 &flags);
1760 g_free(server_challenge);
1761 g_free(target_info);
1762 g_free(tmp);
1764 if (res != SIP_SEC_E_OK) {
1765 g_free(client_sign_key);
1766 g_free(server_sign_key);
1767 g_free(client_seal_key);
1768 g_free(server_seal_key);
1769 return res;
1772 g_free(ctx->client_sign_key);
1773 ctx->client_sign_key = client_sign_key;
1775 g_free(ctx->server_sign_key);
1776 ctx->server_sign_key = server_sign_key;
1778 g_free(ctx->client_seal_key);
1779 ctx->client_seal_key = client_seal_key;
1781 g_free(ctx->server_seal_key);
1782 ctx->server_seal_key = server_seal_key;
1784 ctx->flags = flags;
1785 return SIP_SEC_E_OK;
1790 * @param message a NULL terminated string to sign
1793 static sip_uint32
1794 sip_sec_make_signature__ntlm(SipSecContext context,
1795 const char *message,
1796 SipSecBuffer *signature)
1798 signature->length = 16;
1799 signature->value = g_malloc0(16);
1801 /* FIXME? We always use a random_pad of 0 */
1802 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1803 message,
1805 ((context_ntlm) context)->client_sign_key,
1806 ((context_ntlm) context)->client_seal_key,
1807 /* SipSecBuffer.value is g_malloc()'d:
1808 * use (void *) to remove guint8 alignment
1810 (void *)signature->value);
1811 return SIP_SEC_E_OK;
1815 * @param message a NULL terminated string to check signature of
1816 * @return SIP_SEC_E_OK on success
1818 static sip_uint32
1819 sip_sec_verify_signature__ntlm(SipSecContext context,
1820 const char *message,
1821 SipSecBuffer signature)
1823 guint32 mac[4];
1824 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1825 guint32 random_pad = GUINT32_FROM_LE(((guint32 *)((void *)signature.value))[1]);
1827 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1828 message,
1829 random_pad,
1830 ((context_ntlm) context)->server_sign_key,
1831 ((context_ntlm) context)->server_seal_key,
1832 mac);
1833 return(memcmp(signature.value, mac, 16) ?
1834 SIP_SEC_E_INTERNAL_ERROR :
1835 SIP_SEC_E_OK);
1838 static void
1839 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1841 context_ntlm ctx = (context_ntlm) context;
1843 g_free(ctx->domain);
1844 g_free(ctx->username);
1845 g_free(ctx->password);
1846 g_free(ctx->client_sign_key);
1847 g_free(ctx->server_sign_key);
1848 g_free(ctx->client_seal_key);
1849 g_free(ctx->server_seal_key);
1850 g_free(ctx);
1853 SipSecContext
1854 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER guint type)
1856 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1857 if (!context) return(NULL);
1859 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1860 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1861 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1862 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1863 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1865 return((SipSecContext) context);
1868 void sip_sec_init__ntlm(void)
1870 #ifdef HAVE_LANGINFO_CODESET
1871 const char *sys_cp = nl_langinfo(CODESET);
1872 #else
1873 const char *sys_cp = SIPE_DEFAULT_CODESET;
1874 #endif /* HAVE_LANGINFO_CODESET */
1876 /* fall back to utf-8 */
1877 if (!sys_cp) sys_cp = "UTF-8";
1879 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1880 if (convert_from_utf16le == (GIConv)-1) {
1881 SIPE_DEBUG_ERROR("g_iconv_open from UTF-16LE to %s failed",
1882 sys_cp);
1885 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1886 if (convert_from_utf16le == (GIConv)-1) {
1887 SIPE_DEBUG_ERROR("g_iconv_open from %s to UTF-16LE failed",
1888 sys_cp);
1892 void sip_sec_destroy__ntlm(void)
1894 g_iconv_close(convert_to_utf16le);
1895 g_iconv_close(convert_from_utf16le);
1899 Local Variables:
1900 mode: c
1901 c-file-style: "bsd"
1902 indent-tabs-mode: t
1903 tab-width: 8
1904 End: