Fix #3148124: sipe segfaults during login on Solaris
[siplcs.git] / src / core / sip-sec-ntlm.c
blob114a107f8f9c45832254e8038a645c5af4554a78
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 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
53 #include <stdlib.h>
54 #include <string.h>
55 #include <time.h>
57 #include <glib.h>
59 #ifdef HAVE_LANGINFO_CODESET
60 #include <langinfo.h>
61 #endif /* HAVE_LANGINFO_CODESET */
63 #include "sipe-common.h"
64 #include "sip-sec.h"
65 #include "sip-sec-mech.h"
66 #include "sip-sec-ntlm.h"
67 #include "sipe-backend.h"
68 #include "sipe-crypt.h"
69 #include "sipe-digest.h"
70 #include "sipe-utils.h"
72 /* [MS-NLMP] */
73 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
74 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
75 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
76 #define r9 0x00000008 /* r9 */
77 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
78 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
79 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
80 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
81 #define r8 0x00000100 /* r8 */
82 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
83 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
84 #define anonymous 0x00000800 /* J */
85 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
86 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
87 #define r7 0x00004000 /* r7 */
88 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
89 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
90 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
91 #define r6 0x00040000 /* r6 */
92 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
93 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
94 #define r5 0x00200000 /* r5 */
95 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
96 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
97 #define r4 0x01000000 /* r4 */
98 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
99 #define r3 0x04000000 /* r3 */
100 #define r2 0x08000000 /* r2 */
101 #define r1 0x10000000 /* r1 */
102 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
103 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
104 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
106 /* AvId */
107 #define MsvAvEOL 0
108 #define MsvAvNbComputerName 1
109 #define MsvAvNbDomainName 2
110 #define MsvAvDnsComputerName 3
111 #define MsvAvDnsDomainName 4
112 /** @since Windows XP */
113 #define MsvAvDnsTreeName 5
114 /** @since Windows XP */
115 #define MsvAvFlags 6
116 /** @since Windows Vista */
117 #define MsvAvTimestamp 7
118 /** @since Windows Vista */
119 #define MsAvRestrictions 8
120 /** @since Windows 7 */
121 #define MsvAvTargetName 9
122 /** @since Windows 7 */
123 #define MsvChannelBindings 10
125 /* time_t <-> (guint64) time_val conversion */
126 #define TIME_VAL_FACTOR 10000000
127 #define TIME_VAL_OFFSET 116444736000000000LL
128 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
129 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
131 /* 8 bytes */
132 /* LE (Little Endian) byte order */
133 struct version {
134 guint8 product_major_version;
135 guint8 product_minor_version;
136 guint16 product_build;
137 guint8 zero2[3];
138 guint8 ntlm_revision_current;
142 * NTLMv1 is no longer used except in tests. R.I.P.
144 * It remains in this file only for documentary purposes
146 #ifdef _SIPE_COMPILING_TESTS
147 static gboolean use_ntlm_v2 = FALSE;
149 guint64 test_time_val = 0; /* actual time in implementation */
150 guchar test_client_challenge [8]; /* random in implementation */
151 guchar test_random_session_key[16]; /* random in implementation */
152 struct version test_version; /* hard-coded in implementation */
153 #endif
155 /* Minimum set of common features we need to work. */
156 /* we operate in NTLMv2 mode */
157 #define NEGOTIATE_FLAGS_COMMON_MIN \
158 ( NTLMSSP_NEGOTIATE_UNICODE | \
159 NTLMSSP_NEGOTIATE_NTLM | \
160 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
161 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
162 NTLMSSP_NEGOTIATE_TARGET_INFO \
165 /* Negotiate flags for connection-based mode. Nice to have but optional. */
166 #define NEGOTIATE_FLAGS_CONN \
167 ( NEGOTIATE_FLAGS_COMMON_MIN | \
168 NTLMSSP_NEGOTIATE_VERSION | \
169 NTLMSSP_NEGOTIATE_128 | \
170 NTLMSSP_NEGOTIATE_56 | \
171 NTLMSSP_REQUEST_TARGET \
174 /* Extra negotiate flags required in connectionless NTLM */
175 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
176 ( NTLMSSP_NEGOTIATE_SIGN | \
177 NTLMSSP_NEGOTIATE_DATAGRAM | \
178 NTLMSSP_NEGOTIATE_IDENTIFY | \
179 NTLMSSP_NEGOTIATE_KEY_EXCH \
182 /* Negotiate flags required in connectionless NTLM */
183 #define NEGOTIATE_FLAGS_CONNLESS \
184 ( NEGOTIATE_FLAGS_CONN | \
185 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
188 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
189 #define NTLMSSP_LM_RESP_LEN 24
190 #define NTLMSSP_SESSION_KEY_LEN 16
192 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
194 /* 4 bytes */
195 /* LE (Little Endian) byte order */
196 struct av_pair {
197 guint16 av_id;
198 guint16 av_len;
199 /* value */
202 /* to meet sparc's alignment requirement */
203 #define ALIGN_AV \
204 memcpy(&av_aligned, av, sizeof(av_aligned)); \
205 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
206 av_len = GUINT16_FROM_LE(av_aligned.av_len)
207 #define ALIGN_AV_LOOP_START \
208 struct av_pair av_aligned; \
209 guint16 av_id; \
210 guint16 av_len; \
211 ALIGN_AV; \
212 while (av_id != MsvAvEOL) { \
213 gchar *av_value = ((gchar *)av) + \
214 sizeof(struct av_pair); \
215 switch (av_id)
216 #define ALIGN_AV_LOOP_END \
217 av = av_value + av_len; \
218 ALIGN_AV; \
221 /* 8 bytes */
222 /* LE (Little Endian) byte order */
223 struct smb_header {
224 guint16 len;
225 guint16 maxlen;
226 guint32 offset;
229 /* LE (Little Endian) byte order */
230 struct ntlm_message {
231 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
232 guint32 type; /* 0x00000003 */
235 /* LE (Little Endian) byte order */
236 struct negotiate_message {
237 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
238 guint32 type; /* 0x00000001 */
239 guint32 flags; /* 0xb203 */
240 struct smb_header domain;
241 struct smb_header host;
242 struct version ver;
243 /* payload
244 * - DomainName (always ASCII)
245 * - WorkstationName (always ASCII)
249 /* LE (Little Endian) byte order */
250 struct challenge_message {
251 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
252 guint32 type; /* 0x00000002 */
253 struct smb_header target_name;
254 guint32 flags; /* 0x8201 */
255 guint8 nonce[8];
256 guint8 zero1[8];
257 struct smb_header target_info;
258 struct version ver;
259 /* payload
260 * - TargetName (negotiated encoding)
261 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
265 /* LE (Little Endian) byte order */
266 struct authenticate_message {
267 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
268 guint32 type; /* 0x00000003 */
269 /** LmChallengeResponseFields */
270 struct smb_header lm_resp;
271 /** NtChallengeResponseFields */
272 struct smb_header nt_resp;
273 /** DomainNameFields */
274 struct smb_header domain;
275 /** UserNameFields */
276 struct smb_header user;
277 /** WorkstationFields */
278 struct smb_header host;
279 /** EncryptedRandomSessionKeyFields */
280 struct smb_header session_key;
281 guint32 flags;
282 struct version ver;
283 //guint8 mic[16];
284 /* payload
285 * - LmChallengeResponse
286 * - NtChallengeResponse
287 * - DomainName (negotiated encoding)
288 * - UserName (negotiated encoding)
289 * - Workstation (negotiated encoding)
290 * - EncryptedRandomSessionKey
294 #ifndef HAVE_LANGINFO_CODESET
295 #ifdef __sun__
296 static char SIPE_DEFAULT_CODESET[] = "US-ASCII";
297 #else
298 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
299 #endif
300 #endif
302 /* Private Methods */
304 /* Utility Functions */
305 static GIConv convert_from_utf16le = (GIConv)-1;
306 static GIConv convert_to_utf16le = (GIConv)-1;
308 static gsize
309 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
311 gsize inbytes = strlen(source);
312 gsize outbytes = remlen;
313 if (remlen)
314 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
315 return(remlen - outbytes);
318 /* UTF-16LE to native encoding
319 * Must be g_free'd after use */
320 static gchar *
321 unicode_strconvcopy_back(const gchar *source, gsize len)
323 gsize outbytes = 2 * len;
324 gchar *dest = g_new0(gchar, outbytes + 1);
325 gchar *outbuf = dest;
326 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
327 return dest;
330 /* crc32 source copy from gg's common.c */
331 static guint32 crc32_table[256];
332 static int crc32_initialized = 0;
334 static void crc32_make_table()
336 guint32 h = 1;
337 unsigned int i, j;
339 memset(crc32_table, 0, sizeof(crc32_table));
341 for (i = 128; i; i >>= 1) {
342 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
344 for (j = 0; j < 256; j += 2 * i)
345 crc32_table[i + j] = crc32_table[j] ^ h;
348 crc32_initialized = 1;
351 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
353 if (!crc32_initialized)
354 crc32_make_table();
356 if (!buf || len < 0)
357 return crc;
359 crc ^= 0xffffffffL;
361 while (len--)
362 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
364 return crc ^ 0xffffffffL;
367 static guint32
368 CRC32 (const char *msg, int len)
370 guint32 crc = 0L;
371 crc = crc32(crc, (guint8 *) msg, len);
372 return crc;
375 /* Cyphers */
377 #ifdef _SIPE_COMPILING_TESTS
378 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
380 key[0] = key_56[0];
381 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
382 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
383 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
384 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
385 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
386 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
387 key[7] = (key_56[6] << 1) & 0xFF;
390 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
391 static void
392 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
394 unsigned char key[8];
395 setup_des_key(k, key);
396 sipe_crypt_des(key, d, 8, results);
399 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
400 static void
401 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
403 unsigned char keys[21];
405 /* Copy the first 16 bytes */
406 memcpy(keys, k, 16);
408 /* Zero out the last 5 bytes of the key */
409 memset(keys + 16, 0, 5);
411 DES(keys, d, results);
412 DES(keys + 7, d, results + 8);
413 DES(keys + 14, d, results + 16);
415 #endif
417 #define RC4K(key, key_len, plain, plain_len, encrypted) \
418 sipe_crypt_rc4((key), (key_len), (plain), (plain_len), (encrypted))
420 /* out 16 bytes */
421 #define MD4(d, len, result) sipe_digest_md4((d), (len), (result))
423 /* out 16 bytes */
424 #define MD5(d, len, result) sipe_digest_md5((d), (len), (result))
426 /* out 16 bytes */
428 static void
429 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
431 int i;
432 unsigned char ibuff[64 + data_len];
433 unsigned char obuff[64 + 16];
435 if (key_len > 64)
436 key_len = 64;
438 for (i = 0; i < key_len; i++) {
439 ibuff[i] = key[i] ^ 0x36;
440 obuff[i] = key[i] ^ 0x5c;
442 for (i = key_len; i < 64; i++) {
443 ibuff[i] = 0x36;
444 obuff[i] = 0x5c;
447 memcpy(ibuff+64, data, data_len);
449 MD5 (ibuff, 64 + data_len, obuff+64);
450 MD5 (obuff, 64 + 16, result);
452 #define HMAC_MD5 HMACT64
455 /* out 16 bytes */
456 #define HMAC_MD5(key, key_len, data, data_len, result) \
457 sipe_digest_hmac_md5((key), (key_len), (data), (data_len), (result))
459 /* NTLM Core Methods */
461 static void
462 NONCE(unsigned char *buffer, int num)
464 int i;
465 for (i = 0; i < num; i++) {
466 buffer[i] = (rand() & 0xff);
470 #ifdef _SIPE_COMPILING_TESTS
471 static void
472 Z(unsigned char *buffer, int num)
474 memset(buffer, 0, num);
477 static void
478 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
480 /* "KGS!@#$%" */
481 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
482 unsigned char uppercase_password[14];
483 int i;
485 int len = strlen(password);
486 if (len > 14) {
487 len = 14;
490 // Uppercase password
491 for (i = 0; i < len; i++) {
492 uppercase_password[i] = g_ascii_toupper(password[i]);
495 // Zero the rest
496 for (; i < 14; i++) {
497 uppercase_password[i] = 0;
500 DES (uppercase_password, magic, result);
501 DES (uppercase_password + 7, magic, result + 8);
503 #endif
506 Define NTOWFv1(Passwd, User, UserDom) as
507 MD4(UNICODE(Passwd))
508 EndDefine
510 /* out 16 bytes */
511 static void
512 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
514 int len_u = 2 * strlen(password); // utf16 should not be more
515 unsigned char *unicode_password = g_malloc(len_u);
517 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
518 MD4 (unicode_password, len_u, result);
519 g_free(unicode_password);
523 Define NTOWFv2(Passwd, User, UserDom) as
524 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
525 EndDefine
527 /* out 16 bytes */
528 void
529 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
531 unsigned char response_key_nt_v1 [16];
532 int len_user = user ? strlen(user) : 0;
533 int len_domain = domain ? strlen(domain) : 0;
534 int len_user_u = 2 * len_user; // utf16 should not be more
535 int len_domain_u = 2 * len_domain; // utf16 should not be more
536 unsigned char *user_upper = g_malloc(len_user + 1);
537 unsigned char *buff = g_malloc((len_user + len_domain)*2);
538 int i;
540 /* Uppercase user */
541 for (i = 0; i < len_user; i++) {
542 user_upper[i] = g_ascii_toupper(user[i]);
544 user_upper[len_user] = 0;
546 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
547 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
549 NTOWFv1(password, user, domain, response_key_nt_v1);
551 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
553 g_free(buff);
554 g_free(user_upper);
557 static void
558 compute_response(const guint32 neg_flags,
559 const unsigned char *response_key_nt,
560 const unsigned char *response_key_lm,
561 const guint8 *server_challenge,
562 const guint8 *client_challenge,
563 const guint64 time_val,
564 const guint8 *target_info,
565 int target_info_len,
566 unsigned char *lm_challenge_response,
567 unsigned char *nt_challenge_response,
568 unsigned char *session_base_key)
570 #ifdef _SIPE_COMPILING_TESTS
571 if (use_ntlm_v2)
573 #endif
575 Responserversion - The 1-byte response version. Currently set to 1.
576 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
577 Time - The 8-byte little-endian time in GMT.
578 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
579 ClientChallenge - The 8-byte challenge message generated by the client.
580 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
582 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
583 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
584 Time, //8bytes - 8
585 ClientChallenge, //8bytes - 16
586 Z(4), //4bytes - 24
587 ServerName, //variable - 28
588 Z(4)) //4bytes - 28+target_info_len
589 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
590 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
591 Set LmChallengeResponse to ConcatenationOf(
592 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
593 ClientChallenge )
594 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
595 EndDefine
597 guint8 tmp [16];
598 guint8 nt_proof_str [16];
600 /* client_challenge (8) & temp (temp_len) buff */
601 int temp_len = 8+8+8+4+target_info_len+4;
602 guint64 *temp2 = g_malloc0(8 + temp_len);
603 ((guint8 *) temp2)[8+0] = 1;
604 ((guint8 *) temp2)[8+1] = 1;
605 temp2[2] = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
606 memcpy(((guint8 *) temp2)+8+16, client_challenge, 8);
607 memcpy(((guint8 *) temp2)+8+28, target_info, target_info_len);
609 /* NTProofStr */
610 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
611 memcpy(temp2, server_challenge, 8);
612 HMAC_MD5(response_key_nt, 16, (guint8*)temp2, 8+temp_len, nt_proof_str);
614 /* NtChallengeResponse */
615 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
616 memcpy(nt_challenge_response, nt_proof_str, 16);
617 memcpy(nt_challenge_response+16, temp2+1, temp_len);
618 g_free(temp2);
620 /* SessionBaseKey */
621 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
622 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
624 /* lm_challenge_response */
625 memcpy(tmp, server_challenge, 8);
626 memcpy(tmp+8, client_challenge, 8);
627 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
628 memcpy(lm_challenge_response+16, client_challenge, 8);
630 #ifndef _SIPE_COMPILING_TESTS
631 /* Not used in NTLMv2 */
632 (void)neg_flags;
633 #else
635 else
637 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
638 // @TODO do not even reference nt_challenge_response
639 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
640 DESL (response_key_lm, server_challenge, lm_challenge_response);
641 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
642 unsigned char prehash [16];
643 unsigned char hash [16];
645 /* nt_challenge_response */
646 memcpy(prehash, server_challenge, 8);
647 memcpy(prehash + 8, client_challenge, 8);
648 MD5 (prehash, 16, hash);
649 DESL (response_key_nt, hash, nt_challenge_response);
651 /* lm_challenge_response */
652 memcpy(lm_challenge_response, client_challenge, 8);
653 Z (lm_challenge_response+8, 16);
654 } else {
655 DESL (response_key_nt, server_challenge, nt_challenge_response);
656 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
657 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
658 } else {
659 DESL (response_key_lm, server_challenge, lm_challenge_response);
663 /* Session Key */
664 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
666 #endif
669 static void
670 KXKEY ( guint32 flags,
671 const unsigned char * session_base_key,
672 const unsigned char * lm_challenge_resonse,
673 const guint8 * server_challenge, /* 8-bytes, nonce */
674 unsigned char * key_exchange_key)
676 #ifdef _SIPE_COMPILING_TESTS
677 if (use_ntlm_v2)
679 #else
680 /* Not used in NTLMv2 */
681 (void)flags;
682 (void)lm_challenge_resonse;
683 (void)server_challenge;
684 #endif
685 memcpy(key_exchange_key, session_base_key, 16);
686 #ifdef _SIPE_COMPILING_TESTS
688 else
690 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
691 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
692 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
693 EndDefine
695 guint8 tmp[16];
696 memcpy(tmp, server_challenge, 8);
697 memcpy(tmp+8, lm_challenge_resonse, 8);
698 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
699 } else {
700 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
701 memcpy(key_exchange_key, session_base_key, 16);
704 #endif
708 If (Mode equals "Client")
709 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
710 "session key to client-to-server signing key magic constant"))
711 Else
712 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
713 "session key to server-to-client signing key magic constant"))
714 Endif
716 static void
717 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
719 char * magic = client
720 ? "session key to client-to-server signing key magic constant"
721 : "session key to server-to-client signing key magic constant";
723 int len = strlen(magic) + 1;
724 unsigned char *md5_input = g_malloc(16 + len);
725 memcpy(md5_input, random_session_key, 16);
726 memcpy(md5_input + 16, magic, len);
728 MD5 (md5_input, len + 16, result);
729 g_free(md5_input);
733 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
734 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
735 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
736 Set SealKey to RandomSessionKey
737 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
738 Set SealKey to RandomSessionKey[0..6]
739 Else
740 Set SealKey to RandomSessionKey[0..4]
741 Endif
743 If (Mode equals "Client")
744 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
745 Else
746 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
747 Endif
749 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
750 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
751 Else
752 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
753 Endif
754 EndDefine
756 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
757 static void
758 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
760 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
762 char * magic = client
763 ? "session key to client-to-server sealing key magic constant"
764 : "session key to server-to-client sealing key magic constant";
766 int len = strlen(magic) + 1;
767 unsigned char *md5_input = g_malloc(16 + len);
768 int key_len;
770 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
771 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
772 key_len = 16;
773 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
774 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
775 key_len = 7;
776 } else {
777 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
778 key_len = 5;
781 memcpy(md5_input, random_session_key, key_len);
782 memcpy(md5_input + key_len, magic, len);
784 MD5 (md5_input, key_len + len, result);
785 g_free(md5_input);
787 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
789 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
790 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
791 memcpy(result, random_session_key, 7);
792 result[7] = 0xA0;
793 } else {
794 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
795 memcpy(result, random_session_key, 5);
796 result[5] = 0xE5;
797 result[6] = 0x38;
798 result[7] = 0xB0;
801 else
803 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
804 memcpy(result, random_session_key, 16);
809 = for Extended Session Security =
810 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
811 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
812 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
814 = if Extended Session Security is NOT negotiated =
815 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
816 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
817 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
818 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
820 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
822 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
823 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
825 /** MAC(Handle, SigningKey, SeqNum, Message) */
826 /* out 16 bytes */
827 static void
828 MAC (guint32 flags,
829 const char *buf,
830 int buf_len,
831 unsigned char *sign_key,
832 unsigned long sign_key_len,
833 unsigned char *seal_key,
834 unsigned long seal_key_len,
835 guint32 random_pad,
836 guint32 sequence,
837 guint32 *result)
839 guint32 *res_ptr;
841 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
843 Define MAC(Handle, SigningKey, SeqNum, Message) as
844 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
845 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
846 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
847 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
848 Set SeqNum to SeqNum + 1
849 EndDefine
851 /* If a key exchange key is negotiated
852 Define MAC(Handle, SigningKey, SeqNum, Message) as
853 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
854 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
855 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
856 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
857 Set SeqNum to SeqNum + 1
858 EndDefine
861 unsigned char seal_key_ [16];
862 guchar hmac[16];
863 guint32 *tmp = g_malloc(4 + buf_len);
865 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
866 RC4Init(Handle, SealingKey')
868 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
869 guint32 tmp2[4+1];
871 memcpy(tmp2, seal_key, seal_key_len);
872 tmp2[4] = GUINT32_TO_LE(sequence);
873 MD5 ((guchar *)tmp2, sizeof(tmp2), seal_key_);
874 } else {
875 memcpy(seal_key_, seal_key, seal_key_len);
878 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extented Session Security");
880 res_ptr = result;
881 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
882 res_ptr[3] = GUINT32_TO_LE(sequence);
884 res_ptr = tmp;
885 res_ptr[0] = GUINT32_TO_LE(sequence);
886 memcpy(tmp+1, buf, buf_len);
888 HMAC_MD5(sign_key, sign_key_len, (guchar *)tmp, 4 + buf_len, hmac);
889 g_free(tmp);
891 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
892 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
893 RC4K(seal_key_, seal_key_len, hmac, 8, (guchar *)(result+1));
894 } else {
895 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
896 memcpy(result+1, hmac, 8);
898 } else {
899 /* The content of the first 4 bytes is irrelevant */
900 guint32 crc = CRC32(buf, strlen(buf));
901 guint32 plaintext [] = {
902 GUINT32_TO_LE(0),
903 GUINT32_TO_LE(crc),
904 GUINT32_TO_LE(sequence)
905 }; // 4, 4, 4 bytes
907 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extented Session Security");
909 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, (guchar *)(result+1));
911 res_ptr = result;
912 // Highest four bytes are the Version
913 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
915 // Replace the first four bytes of the ciphertext with the random_pad
916 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
920 /* End Core NTLM Methods */
923 * @param flags (out) flags received from server
924 * @param server_challenge must be g_free()'d after use if requested
925 * @param target_info must be g_free()'d after use if requested
927 static void
928 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
929 guint32 *flags,
930 guchar **server_challenge, /* 8 bytes */
931 guint64 *time_val,
932 guchar **target_info,
933 int *target_info_len)
935 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
936 struct challenge_message *cmsg = (void *)in_buff.value;
937 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
939 /* server challenge (nonce) */
940 if (server_challenge) {
941 *server_challenge = g_memdup(cmsg->nonce, 8);
944 /* flags */
945 if (flags) {
946 *flags = host_flags;
949 /* target_info */
950 if (cmsg->target_info.len && cmsg->target_info.offset) {
951 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
952 void *av = content;
953 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
955 ALIGN_AV_LOOP_START
957 /* @since Vista */
958 case MsvAvTimestamp:
959 if (time_val) {
960 guint64 tmp;
962 /* to meet sparc's alignment requirement */
963 memcpy(&tmp, av_value, sizeof(tmp));
964 *time_val = GUINT64_FROM_LE(tmp);
966 break;
968 ALIGN_AV_LOOP_END;
970 if (target_info_len) {
971 *target_info_len = len;
973 if (target_info) {
974 *target_info = g_memdup(content, len);
980 * @param client_sign_key (out) must be g_free()'d after use
981 * @param server_sign_key (out) must be g_free()'d after use
982 * @param client_seal_key (out) must be g_free()'d after use
983 * @param server_seal_key (out) must be g_free()'d after use
984 * @param flags (in, out) negotiated flags
986 static sip_uint32
987 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
988 guchar **server_sign_key,
989 guchar **client_seal_key,
990 guchar **server_seal_key,
991 const gchar *user,
992 const gchar *password,
993 const gchar *hostname,
994 const gchar *domain,
995 const guint8 *server_challenge, /* nonce */
996 const guint64 time_val,
997 const guint8 *target_info,
998 int target_info_len,
999 gboolean is_connection_based,
1000 SipSecBuffer *out_buff,
1001 guint32 *flags)
1003 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
1004 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1005 int ntlmssp_nt_resp_len =
1006 #ifdef _SIPE_COMPILING_TESTS
1007 use_ntlm_v2 ?
1008 #endif
1009 (16 + (32+target_info_len))
1010 #ifdef _SIPE_COMPILING_TESTS
1011 : NTLMSSP_LM_RESP_LEN
1012 #endif
1014 gsize msglen = sizeof(struct authenticate_message)
1015 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1016 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1017 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1018 struct authenticate_message *tmsg;
1019 char *tmp;
1020 guint32 offset;
1021 guint16 len;
1022 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1023 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1024 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1025 unsigned char *nt_challenge_response = g_malloc(ntlmssp_nt_resp_len); /* variable or 24 */
1026 unsigned char session_base_key [16];
1027 unsigned char key_exchange_key [16];
1028 unsigned char exported_session_key[16];
1029 unsigned char encrypted_random_session_key [16];
1030 unsigned char key [16];
1031 unsigned char client_challenge [8];
1032 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1034 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1035 !(is_connection_based || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)))
1037 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1038 return SIP_SEC_E_INTERNAL_ERROR;
1041 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1042 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1045 tmsg = g_malloc0(msglen);
1047 NONCE (client_challenge, 8);
1049 #ifdef _SIPE_COMPILING_TESTS
1050 memcpy(client_challenge, test_client_challenge, 8);
1051 time_vl = test_time_val ? test_time_val : time_vl;
1053 if (use_ntlm_v2) {
1055 #endif
1056 NTOWFv2 (password, user, domain, response_key_nt);
1057 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1058 #ifdef _SIPE_COMPILING_TESTS
1059 } else {
1060 NTOWFv1 (password, user, domain, response_key_nt);
1061 LMOWFv1 (password, user, domain, response_key_lm);
1063 #endif
1065 compute_response(neg_flags,
1066 response_key_nt,
1067 response_key_lm,
1068 server_challenge,
1069 client_challenge,
1070 time_vl,
1071 target_info,
1072 target_info_len,
1073 lm_challenge_response, /* out */
1074 nt_challenge_response, /* out */
1075 session_base_key); /* out */
1077 /* same as session_base_key for
1078 * - NTLNv1 w/o Ext.Sess.Sec and
1079 * - NTLMv2
1081 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1083 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1084 NONCE (exported_session_key, 16); // random master key
1085 #ifdef _SIPE_COMPILING_TESTS
1086 memcpy(exported_session_key, test_random_session_key, 16);
1087 #endif
1088 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1089 } else {
1090 memcpy(exported_session_key, key_exchange_key, 16);
1093 tmp = buff_to_hex_str(exported_session_key, 16);
1094 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp);
1095 g_free(tmp);
1097 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1098 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1100 /* p.46
1101 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1102 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1104 SIGNKEY(exported_session_key, TRUE, key);
1105 *client_sign_key = g_memdup(key, 16);
1106 SIGNKEY(exported_session_key, FALSE, key);
1107 *server_sign_key = g_memdup(key, 16);
1108 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1109 *client_seal_key = g_memdup(key, 16);
1110 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1111 *server_seal_key = g_memdup(key, 16);
1114 /* @TODO: */
1115 /* @since Vista
1116 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1117 the client SHOULD provide a MIC:
1118 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1119 - then in the Value field, set bit 0x2 to 1.
1120 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1121 and the Value field bit 0x2 to 1.
1122 - Populate the MIC field with the MIC.
1125 /* Connection-oriented:
1126 Set MIC to HMAC_MD5(ExportedSessionKey,
1127 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1128 Connectionless:
1129 Set MIC to HMAC_MD5(ExportedSessionKey,
1130 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1133 /* on the server-side:
1134 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1135 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1136 Set MIC to HMAC_MD5(ExportedSessionKey,
1137 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1138 Else
1139 Set ExportedSessionKey to KeyExchangeKey
1140 Set MIC to HMAC_MD5(KeyExchangeKey,
1141 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1142 =====
1143 @since Vista
1144 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1145 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1146 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1147 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1148 an AV_PAIR structure whose two fields:
1149 - AvId == MsvAvFlags
1150 - Value bit 0x2 == 1
1151 @supported NT, 2000, XP
1152 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1153 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1154 the server time, then the server SHOULD return a failure.
1156 Connectionless:
1157 Set MIC to HMAC_MD5(ResponseKeyNT,
1158 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1161 /* authenticate message initialization */
1162 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1163 tmsg->type = GUINT32_TO_LE(3);
1165 /* Initial offset */
1166 offset = sizeof(struct authenticate_message);
1167 tmp = ((char*) tmsg) + offset;
1169 #define _FILL_SMB_HEADER(header) \
1170 tmsg->header.offset = GUINT32_TO_LE(offset); \
1171 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1172 tmp += len; \
1173 offset += len
1174 #define _APPEND_STRING(header, src) \
1175 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1176 _FILL_SMB_HEADER(header)
1177 #define _APPEND_DATA(header, src, srclen) \
1178 len = (srclen); \
1179 memcpy(tmp, (src), len); \
1180 _FILL_SMB_HEADER(header)
1182 /* Domain */
1183 _APPEND_STRING(domain, domain);
1185 /* User */
1186 _APPEND_STRING(user, user);
1188 /* Host */
1189 _APPEND_STRING(host, hostname);
1191 /* LM */
1192 /* @since Windows 7
1193 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1194 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1195 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1197 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1199 /* NT */
1200 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1202 /* Session Key */
1203 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1205 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1207 else
1209 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1210 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1213 /* Version */
1214 #ifdef _SIPE_COMPILING_TESTS
1215 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1216 #else
1217 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1218 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1219 tmsg->ver.product_minor_version = 1;
1220 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1221 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1223 #endif
1225 /* Set Negotiate Flags */
1226 tmsg->flags = GUINT32_TO_LE(neg_flags);
1227 *flags = neg_flags;
1229 out_buff->value = (guint8 *)tmsg;
1230 out_buff->length = msglen;
1232 g_free(nt_challenge_response);
1234 return SIP_SEC_E_OK;
1238 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1240 static void
1241 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1243 guint32 offset;
1244 guint16 len;
1245 int msglen = sizeof(struct negotiate_message);
1246 struct negotiate_message *tmsg = g_malloc0(msglen);
1248 /* negotiate message initialization */
1249 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1250 tmsg->type = GUINT32_TO_LE(1);
1252 /* Set Negotiate Flags */
1253 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1255 /* Domain */
1256 offset = sizeof(struct negotiate_message);
1257 tmsg->domain.offset = GUINT32_TO_LE(offset);
1258 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1260 /* Host */
1261 offset += len;
1262 tmsg->host.offset = GUINT32_TO_LE(offset);
1263 tmsg->host.len = tmsg->host.maxlen = len = 0;
1265 /* Version */
1266 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1267 tmsg->ver.product_minor_version = 1;
1268 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1269 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1271 out_buff->value = (guint8 *)tmsg;
1272 out_buff->length = msglen;
1275 static void
1276 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1277 const char *msg,
1278 guint32 random_pad,
1279 unsigned char *sign_key,
1280 unsigned char *seal_key,
1281 guint32 *result)
1283 char *res;
1285 MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100, result);
1287 res = buff_to_hex_str((guint8 *)result, 16);
1288 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res);
1289 g_free(res);
1293 /* Describe NTLM messages functions */
1295 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1296 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1298 static gchar *
1299 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1301 GString* str = g_string_new(NULL);
1303 flags = GUINT32_FROM_LE(flags);
1305 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1306 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1307 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1308 APPEND_NEG_FLAG(str, flags, r9, "r9");
1309 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1310 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1311 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1312 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1313 APPEND_NEG_FLAG(str, flags, r8, "r8");
1314 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1315 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1316 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1317 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1318 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1319 APPEND_NEG_FLAG(str, flags, r7, "r7");
1320 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1321 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1322 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1323 APPEND_NEG_FLAG(str, flags, r6, "r6");
1324 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1325 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1326 APPEND_NEG_FLAG(str, flags, r5, "r5");
1327 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1328 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1329 APPEND_NEG_FLAG(str, flags, r4, "r4");
1330 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1331 APPEND_NEG_FLAG(str, flags, r3, "r3");
1332 APPEND_NEG_FLAG(str, flags, r2, "r2");
1333 APPEND_NEG_FLAG(str, flags, r1, "r1");
1334 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1335 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1336 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1338 return g_string_free(str, FALSE);
1341 static gchar *
1342 sip_sec_ntlm_describe_version(struct version *ver) {
1343 GString* str = g_string_new(NULL);
1344 gchar *ver_desc = "";
1345 gchar *ntlm_revision_desc = "";
1347 if (ver->product_major_version == 6) {
1348 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1349 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1350 ver_desc = "Windows Server 2003";
1351 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1352 ver_desc = "Windows XP SP2";
1355 if (ver->ntlm_revision_current == 0x0F) {
1356 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1357 } else if (ver->ntlm_revision_current == 0x0A) {
1358 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1361 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1362 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1363 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1365 return g_string_free(str, FALSE);
1368 static gchar *
1369 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1370 const char* name)
1372 GString* str = g_string_new(NULL);
1374 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1375 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1376 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1378 return g_string_free(str, FALSE);
1381 static gchar *
1382 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1384 GString* str = g_string_new(NULL);
1385 char *tmp;
1387 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1388 g_free(tmp);
1390 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1391 g_free(tmp);
1393 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1394 g_free(tmp);
1396 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1397 g_string_append(str, tmp);
1398 g_free(tmp);
1400 if (cmsg->domain.len && cmsg->domain.offset) {
1401 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1402 g_string_append_printf(str, "\tdomain: %s\n", domain);
1403 g_free(domain);
1406 if (cmsg->host.len && cmsg->host.offset) {
1407 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1408 g_string_append_printf(str, "\thost: %s\n", host);
1409 g_free(host);
1412 return g_string_free(str, FALSE);
1415 static void
1416 describe_av_pairs(GString* str, const void *av)
1418 #define AV_DESC(av_name) \
1420 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1421 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1422 g_free(tmp); \
1425 ALIGN_AV_LOOP_START
1427 case MsvAvNbComputerName:
1428 AV_DESC("MsvAvNbComputerName");
1429 break;
1430 case MsvAvNbDomainName:
1431 AV_DESC("MsvAvNbDomainName");
1432 break;
1433 case MsvAvDnsComputerName:
1434 AV_DESC("MsvAvDnsComputerName");
1435 break;
1436 case MsvAvDnsDomainName:
1437 AV_DESC("MsvAvDnsDomainName");
1438 break;
1439 case MsvAvDnsTreeName:
1440 AV_DESC("MsvAvDnsTreeName");
1441 break;
1442 case MsvAvFlags:
1444 guint32 flags;
1446 /* to meet sparc's alignment requirement */
1447 memcpy(&flags, av_value, sizeof(guint32));
1448 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1450 break;
1451 case MsvAvTimestamp:
1453 char *tmp;
1454 guint64 time_val;
1455 time_t time_t_val;
1457 /* to meet sparc's alignment requirement */
1458 memcpy(&time_val, av_value, sizeof(time_val));
1459 time_t_val = TIME_VAL_TO_T(time_val);
1461 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1462 asctime(gmtime(&time_t_val)));
1463 g_free(tmp);
1465 break;
1466 case MsAvRestrictions:
1467 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1468 break;
1469 case MsvAvTargetName:
1470 AV_DESC("MsvAvTargetName");
1471 break;
1472 case MsvChannelBindings:
1473 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1474 break;
1476 ALIGN_AV_LOOP_END;
1479 static gchar *
1480 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1482 GString* str = g_string_new(NULL);
1483 char *tmp;
1484 gsize value_len;
1485 guint8 *value;
1487 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1488 g_free(tmp);
1490 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1491 g_free(tmp);
1493 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1494 g_free(tmp);
1496 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1497 g_free(tmp);
1499 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1500 g_free(tmp);
1502 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1503 g_free(tmp);
1505 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1506 g_free(tmp);
1508 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1509 g_string_append(str, tmp);
1510 g_free(tmp);
1512 /* mic */
1513 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1514 //g_free(tmp);
1516 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1517 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1518 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1519 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1520 g_free(tmp);
1523 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1524 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1525 int nt_resp_len = nt_resp_len_full;
1527 value_len = nt_resp_len_full;
1528 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1529 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1530 g_free(tmp);
1532 if (nt_resp_len > 24) { /* NTLMv2 */
1533 nt_resp_len = 16;
1536 value_len = nt_resp_len;
1537 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1538 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1539 g_free(tmp);
1541 if (nt_resp_len_full > 24) { /* NTLMv2 */
1542 /* Work around Debian/x86_64 compiler bug */
1543 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1544 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1545 const guint8 *temp = (guint8 *)cmsg + offset;
1546 const guint response_version = temp[0];
1547 const guint hi_response_version = temp[1];
1548 const guint8 *client_challenge = temp + 16;
1549 const guint8 *target_info = temp + 28;
1550 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1551 guint64 time_val;
1552 time_t time_t_val;
1553 char *tmp;
1555 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1556 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1557 g_free(tmp);
1559 /* This is not int64 aligned on sparc */
1560 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1561 time_t_val = TIME_VAL_TO_T(time_val);
1563 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1564 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1566 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1567 asctime(gmtime(&time_t_val)));
1568 g_free(tmp);
1570 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1571 g_free(tmp);
1573 describe_av_pairs(str, target_info);
1575 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1579 if (cmsg->domain.len && cmsg->domain.offset) {
1580 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1581 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1582 g_free(domain);
1585 if (cmsg->user.len && cmsg->user.offset) {
1586 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1587 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1588 g_free(user);
1591 if (cmsg->host.len && cmsg->host.offset) {
1592 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1593 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1594 g_free(host);
1597 if (cmsg->session_key.len && cmsg->session_key.offset) {
1598 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1599 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1600 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1601 g_free(tmp);
1604 return g_string_free(str, FALSE);
1607 static gchar *
1608 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1610 GString* str = g_string_new(NULL);
1611 char *tmp;
1613 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1614 g_free(tmp);
1616 /* nonce (server_challenge) */
1617 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1618 g_free(tmp);
1620 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1621 g_free(tmp);
1623 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1624 g_free(tmp);
1626 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1627 g_free(tmp);
1629 if (cmsg->target_name.len && cmsg->target_name.offset) {
1630 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1631 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1632 g_free(target_name);
1635 if (cmsg->target_info.len && cmsg->target_info.offset) {
1636 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1637 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1639 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1640 g_free(tmp);
1642 describe_av_pairs(str, target_info);
1645 return g_string_free(str, FALSE);
1648 gchar *
1649 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1651 struct ntlm_message *msg;
1652 gchar *res = NULL;
1654 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1656 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1657 msg = (void *)buff.value;
1658 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1660 switch (GUINT32_FROM_LE(msg->type)) {
1661 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1662 break;
1663 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1664 break;
1665 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1666 break;
1669 return res;
1672 /* sip-sec-mech.h API implementation for NTLM */
1674 /* Security context for NTLM */
1675 typedef struct _context_ntlm {
1676 struct sip_sec_context common;
1677 char* domain;
1678 char *username;
1679 char *password;
1680 int step;
1681 guchar *client_sign_key;
1682 guchar *server_sign_key;
1683 guchar *client_seal_key;
1684 guchar *server_seal_key;
1685 guint32 flags;
1686 } *context_ntlm;
1689 static sip_uint32
1690 sip_sec_acquire_cred__ntlm(SipSecContext context,
1691 const char *domain,
1692 const char *username,
1693 const char *password)
1695 context_ntlm ctx = (context_ntlm)context;
1697 /* NTLM requires a username & password. Domain may be empty */
1698 if (!domain || is_empty(username) || is_empty(password))
1699 return SIP_SEC_E_INTERNAL_ERROR;
1701 ctx->domain = g_strdup(domain);
1702 ctx->username = g_strdup(username);
1703 ctx->password = g_strdup(password);
1705 return SIP_SEC_E_OK;
1708 static sip_uint32
1709 sip_sec_init_sec_context__ntlm(SipSecContext context,
1710 SipSecBuffer in_buff,
1711 SipSecBuffer *out_buff,
1712 SIPE_UNUSED_PARAMETER const char *service_name)
1714 context_ntlm ctx = (context_ntlm) context;
1716 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
1718 ctx->step++;
1719 if (ctx->step == 1) {
1720 if (!context->is_connection_based) {
1721 out_buff->length = 0;
1722 out_buff->value = NULL;
1723 } else {
1724 sip_sec_ntlm_gen_negotiate(out_buff);
1726 return SIP_SEC_I_CONTINUE_NEEDED;
1728 } else {
1729 sip_uint32 res;
1730 guchar *client_sign_key = NULL;
1731 guchar *server_sign_key = NULL;
1732 guchar *client_seal_key = NULL;
1733 guchar *server_seal_key = NULL;
1734 guchar *server_challenge = NULL;
1735 guint64 time_val = 0;
1736 guchar *target_info = NULL;
1737 int target_info_len = 0;
1738 guint32 flags;
1739 gchar *tmp;
1741 if (!in_buff.value || !in_buff.length) {
1742 return SIP_SEC_E_INTERNAL_ERROR;
1745 sip_sec_ntlm_parse_challenge(in_buff,
1746 &flags,
1747 &server_challenge, /* 8 bytes */
1748 &time_val,
1749 &target_info,
1750 &target_info_len);
1752 res = sip_sec_ntlm_gen_authenticate(
1753 &client_sign_key,
1754 &server_sign_key,
1755 &client_seal_key,
1756 &server_seal_key,
1757 ctx->username,
1758 ctx->password,
1759 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1760 ctx->domain,
1761 server_challenge,
1762 time_val,
1763 target_info,
1764 target_info_len,
1765 context->is_connection_based,
1766 out_buff,
1767 &flags);
1768 g_free(server_challenge);
1769 g_free(target_info);
1770 g_free(tmp);
1772 if (res != SIP_SEC_E_OK) {
1773 g_free(client_sign_key);
1774 g_free(server_sign_key);
1775 g_free(client_seal_key);
1776 g_free(server_seal_key);
1777 return res;
1780 g_free(ctx->client_sign_key);
1781 ctx->client_sign_key = client_sign_key;
1783 g_free(ctx->server_sign_key);
1784 ctx->server_sign_key = server_sign_key;
1786 g_free(ctx->client_seal_key);
1787 ctx->client_seal_key = client_seal_key;
1789 g_free(ctx->server_seal_key);
1790 ctx->server_seal_key = server_seal_key;
1792 ctx->flags = flags;
1793 return SIP_SEC_E_OK;
1798 * @param message a NULL terminated string to sign
1801 static sip_uint32
1802 sip_sec_make_signature__ntlm(SipSecContext context,
1803 const char *message,
1804 SipSecBuffer *signature)
1806 signature->length = 16;
1807 signature->value = g_malloc0(16);
1809 /* FIXME? We always use a random_pad of 0 */
1810 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1811 message,
1813 ((context_ntlm) context)->client_sign_key,
1814 ((context_ntlm) context)->client_seal_key,
1815 /* SipSecBuffer.value is g_malloc()'d:
1816 * use (void *) to remove guint8 alignment
1818 (void *)signature->value);
1819 return SIP_SEC_E_OK;
1823 * @param message a NULL terminated string to check signature of
1824 * @return SIP_SEC_E_OK on success
1826 static sip_uint32
1827 sip_sec_verify_signature__ntlm(SipSecContext context,
1828 const char *message,
1829 SipSecBuffer signature)
1831 guint32 mac[4];
1832 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1833 guint32 random_pad = GUINT32_FROM_LE(((guint32 *)((void *)signature.value))[1]);
1835 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1836 message,
1837 random_pad,
1838 ((context_ntlm) context)->server_sign_key,
1839 ((context_ntlm) context)->server_seal_key,
1840 mac);
1841 return(memcmp(signature.value, mac, 16) ?
1842 SIP_SEC_E_INTERNAL_ERROR :
1843 SIP_SEC_E_OK);
1846 static void
1847 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1849 context_ntlm ctx = (context_ntlm) context;
1851 g_free(ctx->domain);
1852 g_free(ctx->username);
1853 g_free(ctx->password);
1854 g_free(ctx->client_sign_key);
1855 g_free(ctx->server_sign_key);
1856 g_free(ctx->client_seal_key);
1857 g_free(ctx->server_seal_key);
1858 g_free(ctx);
1861 SipSecContext
1862 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER guint type)
1864 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1865 if (!context) return(NULL);
1867 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1868 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1869 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1870 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1871 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1873 return((SipSecContext) context);
1876 void sip_sec_init__ntlm(void)
1878 #ifdef HAVE_LANGINFO_CODESET
1879 const char *sys_cp = nl_langinfo(CODESET);
1880 #else
1881 const char *sys_cp = SIPE_DEFAULT_CODESET;
1882 #endif /* HAVE_LANGINFO_CODESET */
1884 /* fall back to utf-8 */
1885 if (!sys_cp) sys_cp = "UTF-8";
1887 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1888 if (convert_from_utf16le == (GIConv)-1) {
1889 SIPE_DEBUG_ERROR("g_iconv_open from UTF-16LE to %s failed",
1890 sys_cp);
1893 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1894 if (convert_to_utf16le == (GIConv)-1) {
1895 SIPE_DEBUG_ERROR("g_iconv_open from %s to UTF-16LE failed",
1896 sys_cp);
1900 void sip_sec_destroy__ntlm(void)
1902 g_iconv_close(convert_to_utf16le);
1903 g_iconv_close(convert_from_utf16le);
1907 Local Variables:
1908 mode: c
1909 c-file-style: "bsd"
1910 indent-tabs-mode: t
1911 tab-width: 8
1912 End: