l10n: Updates to Portuguese (Brazilian) (pt_BR) translation
[siplcs.git] / src / core / sip-sec-ntlm.c
blob46509a691259f99e6cf53779db30c3f62a1c1df9
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2009, 2010 pier11 <pier11@operamail.com>
7 * Copyright (C) 2008 Novell, Inc.
8 * Modify 2007, Anibal Avelar <avelar@gmail.com>
9 * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
11 * Implemented with reference to the follow documentation:
12 * - http://davenport.sourceforge.net/ntlm.html
13 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
14 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * Byte order policy:
34 * - NTLM messages (byte streams) should be in LE (Little-Endian) byte order.
35 * - internal int16, int32, int64 should contain proper values.
36 * For example: 01 00 00 00 LE should be translated to (int32)1
37 * - When reading/writing from/to NTLM message appropriate conversion should
38 * be taken to properly present integer values. glib's "Byte Order Macros"
39 * should be used for that, for example GUINT32_FROM_LE
41 * NOTE: The Byte Order Macros can have side effects!
42 * Do *NOT* make any calculations inside the macros!
44 * - All calculations should be made in dedicated local variables (system-endian),
45 * not in NTLM (LE) structures.
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
52 #include <glib.h>
54 #ifdef HAVE_LANGINFO_CODESET
55 #include <langinfo.h>
56 #endif /* HAVE_LANGINFO_CODESET */
58 #include "sipe-common.h"
59 #include "sip-sec.h"
60 #include "sip-sec-mech.h"
61 #include "sip-sec-ntlm.h"
62 #include "sipe-backend.h"
63 #include "sipe-utils.h"
65 /* [MS-NLMP] */
66 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
67 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
68 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
69 #define r9 0x00000008 /* r9 */
70 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
71 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
72 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
73 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
74 #define r8 0x00000100 /* r8 */
75 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
76 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
77 #define anonymous 0x00000800 /* J */
78 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
79 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
80 #define r7 0x00004000 /* r7 */
81 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
82 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
83 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
84 #define r6 0x00040000 /* r6 */
85 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
86 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
87 #define r5 0x00200000 /* r5 */
88 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
89 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
90 #define r4 0x01000000 /* r4 */
91 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
92 #define r3 0x04000000 /* r3 */
93 #define r2 0x08000000 /* r2 */
94 #define r1 0x10000000 /* r1 */
95 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
96 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
97 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
99 /* AvId */
100 #define MsvAvEOL 0
101 #define MsvAvNbComputerName 1
102 #define MsvAvNbDomainName 2
103 #define MsvAvDnsComputerName 3
104 #define MsvAvDnsDomainName 4
105 /** @since Windows XP */
106 #define MsvAvDnsTreeName 5
107 /** @since Windows XP */
108 #define MsvAvFlags 6
109 /** @since Windows Vista */
110 #define MsvAvTimestamp 7
111 /** @since Windows Vista */
112 #define MsAvRestrictions 8
113 /** @since Windows 7 */
114 #define MsvAvTargetName 9
115 /** @since Windows 7 */
116 #define MsvChannelBindings 10
118 /* time_t <-> (guint64) time_val conversion */
119 #define TIME_VAL_FACTOR 10000000
120 #define TIME_VAL_OFFSET 116444736000000000LL
121 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
122 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
124 /* 8 bytes */
125 /* LE (Little Endian) byte order */
126 struct version {
127 guint8 product_major_version;
128 guint8 product_minor_version;
129 guint16 product_build;
130 guint8 zero2[3];
131 guint8 ntlm_revision_current;
135 * NTLMv1 is no longer used except in tests. R.I.P.
137 * It remains in this file only for documentary purposes
139 #ifdef _SIPE_COMPILING_TESTS
140 static gboolean use_ntlm_v2 = FALSE;
142 guint64 test_time_val = 0; /* actual time in implementation */
143 guchar test_client_challenge [8]; /* random in implementation */
144 guchar test_random_session_key[16]; /* random in implementation */
145 struct version test_version; /* hard-coded in implementation */
146 #endif
148 /* Minimum set of common features we need to work. */
149 /* we operate in NTLMv2 mode */
150 #define NEGOTIATE_FLAGS_COMMON_MIN \
151 ( NTLMSSP_NEGOTIATE_UNICODE | \
152 NTLMSSP_NEGOTIATE_NTLM | \
153 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
154 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
155 NTLMSSP_NEGOTIATE_TARGET_INFO \
158 /* Negotiate flags for connection-based mode. Nice to have but optional. */
159 #define NEGOTIATE_FLAGS_CONN \
160 ( NEGOTIATE_FLAGS_COMMON_MIN | \
161 NTLMSSP_NEGOTIATE_VERSION | \
162 NTLMSSP_NEGOTIATE_128 | \
163 NTLMSSP_NEGOTIATE_56 | \
164 NTLMSSP_REQUEST_TARGET \
167 /* Extra negotiate flags required in connectionless NTLM */
168 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
169 ( NTLMSSP_NEGOTIATE_SIGN | \
170 NTLMSSP_NEGOTIATE_DATAGRAM | \
171 NTLMSSP_NEGOTIATE_IDENTIFY | \
172 NTLMSSP_NEGOTIATE_KEY_EXCH \
175 /* Negotiate flags required in connectionless NTLM */
176 #define NEGOTIATE_FLAGS_CONNLESS \
177 ( NEGOTIATE_FLAGS_CONN | \
178 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
181 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
182 #define NTLMSSP_LM_RESP_LEN 24
183 #define NTLMSSP_SESSION_KEY_LEN 16
185 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
187 /* 4 bytes */
188 /* LE (Little Endian) byte order */
189 struct av_pair {
190 guint16 av_id;
191 guint16 av_len;
192 /* value */
195 /* to meet sparc's alignment requirement */
196 #define ALIGN_AV \
197 memcpy(&av_aligned, av, sizeof(av_aligned)); \
198 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
199 av_len = GUINT16_FROM_LE(av_aligned.av_len)
200 #define ALIGN_AV_LOOP_START \
201 struct av_pair av_aligned; \
202 guint16 av_id; \
203 guint16 av_len; \
204 ALIGN_AV; \
205 while (av_id != MsvAvEOL) { \
206 gchar *av_value = ((gchar *)av) + \
207 sizeof(struct av_pair); \
208 switch (av_id)
209 #define ALIGN_AV_LOOP_END \
210 av = av_value + av_len; \
211 ALIGN_AV; \
214 /* 8 bytes */
215 /* LE (Little Endian) byte order */
216 struct smb_header {
217 guint16 len;
218 guint16 maxlen;
219 guint32 offset;
222 /* LE (Little Endian) byte order */
223 struct ntlm_message {
224 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
225 guint32 type; /* 0x00000003 */
228 /* LE (Little Endian) byte order */
229 struct negotiate_message {
230 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
231 guint32 type; /* 0x00000001 */
232 guint32 flags; /* 0xb203 */
233 struct smb_header domain;
234 struct smb_header host;
235 struct version ver;
236 /* payload
237 * - DomainName (always ASCII)
238 * - WorkstationName (always ASCII)
242 /* LE (Little Endian) byte order */
243 struct challenge_message {
244 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
245 guint32 type; /* 0x00000002 */
246 struct smb_header target_name;
247 guint32 flags; /* 0x8201 */
248 guint8 nonce[8];
249 guint8 zero1[8];
250 struct smb_header target_info;
251 struct version ver;
252 /* payload
253 * - TargetName (negotiated encoding)
254 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
258 /* LE (Little Endian) byte order */
259 struct authenticate_message {
260 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
261 guint32 type; /* 0x00000003 */
262 /** LmChallengeResponseFields */
263 struct smb_header lm_resp;
264 /** NtChallengeResponseFields */
265 struct smb_header nt_resp;
266 /** DomainNameFields */
267 struct smb_header domain;
268 /** UserNameFields */
269 struct smb_header user;
270 /** WorkstationFields */
271 struct smb_header host;
272 /** EncryptedRandomSessionKeyFields */
273 struct smb_header session_key;
274 guint32 flags;
275 struct version ver;
276 //guint8 mic[16];
277 /* payload
278 * - LmChallengeResponse
279 * - NtChallengeResponse
280 * - DomainName (negotiated encoding)
281 * - UserName (negotiated encoding)
282 * - Workstation (negotiated encoding)
283 * - EncryptedRandomSessionKey
287 #ifndef HAVE_LANGINFO_CODESET
288 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
289 #endif
291 /* Private Methods */
293 /* Utility Functions */
294 static GIConv convert_from_utf16le = (GIConv)-1;
295 static GIConv convert_to_utf16le = (GIConv)-1;
297 static gsize
298 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
300 gsize inbytes = strlen(source);
301 gsize outbytes = remlen;
302 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
303 return(remlen - outbytes);
306 /* UTF-16LE to native encoding
307 * Must be g_free'd after use */
308 static gchar *
309 unicode_strconvcopy_back(const gchar *source, gsize len)
311 gsize outbytes = 2 * len;
312 gchar *dest = g_new0(gchar, outbytes + 1);
313 gchar *outbuf = dest;
314 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
315 return dest;
318 /* crc32 source copy from gg's common.c */
319 static guint32 crc32_table[256];
320 static int crc32_initialized = 0;
322 static void crc32_make_table()
324 guint32 h = 1;
325 unsigned int i, j;
327 memset(crc32_table, 0, sizeof(crc32_table));
329 for (i = 128; i; i >>= 1) {
330 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
332 for (j = 0; j < 256; j += 2 * i)
333 crc32_table[i + j] = crc32_table[j] ^ h;
336 crc32_initialized = 1;
339 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
341 if (!crc32_initialized)
342 crc32_make_table();
344 if (!buf || len < 0)
345 return crc;
347 crc ^= 0xffffffffL;
349 while (len--)
350 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
352 return crc ^ 0xffffffffL;
355 static guint32
356 CRC32 (const char *msg, int len)
358 guint32 crc = 0L;
359 crc = crc32(crc, (guint8 *) msg, len);
360 return crc;
363 /* Cyphers */
365 #ifdef _SIPE_COMPILING_TESTS
366 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
368 key[0] = key_56[0];
369 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
370 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
371 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
372 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
373 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
374 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
375 key[7] = (key_56[6] << 1) & 0xFF;
378 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
379 static void
380 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
382 unsigned char key[8];
383 setup_des_key(k, key);
384 sipe_backend_encrypt_des(key, d, 8, results);
387 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
388 static void
389 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
391 unsigned char keys[21];
393 /* Copy the first 16 bytes */
394 memcpy(keys, k, 16);
396 /* Zero out the last 5 bytes of the key */
397 memset(keys + 16, 0, 5);
399 DES(keys, d, results);
400 DES(keys + 7, d, results + 8);
401 DES(keys + 14, d, results + 16);
403 #endif
405 #define RC4K(key, key_len, plain, plain_len, encrypted) \
406 sipe_backend_encrypt_rc4((key), (key_len), (plain), (plain_len), (encrypted))
408 /* out 16 bytes */
409 #define MD4(d, len, result) sipe_backend_digest_md4((d), (len), (result))
411 /* out 16 bytes */
412 #define MD5(d, len, result) sipe_backend_digest_md5((d), (len), (result))
414 /* out 16 bytes */
416 static void
417 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
419 int i;
420 unsigned char ibuff[64 + data_len];
421 unsigned char obuff[64 + 16];
423 if (key_len > 64)
424 key_len = 64;
426 for (i = 0; i < key_len; i++) {
427 ibuff[i] = key[i] ^ 0x36;
428 obuff[i] = key[i] ^ 0x5c;
430 for (i = key_len; i < 64; i++) {
431 ibuff[i] = 0x36;
432 obuff[i] = 0x5c;
435 memcpy(ibuff+64, data, data_len);
437 MD5 (ibuff, 64 + data_len, obuff+64);
438 MD5 (obuff, 64 + 16, result);
440 #define HMAC_MD5 HMACT64
443 /* out 16 bytes */
444 #define HMAC_MD5(key, key_len, data, data_len, result) \
445 sipe_backend_digest_hmac_md5((key), (key_len), (data), (data_len), (result))
447 /* NTLM Core Methods */
449 static void
450 NONCE(unsigned char *buffer, int num)
452 int i;
453 for (i = 0; i < num; i++) {
454 buffer[i] = (rand() & 0xff);
458 #ifdef _SIPE_COMPILING_TESTS
459 static void
460 Z(unsigned char *buffer, int num)
462 memset(buffer, 0, num);
465 static void
466 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
468 /* "KGS!@#$%" */
469 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
470 unsigned char uppercase_password[14];
471 int i;
473 int len = strlen(password);
474 if (len > 14) {
475 len = 14;
478 // Uppercase password
479 for (i = 0; i < len; i++) {
480 uppercase_password[i] = g_ascii_toupper(password[i]);
483 // Zero the rest
484 for (; i < 14; i++) {
485 uppercase_password[i] = 0;
488 DES (uppercase_password, magic, result);
489 DES (uppercase_password + 7, magic, result + 8);
491 #endif
494 Define NTOWFv1(Passwd, User, UserDom) as
495 MD4(UNICODE(Passwd))
496 EndDefine
498 /* out 16 bytes */
499 static void
500 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
502 int len_u = 2 * strlen(password); // utf16 should not be more
503 unsigned char unicode_password[len_u];
505 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
506 MD4 (unicode_password, len_u, result);
510 Define NTOWFv2(Passwd, User, UserDom) as
511 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
512 EndDefine
514 /* out 16 bytes */
515 void
516 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
518 unsigned char response_key_nt_v1 [16];
519 int len_user = user ? strlen(user) : 0;
520 int len_domain = domain ? strlen(domain) : 0;
521 unsigned char user_upper[len_user + 1];
522 int len_user_u = 2 * len_user; // utf16 should not be more
523 int len_domain_u = 2 * len_domain; // utf16 should not be more
524 unsigned char buff[(len_user + len_domain)*2];
525 int i;
527 /* Uppercase user */
528 for (i = 0; i < len_user; i++) {
529 user_upper[i] = g_ascii_toupper(user[i]);
531 user_upper[len_user] = 0;
533 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
534 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
536 NTOWFv1(password, user, domain, response_key_nt_v1);
538 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
541 static void
542 compute_response(const guint32 neg_flags,
543 const unsigned char *response_key_nt,
544 const unsigned char *response_key_lm,
545 const guint8 *server_challenge,
546 const guint8 *client_challenge,
547 const guint64 time_val,
548 const guint8 *target_info,
549 int target_info_len,
550 unsigned char *lm_challenge_response,
551 unsigned char *nt_challenge_response,
552 unsigned char *session_base_key)
554 #ifdef _SIPE_COMPILING_TESTS
555 if (use_ntlm_v2)
557 #endif
559 Responserversion - The 1-byte response version. Currently set to 1.
560 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
561 Time - The 8-byte little-endian time in GMT.
562 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
563 ClientChallenge - The 8-byte challenge message generated by the client.
564 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
566 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
567 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
568 Time, //8bytes - 8
569 ClientChallenge, //8bytes - 16
570 Z(4), //4bytes - 24
571 ServerName, //variable - 28
572 Z(4)) //4bytes - 28+target_info_len
573 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
574 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
575 Set LmChallengeResponse to ConcatenationOf(
576 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
577 ClientChallenge )
578 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
579 EndDefine
581 guint8 tmp [16];
582 guint8 nt_proof_str [16];
584 /* client_challenge (8) & temp (temp_len) buff */
585 int temp_len = 8+8+8+4+target_info_len+4;
586 guint8 temp2 [8 + temp_len];
587 memset(temp2, 0, 8 + temp_len); /* init to 0 */
588 temp2[8+0] = 1;
589 temp2[8+1] = 1;
590 *((guint64 *)(temp2+8+8)) = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
591 memcpy(temp2+8+16, client_challenge, 8);
592 memcpy(temp2+8+28, target_info, target_info_len);
594 /* NTProofStr */
595 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
596 memcpy(temp2, server_challenge, 8);
597 HMAC_MD5(response_key_nt, 16, temp2, 8+temp_len, nt_proof_str);
599 /* NtChallengeResponse */
600 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
601 memcpy(nt_challenge_response, nt_proof_str, 16);
602 memcpy(nt_challenge_response+16, temp2+8, temp_len);
604 /* SessionBaseKey */
605 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
606 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
608 /* lm_challenge_response */
609 memcpy(tmp, server_challenge, 8);
610 memcpy(tmp+8, client_challenge, 8);
611 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
612 memcpy(lm_challenge_response+16, client_challenge, 8);
614 #ifndef _SIPE_COMPILING_TESTS
615 /* Not used in NTLMv2 */
616 (void)neg_flags;
617 #else
619 else
621 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
622 // @TODO do not even reference nt_challenge_response
623 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
624 DESL (response_key_lm, server_challenge, lm_challenge_response);
625 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
626 unsigned char prehash [16];
627 unsigned char hash [16];
629 /* nt_challenge_response */
630 memcpy(prehash, server_challenge, 8);
631 memcpy(prehash + 8, client_challenge, 8);
632 MD5 (prehash, 16, hash);
633 DESL (response_key_nt, hash, nt_challenge_response);
635 /* lm_challenge_response */
636 memcpy(lm_challenge_response, client_challenge, 8);
637 Z (lm_challenge_response+8, 16);
638 } else {
639 DESL (response_key_nt, server_challenge, nt_challenge_response);
640 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
641 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
642 } else {
643 DESL (response_key_lm, server_challenge, lm_challenge_response);
647 /* Session Key */
648 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
650 #endif
653 static void
654 KXKEY ( guint32 flags,
655 const unsigned char * session_base_key,
656 const unsigned char * lm_challenge_resonse,
657 const guint8 * server_challenge, /* 8-bytes, nonce */
658 unsigned char * key_exchange_key)
660 #ifdef _SIPE_COMPILING_TESTS
661 if (use_ntlm_v2)
663 #else
664 /* Not used in NTLMv2 */
665 (void)flags;
666 (void)lm_challenge_resonse;
667 (void)server_challenge;
668 #endif
669 memcpy(key_exchange_key, session_base_key, 16);
670 #ifdef _SIPE_COMPILING_TESTS
672 else
674 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
675 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
676 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
677 EndDefine
679 guint8 tmp[16];
680 memcpy(tmp, server_challenge, 8);
681 memcpy(tmp+8, lm_challenge_resonse, 8);
682 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
683 } else {
684 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
685 memcpy(key_exchange_key, session_base_key, 16);
688 #endif
692 If (Mode equals "Client")
693 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
694 "session key to client-to-server signing key magic constant"))
695 Else
696 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
697 "session key to server-to-client signing key magic constant"))
698 Endif
700 static void
701 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
703 char * magic = client
704 ? "session key to client-to-server signing key magic constant"
705 : "session key to server-to-client signing key magic constant";
707 int len = strlen(magic) + 1;
708 unsigned char md5_input [16 + len];
709 memcpy(md5_input, random_session_key, 16);
710 memcpy(md5_input + 16, magic, len);
712 MD5 (md5_input, len + 16, result);
716 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
717 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
718 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
719 Set SealKey to RandomSessionKey
720 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
721 Set SealKey to RandomSessionKey[0..6]
722 Else
723 Set SealKey to RandomSessionKey[0..4]
724 Endif
726 If (Mode equals "Client")
727 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
728 Else
729 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
730 Endif
732 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
733 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
734 Else
735 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
736 Endif
737 EndDefine
739 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
740 static void
741 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
743 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
745 char * magic = client
746 ? "session key to client-to-server sealing key magic constant"
747 : "session key to server-to-client sealing key magic constant";
749 int len = strlen(magic) + 1;
750 unsigned char md5_input [16 + len];
751 int key_len;
753 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
754 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
755 key_len = 16;
756 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
757 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
758 key_len = 7;
759 } else {
760 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
761 key_len = 5;
764 memcpy(md5_input, random_session_key, key_len);
765 memcpy(md5_input + key_len, magic, len);
767 MD5 (md5_input, key_len + len, result);
769 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
771 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
772 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
773 memcpy(result, random_session_key, 7);
774 result[7] = 0xA0;
775 } else {
776 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
777 memcpy(result, random_session_key, 5);
778 result[5] = 0xE5;
779 result[6] = 0x38;
780 result[7] = 0xB0;
783 else
785 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
786 memcpy(result, random_session_key, 16);
791 = for Extended Session Security =
792 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
793 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
794 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
796 = if Extended Session Security is NOT negotiated =
797 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
798 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
799 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
800 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
802 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
804 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
805 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
807 /** MAC(Handle, SigningKey, SeqNum, Message) */
808 /* out 16 bytes */
809 static void
810 MAC (guint32 flags,
811 const char *buf,
812 int buf_len,
813 unsigned char *sign_key,
814 unsigned long sign_key_len,
815 unsigned char *seal_key,
816 unsigned long seal_key_len,
817 guint32 random_pad,
818 guint32 sequence,
819 unsigned char *result)
821 guint32 *res_ptr;
823 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
825 Define MAC(Handle, SigningKey, SeqNum, Message) as
826 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
827 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
828 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
829 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
830 Set SeqNum to SeqNum + 1
831 EndDefine
833 /* If a key exchange key is negotiated
834 Define MAC(Handle, SigningKey, SeqNum, Message) as
835 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
836 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
837 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
838 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
839 Set SeqNum to SeqNum + 1
840 EndDefine
843 unsigned char seal_key_ [16];
844 guchar hmac[16];
845 guchar tmp[4 + buf_len];
847 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
848 RC4Init(Handle, SealingKey')
850 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
851 unsigned char tmp2 [16+4];
853 memcpy(tmp2, seal_key, seal_key_len);
854 *((guint32 *)(tmp2+16)) = GUINT32_TO_LE(sequence);
855 MD5 (tmp2, 16+4, seal_key_);
856 } else {
857 memcpy(seal_key_, seal_key, seal_key_len);
860 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extented Session Security");
862 res_ptr = (guint32 *)result;
863 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
864 res_ptr[3] = GUINT32_TO_LE(sequence);
866 res_ptr = (guint32 *)tmp;
867 res_ptr[0] = GUINT32_TO_LE(sequence);
868 memcpy(tmp+4, buf, buf_len);
870 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
872 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
873 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
874 RC4K(seal_key_, seal_key_len, hmac, 8, result+4);
875 } else {
876 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
877 memcpy(result+4, hmac, 8);
879 } else {
880 /* The content of the first 4 bytes is irrelevant */
881 guint32 crc = CRC32(buf, strlen(buf));
882 guint32 plaintext [] = {
883 GUINT32_TO_LE(0),
884 GUINT32_TO_LE(crc),
885 GUINT32_TO_LE(sequence)
886 }; // 4, 4, 4 bytes
888 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extented Session Security");
890 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, result+4);
892 res_ptr = (guint32 *)result;
893 // Highest four bytes are the Version
894 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
896 // Replace the first four bytes of the ciphertext with the random_pad
897 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
901 /* End Core NTLM Methods */
904 * @param flags (out) flags received from server
905 * @param server_challenge must be g_free()'d after use if requested
906 * @param target_info must be g_free()'d after use if requested
908 static void
909 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
910 guint32 *flags,
911 guchar **server_challenge, /* 8 bytes */
912 guint64 *time_val,
913 guchar **target_info,
914 int *target_info_len)
916 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
917 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
919 /* server challenge (nonce) */
920 if (server_challenge) {
921 *server_challenge = g_memdup(cmsg->nonce, 8);
924 /* flags */
925 if (flags) {
926 *flags = host_flags;
929 /* target_info */
930 if (cmsg->target_info.len && cmsg->target_info.offset) {
931 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
932 void *av = content;
933 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
935 ALIGN_AV_LOOP_START
937 /* @since Vista */
938 case MsvAvTimestamp:
939 if (time_val) {
940 guint64 tmp;
942 /* to meet sparc's alignment requirement */
943 memcpy(&tmp, av_value, sizeof(tmp));
944 *time_val = GUINT64_FROM_LE(tmp);
946 break;
948 ALIGN_AV_LOOP_END;
950 if (target_info_len) {
951 *target_info_len = len;
953 if (target_info) {
954 *target_info = g_memdup(content, len);
960 * @param client_sign_key (out) must be g_free()'d after use
961 * @param server_sign_key (out) must be g_free()'d after use
962 * @param client_seal_key (out) must be g_free()'d after use
963 * @param server_seal_key (out) must be g_free()'d after use
964 * @param flags (in, out) negotiated flags
966 static sip_uint32
967 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
968 guchar **server_sign_key,
969 guchar **client_seal_key,
970 guchar **server_seal_key,
971 const gchar *user,
972 const gchar *password,
973 const gchar *hostname,
974 const gchar *domain,
975 const guint8 *server_challenge, /* nonce */
976 const guint64 time_val,
977 const guint8 *target_info,
978 int target_info_len,
979 gboolean is_connection_based,
980 SipSecBuffer *out_buff,
981 guint32 *flags)
983 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
984 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
985 int ntlmssp_nt_resp_len =
986 #ifdef _SIPE_COMPILING_TESTS
987 use_ntlm_v2 ?
988 #endif
989 (16 + (32+target_info_len))
990 #ifdef _SIPE_COMPILING_TESTS
991 : NTLMSSP_LM_RESP_LEN
992 #endif
994 gsize msglen = sizeof(struct authenticate_message)
995 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
996 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
997 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
998 struct authenticate_message *tmsg;
999 char *tmp;
1000 guint32 offset;
1001 guint16 len;
1002 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1003 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1004 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1005 unsigned char nt_challenge_response [ntlmssp_nt_resp_len]; /* variable or 24 */
1006 unsigned char session_base_key [16];
1007 unsigned char key_exchange_key [16];
1008 unsigned char exported_session_key[16];
1009 unsigned char encrypted_random_session_key [16];
1010 unsigned char key [16];
1011 unsigned char client_challenge [8];
1012 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1014 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1015 !(is_connection_based || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)))
1017 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1018 return SIP_SEC_E_INTERNAL_ERROR;
1021 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1022 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1025 tmsg = g_malloc0(msglen);
1027 NONCE (client_challenge, 8);
1029 #ifdef _SIPE_COMPILING_TESTS
1030 memcpy(client_challenge, test_client_challenge, 8);
1031 time_vl = test_time_val ? test_time_val : time_vl;
1033 if (use_ntlm_v2) {
1035 #endif
1036 NTOWFv2 (password, user, domain, response_key_nt);
1037 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1038 #ifdef _SIPE_COMPILING_TESTS
1039 } else {
1040 NTOWFv1 (password, user, domain, response_key_nt);
1041 LMOWFv1 (password, user, domain, response_key_lm);
1043 #endif
1045 compute_response(neg_flags,
1046 response_key_nt,
1047 response_key_lm,
1048 server_challenge,
1049 client_challenge,
1050 time_vl,
1051 target_info,
1052 target_info_len,
1053 lm_challenge_response, /* out */
1054 nt_challenge_response, /* out */
1055 session_base_key); /* out */
1057 /* same as session_base_key for
1058 * - NTLNv1 w/o Ext.Sess.Sec and
1059 * - NTLMv2
1061 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1063 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1064 NONCE (exported_session_key, 16); // random master key
1065 #ifdef _SIPE_COMPILING_TESTS
1066 memcpy(exported_session_key, test_random_session_key, 16);
1067 #endif
1068 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1069 } else {
1070 memcpy(exported_session_key, key_exchange_key, 16);
1073 tmp = buff_to_hex_str(exported_session_key, 16);
1074 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp);
1075 g_free(tmp);
1077 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1078 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1080 /* p.46
1081 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1082 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1084 SIGNKEY(exported_session_key, TRUE, key);
1085 *client_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1086 SIGNKEY(exported_session_key, FALSE, key);
1087 *server_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1088 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1089 *client_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1090 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1091 *server_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1094 /* @TODO: */
1095 /* @since Vista
1096 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1097 the client SHOULD provide a MIC:
1098 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1099 - then in the Value field, set bit 0x2 to 1.
1100 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1101 and the Value field bit 0x2 to 1.
1102 - Populate the MIC field with the MIC.
1105 /* Connection-oriented:
1106 Set MIC to HMAC_MD5(ExportedSessionKey,
1107 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1108 Connectionless:
1109 Set MIC to HMAC_MD5(ExportedSessionKey,
1110 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1113 /* on the server-side:
1114 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1115 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1116 Set MIC to HMAC_MD5(ExportedSessionKey,
1117 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1118 Else
1119 Set ExportedSessionKey to KeyExchangeKey
1120 Set MIC to HMAC_MD5(KeyExchangeKey,
1121 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1122 =====
1123 @since Vista
1124 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1125 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1126 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1127 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1128 an AV_PAIR structure whose two fields:
1129 - AvId == MsvAvFlags
1130 - Value bit 0x2 == 1
1131 @supported NT, 2000, XP
1132 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1133 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1134 the server time, then the server SHOULD return a failure.
1136 Connectionless:
1137 Set MIC to HMAC_MD5(ResponseKeyNT,
1138 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1141 /* authenticate message initialization */
1142 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1143 tmsg->type = GUINT32_TO_LE(3);
1145 /* Initial offset */
1146 offset = sizeof(struct authenticate_message);
1147 tmp = ((char*) tmsg) + offset;
1149 #define _FILL_SMB_HEADER(header) \
1150 tmsg->header.offset = GUINT32_TO_LE(offset); \
1151 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1152 tmp += len; \
1153 offset += len
1154 #define _APPEND_STRING(header, src) \
1155 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1156 _FILL_SMB_HEADER(header)
1157 #define _APPEND_DATA(header, src, srclen) \
1158 len = (srclen); \
1159 memcpy(tmp, (src), len); \
1160 _FILL_SMB_HEADER(header)
1162 /* Domain */
1163 _APPEND_STRING(domain, domain);
1165 /* User */
1166 _APPEND_STRING(user, user);
1168 /* Host */
1169 _APPEND_STRING(host, hostname);
1171 /* LM */
1172 /* @since Windows 7
1173 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1174 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1175 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1177 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1179 /* NT */
1180 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1182 /* Session Key */
1183 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1185 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1187 else
1189 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1190 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1193 /* Version */
1194 #ifdef _SIPE_COMPILING_TESTS
1195 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1196 #else
1197 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1198 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1199 tmsg->ver.product_minor_version = 1;
1200 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1201 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1203 #endif
1205 /* Set Negotiate Flags */
1206 tmsg->flags = GUINT32_TO_LE(neg_flags);
1207 *flags = neg_flags;
1209 out_buff->value = (guint8 *)tmsg;
1210 out_buff->length = msglen;
1212 return SIP_SEC_E_OK;
1216 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1218 static void
1219 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1221 guint32 offset;
1222 guint16 len;
1223 int msglen = sizeof(struct negotiate_message);
1224 struct negotiate_message *tmsg = g_malloc0(msglen);
1226 /* negotiate message initialization */
1227 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1228 tmsg->type = GUINT32_TO_LE(1);
1230 /* Set Negotiate Flags */
1231 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1233 /* Domain */
1234 offset = sizeof(struct negotiate_message);
1235 tmsg->domain.offset = GUINT32_TO_LE(offset);
1236 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1238 /* Host */
1239 offset += len;
1240 tmsg->host.offset = GUINT32_TO_LE(offset);
1241 tmsg->host.len = tmsg->host.maxlen = len = 0;
1243 /* Version */
1244 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1245 tmsg->ver.product_minor_version = 1;
1246 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1247 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1249 out_buff->value = (guint8 *)tmsg;
1250 out_buff->length = msglen;
1253 static void
1254 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1255 const char *msg,
1256 guint32 random_pad,
1257 unsigned char *sign_key,
1258 unsigned char *seal_key,
1259 unsigned char *result)
1261 char *res;
1263 MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100, result);
1265 res = buff_to_hex_str(result, 16);
1266 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res);
1267 g_free(res);
1271 /* Describe NTLM messages functions */
1273 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1274 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1276 static gchar *
1277 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1279 GString* str = g_string_new(NULL);
1281 flags = GUINT32_FROM_LE(flags);
1283 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1284 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1285 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1286 APPEND_NEG_FLAG(str, flags, r9, "r9");
1287 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1288 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1289 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1290 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1291 APPEND_NEG_FLAG(str, flags, r8, "r8");
1292 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1293 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1294 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1295 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1296 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1297 APPEND_NEG_FLAG(str, flags, r7, "r7");
1298 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1299 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1300 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1301 APPEND_NEG_FLAG(str, flags, r6, "r6");
1302 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1303 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1304 APPEND_NEG_FLAG(str, flags, r5, "r5");
1305 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1306 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1307 APPEND_NEG_FLAG(str, flags, r4, "r4");
1308 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1309 APPEND_NEG_FLAG(str, flags, r3, "r3");
1310 APPEND_NEG_FLAG(str, flags, r2, "r2");
1311 APPEND_NEG_FLAG(str, flags, r1, "r1");
1312 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1313 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1314 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1316 return g_string_free(str, FALSE);
1319 static gchar *
1320 sip_sec_ntlm_describe_version(struct version *ver) {
1321 GString* str = g_string_new(NULL);
1322 gchar *ver_desc = "";
1323 gchar *ntlm_revision_desc = "";
1325 if (ver->product_major_version == 6) {
1326 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1327 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1328 ver_desc = "Windows Server 2003";
1329 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1330 ver_desc = "Windows XP SP2";
1333 if (ver->ntlm_revision_current == 0x0F) {
1334 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1335 } else if (ver->ntlm_revision_current == 0x0A) {
1336 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1339 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1340 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1341 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1343 return g_string_free(str, FALSE);
1346 static gchar *
1347 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1348 const char* name)
1350 GString* str = g_string_new(NULL);
1352 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1353 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1354 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1356 return g_string_free(str, FALSE);
1359 static gchar *
1360 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1362 GString* str = g_string_new(NULL);
1363 char *tmp;
1365 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1366 g_free(tmp);
1368 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1369 g_free(tmp);
1371 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1372 g_free(tmp);
1374 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1375 g_string_append(str, tmp);
1376 g_free(tmp);
1378 if (cmsg->domain.len && cmsg->domain.offset) {
1379 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1380 g_string_append_printf(str, "\tdomain: %s\n", domain);
1381 g_free(domain);
1384 if (cmsg->host.len && cmsg->host.offset) {
1385 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1386 g_string_append_printf(str, "\thost: %s\n", host);
1387 g_free(host);
1390 return g_string_free(str, FALSE);
1393 static void
1394 describe_av_pairs(GString* str, const void *av)
1396 #define AV_DESC(av_name) \
1398 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1399 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1400 g_free(tmp); \
1403 ALIGN_AV_LOOP_START
1405 case MsvAvNbComputerName:
1406 AV_DESC("MsvAvNbComputerName");
1407 break;
1408 case MsvAvNbDomainName:
1409 AV_DESC("MsvAvNbDomainName");
1410 break;
1411 case MsvAvDnsComputerName:
1412 AV_DESC("MsvAvDnsComputerName");
1413 break;
1414 case MsvAvDnsDomainName:
1415 AV_DESC("MsvAvDnsDomainName");
1416 break;
1417 case MsvAvDnsTreeName:
1418 AV_DESC("MsvAvDnsTreeName");
1419 break;
1420 case MsvAvFlags:
1422 guint32 flags;
1424 /* to meet sparc's alignment requirement */
1425 memcpy(&flags, av_value, sizeof(guint32));
1426 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1428 break;
1429 case MsvAvTimestamp:
1431 char *tmp;
1432 guint64 time_val;
1433 time_t time_t_val;
1435 /* to meet sparc's alignment requirement */
1436 memcpy(&time_val, av_value, sizeof(time_val));
1437 time_t_val = TIME_VAL_TO_T(time_val);
1439 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1440 asctime(gmtime(&time_t_val)));
1441 g_free(tmp);
1443 break;
1444 case MsAvRestrictions:
1445 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1446 break;
1447 case MsvAvTargetName:
1448 AV_DESC("MsvAvTargetName");
1449 break;
1450 case MsvChannelBindings:
1451 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1452 break;
1454 ALIGN_AV_LOOP_END;
1457 static gchar *
1458 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1460 GString* str = g_string_new(NULL);
1461 char *tmp;
1462 gsize value_len;
1463 guint8 *value;
1465 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1466 g_free(tmp);
1468 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1469 g_free(tmp);
1471 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1472 g_free(tmp);
1474 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1475 g_free(tmp);
1477 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1478 g_free(tmp);
1480 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1481 g_free(tmp);
1483 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1484 g_free(tmp);
1486 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1487 g_string_append(str, tmp);
1488 g_free(tmp);
1490 /* mic */
1491 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1492 //g_free(tmp);
1494 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1495 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1496 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1497 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1498 g_free(tmp);
1501 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1502 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1503 int nt_resp_len = nt_resp_len_full;
1505 value_len = nt_resp_len_full;
1506 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1507 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1508 g_free(tmp);
1510 if (nt_resp_len > 24) { /* NTLMv2 */
1511 nt_resp_len = 16;
1514 value_len = nt_resp_len;
1515 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1516 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1517 g_free(tmp);
1519 if (nt_resp_len_full > 24) { /* NTLMv2 */
1520 /* Work around Debian/x86_64 compiler bug */
1521 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1522 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1523 const guint8 *temp = (guint8 *)cmsg + offset;
1524 const guint response_version = temp[0];
1525 const guint hi_response_version = temp[1];
1526 const guint8 *client_challenge = temp + 16;
1527 const guint8 *target_info = temp + 28;
1528 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1529 guint64 time_val;
1530 time_t time_t_val;
1531 char *tmp;
1533 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1534 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1535 g_free(tmp);
1537 /* This is not int64 aligned on sparc */
1538 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1539 time_t_val = TIME_VAL_TO_T(time_val);
1541 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1542 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1544 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1545 asctime(gmtime(&time_t_val)));
1546 g_free(tmp);
1548 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1549 g_free(tmp);
1551 describe_av_pairs(str, target_info);
1553 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1557 if (cmsg->domain.len && cmsg->domain.offset) {
1558 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1559 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1560 g_free(domain);
1563 if (cmsg->user.len && cmsg->user.offset) {
1564 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1565 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1566 g_free(user);
1569 if (cmsg->host.len && cmsg->host.offset) {
1570 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1571 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1572 g_free(host);
1575 if (cmsg->session_key.len && cmsg->session_key.offset) {
1576 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1577 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1578 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1579 g_free(tmp);
1582 return g_string_free(str, FALSE);
1585 static gchar *
1586 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1588 GString* str = g_string_new(NULL);
1589 char *tmp;
1591 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1592 g_free(tmp);
1594 /* nonce (server_challenge) */
1595 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1596 g_free(tmp);
1598 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1599 g_free(tmp);
1601 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1602 g_free(tmp);
1604 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1605 g_free(tmp);
1607 if (cmsg->target_name.len && cmsg->target_name.offset) {
1608 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1609 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1610 g_free(target_name);
1613 if (cmsg->target_info.len && cmsg->target_info.offset) {
1614 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1615 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1617 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1618 g_free(tmp);
1620 describe_av_pairs(str, target_info);
1623 return g_string_free(str, FALSE);
1626 gchar *
1627 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1629 struct ntlm_message *msg;
1630 gchar *res = NULL;
1632 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1634 msg = (struct ntlm_message *)buff.value;
1635 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1637 switch (GUINT32_FROM_LE(msg->type)) {
1638 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1639 break;
1640 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1641 break;
1642 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1643 break;
1646 return res;
1649 /* sip-sec-mech.h API implementation for NTLM */
1651 /* Security context for NTLM */
1652 typedef struct _context_ntlm {
1653 struct sip_sec_context common;
1654 char* domain;
1655 char *username;
1656 char *password;
1657 int step;
1658 guchar *client_sign_key;
1659 guchar *server_sign_key;
1660 guchar *client_seal_key;
1661 guchar *server_seal_key;
1662 guint32 flags;
1663 } *context_ntlm;
1666 static sip_uint32
1667 sip_sec_acquire_cred__ntlm(SipSecContext context,
1668 const char *domain,
1669 const char *username,
1670 const char *password)
1672 context_ntlm ctx = (context_ntlm)context;
1674 /* NTLM requires a domain, username & password */
1675 if (!domain || !username || !password)
1676 return SIP_SEC_E_INTERNAL_ERROR;
1678 ctx->domain = g_strdup(domain);
1679 ctx->username = g_strdup(username);
1680 ctx->password = g_strdup(password);
1682 return SIP_SEC_E_OK;
1685 static sip_uint32
1686 sip_sec_init_sec_context__ntlm(SipSecContext context,
1687 SipSecBuffer in_buff,
1688 SipSecBuffer *out_buff,
1689 SIPE_UNUSED_PARAMETER const char *service_name)
1691 context_ntlm ctx = (context_ntlm) context;
1693 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
1695 ctx->step++;
1696 if (ctx->step == 1) {
1697 if (!context->is_connection_based) {
1698 out_buff->length = 0;
1699 out_buff->value = NULL;
1700 } else {
1701 sip_sec_ntlm_gen_negotiate(out_buff);
1703 return SIP_SEC_I_CONTINUE_NEEDED;
1705 } else {
1706 sip_uint32 res;
1707 guchar *client_sign_key = NULL;
1708 guchar *server_sign_key = NULL;
1709 guchar *client_seal_key = NULL;
1710 guchar *server_seal_key = NULL;
1711 guchar *server_challenge = NULL;
1712 guint64 time_val = 0;
1713 guchar *target_info = NULL;
1714 int target_info_len = 0;
1715 guint32 flags;
1716 gchar *tmp;
1718 if (!in_buff.value || !in_buff.length) {
1719 return SIP_SEC_E_INTERNAL_ERROR;
1722 sip_sec_ntlm_parse_challenge(in_buff,
1723 &flags,
1724 &server_challenge, /* 8 bytes */
1725 &time_val,
1726 &target_info,
1727 &target_info_len);
1729 res = sip_sec_ntlm_gen_authenticate(
1730 &client_sign_key,
1731 &server_sign_key,
1732 &client_seal_key,
1733 &server_seal_key,
1734 ctx->username,
1735 ctx->password,
1736 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1737 ctx->domain,
1738 server_challenge,
1739 time_val,
1740 target_info,
1741 target_info_len,
1742 context->is_connection_based,
1743 out_buff,
1744 &flags);
1745 g_free(server_challenge);
1746 g_free(target_info);
1747 g_free(tmp);
1749 if (res != SIP_SEC_E_OK) {
1750 g_free(client_sign_key);
1751 g_free(server_sign_key);
1752 g_free(client_seal_key);
1753 g_free(server_seal_key);
1754 return res;
1757 g_free(ctx->client_sign_key);
1758 ctx->client_sign_key = client_sign_key;
1760 g_free(ctx->server_sign_key);
1761 ctx->server_sign_key = server_sign_key;
1763 g_free(ctx->client_seal_key);
1764 ctx->client_seal_key = client_seal_key;
1766 g_free(ctx->server_seal_key);
1767 ctx->server_seal_key = server_seal_key;
1769 ctx->flags = flags;
1770 return SIP_SEC_E_OK;
1775 * @param message a NULL terminated string to sign
1778 static sip_uint32
1779 sip_sec_make_signature__ntlm(SipSecContext context,
1780 const char *message,
1781 SipSecBuffer *signature)
1783 signature->length = 16;
1784 signature->value = g_malloc0(16);
1786 /* FIXME? We always use a random_pad of 0 */
1787 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1788 message,
1790 ((context_ntlm) context)->client_sign_key,
1791 ((context_ntlm) context)->client_seal_key,
1792 signature->value);
1793 return SIP_SEC_E_OK;
1797 * @param message a NULL terminated string to check signature of
1798 * @return SIP_SEC_E_OK on success
1800 static sip_uint32
1801 sip_sec_verify_signature__ntlm(SipSecContext context,
1802 const char *message,
1803 SipSecBuffer signature)
1805 guint8 mac[16];
1806 guint32 random_pad = GUINT32_FROM_LE(((guint32 *) signature.value)[1]);
1808 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1809 message,
1810 random_pad,
1811 ((context_ntlm) context)->server_sign_key,
1812 ((context_ntlm) context)->server_seal_key,
1813 mac);
1814 return(memcmp(signature.value, mac, 16) ?
1815 SIP_SEC_E_INTERNAL_ERROR :
1816 SIP_SEC_E_OK);
1819 static void
1820 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1822 context_ntlm ctx = (context_ntlm) context;
1824 g_free(ctx->domain);
1825 g_free(ctx->username);
1826 g_free(ctx->password);
1827 g_free(ctx->client_sign_key);
1828 g_free(ctx->server_sign_key);
1829 g_free(ctx->client_seal_key);
1830 g_free(ctx->server_seal_key);
1831 g_free(ctx);
1834 SipSecContext
1835 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1837 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1838 if (!context) return(NULL);
1840 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1841 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1842 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1843 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1844 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1846 return((SipSecContext) context);
1849 void sip_sec_init__ntlm(void)
1851 #ifdef HAVE_LANGINFO_CODESET
1852 const char *sys_cp = nl_langinfo(CODESET);
1853 #else
1854 const char *sys_cp = SIPE_DEFAULT_CODESET;
1855 #endif /* HAVE_LANGINFO_CODESET */
1857 /* fall back to utf-8 */
1858 if (!sys_cp) sys_cp = "UTF-8";
1860 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1861 if (convert_from_utf16le == (GIConv)-1) {
1862 SIPE_DEBUG_ERROR("g_iconv_open from UTF-16LE to %s failed",
1863 sys_cp);
1866 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1867 if (convert_from_utf16le == (GIConv)-1) {
1868 SIPE_DEBUG_ERROR("g_iconv_open from %s to UTF-16LE failed",
1869 sys_cp);
1873 void sip_sec_destroy__ntlm(void)
1875 g_iconv_close(convert_to_utf16le);
1876 g_iconv_close(convert_from_utf16le);
1880 Local Variables:
1881 mode: c
1882 c-file-style: "bsd"
1883 indent-tabs-mode: t
1884 tab-width: 8
1885 End: