core cleanup: move MD4/MD5 digest calculation to backend
[siplcs.git] / src / core / sip-sec-ntlm.c
blobe865e877a27c99e5bf524f47b72bcc005e21f850
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 "cipher.h"
60 #include "sipe-common.h"
61 #include "sip-sec.h"
62 #include "sip-sec-mech.h"
63 #include "sip-sec-ntlm.h"
64 #include "sipe-backend.h"
65 #include "sipe-utils.h"
67 /* [MS-NLMP] */
68 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
69 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
70 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
71 #define r9 0x00000008 /* r9 */
72 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
73 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
74 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
75 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
76 #define r8 0x00000100 /* r8 */
77 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
78 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
79 #define anonymous 0x00000800 /* J */
80 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
81 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
82 #define r7 0x00004000 /* r7 */
83 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
84 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
85 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
86 #define r6 0x00040000 /* r6 */
87 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
88 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
89 #define r5 0x00200000 /* r5 */
90 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
91 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
92 #define r4 0x01000000 /* r4 */
93 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
94 #define r3 0x04000000 /* r3 */
95 #define r2 0x08000000 /* r2 */
96 #define r1 0x10000000 /* r1 */
97 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
98 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
99 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
101 /* AvId */
102 #define MsvAvEOL 0
103 #define MsvAvNbComputerName 1
104 #define MsvAvNbDomainName 2
105 #define MsvAvDnsComputerName 3
106 #define MsvAvDnsDomainName 4
107 /** @since Windows XP */
108 #define MsvAvDnsTreeName 5
109 /** @since Windows XP */
110 #define MsvAvFlags 6
111 /** @since Windows Vista */
112 #define MsvAvTimestamp 7
113 /** @since Windows Vista */
114 #define MsAvRestrictions 8
115 /** @since Windows 7 */
116 #define MsvAvTargetName 9
117 /** @since Windows 7 */
118 #define MsvChannelBindings 10
120 /* time_t <-> (guint64) time_val conversion */
121 #define TIME_VAL_FACTOR 10000000
122 #define TIME_VAL_OFFSET 116444736000000000LL
123 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
124 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
126 /* 8 bytes */
127 /* LE (Little Endian) byte order */
128 struct version {
129 guint8 product_major_version;
130 guint8 product_minor_version;
131 guint16 product_build;
132 guint8 zero2[3];
133 guint8 ntlm_revision_current;
137 * NTLMv1 is no longer used except in tests. R.I.P.
139 * It remains in this file only for documentary purposes
141 #ifdef _SIPE_COMPILING_TESTS
142 static gboolean use_ntlm_v2 = FALSE;
144 guint64 test_time_val = 0; /* actual time in implementation */
145 guchar test_client_challenge [8]; /* random in implementation */
146 guchar test_random_session_key[16]; /* random in implementation */
147 struct version test_version; /* hard-coded in implementation */
148 #endif
150 /* Minimum set of common features we need to work. */
151 /* we operate in NTLMv2 mode */
152 #define NEGOTIATE_FLAGS_COMMON_MIN \
153 ( NTLMSSP_NEGOTIATE_UNICODE | \
154 NTLMSSP_NEGOTIATE_NTLM | \
155 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
156 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
157 NTLMSSP_NEGOTIATE_TARGET_INFO \
160 /* Negotiate flags for connection-based mode. Nice to have but optional. */
161 #define NEGOTIATE_FLAGS_CONN \
162 ( NEGOTIATE_FLAGS_COMMON_MIN | \
163 NTLMSSP_NEGOTIATE_VERSION | \
164 NTLMSSP_NEGOTIATE_128 | \
165 NTLMSSP_NEGOTIATE_56 | \
166 NTLMSSP_REQUEST_TARGET \
169 /* Extra negotiate flags required in connectionless NTLM */
170 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
171 ( NTLMSSP_NEGOTIATE_SIGN | \
172 NTLMSSP_NEGOTIATE_DATAGRAM | \
173 NTLMSSP_NEGOTIATE_IDENTIFY | \
174 NTLMSSP_NEGOTIATE_KEY_EXCH \
177 /* Negotiate flags required in connectionless NTLM */
178 #define NEGOTIATE_FLAGS_CONNLESS \
179 ( NEGOTIATE_FLAGS_CONN | \
180 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
183 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
184 #define NTLMSSP_LM_RESP_LEN 24
185 #define NTLMSSP_SESSION_KEY_LEN 16
187 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
189 /* 4 bytes */
190 /* LE (Little Endian) byte order */
191 struct av_pair {
192 guint16 av_id;
193 guint16 av_len;
194 /* value */
197 /* to meet sparc's alignment requirement */
198 #define ALIGN_AV \
199 memcpy(&av_aligned, av, sizeof(av_aligned)); \
200 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
201 av_len = GUINT16_FROM_LE(av_aligned.av_len)
202 #define ALIGN_AV_LOOP_START \
203 struct av_pair av_aligned; \
204 guint16 av_id; \
205 guint16 av_len; \
206 ALIGN_AV; \
207 while (av_id != MsvAvEOL) { \
208 gchar *av_value = ((gchar *)av) + \
209 sizeof(struct av_pair); \
210 switch (av_id)
211 #define ALIGN_AV_LOOP_END \
212 av = av_value + av_len; \
213 ALIGN_AV; \
216 /* 8 bytes */
217 /* LE (Little Endian) byte order */
218 struct smb_header {
219 guint16 len;
220 guint16 maxlen;
221 guint32 offset;
224 /* LE (Little Endian) byte order */
225 struct ntlm_message {
226 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
227 guint32 type; /* 0x00000003 */
230 /* LE (Little Endian) byte order */
231 struct negotiate_message {
232 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
233 guint32 type; /* 0x00000001 */
234 guint32 flags; /* 0xb203 */
235 struct smb_header domain;
236 struct smb_header host;
237 struct version ver;
238 /* payload
239 * - DomainName (always ASCII)
240 * - WorkstationName (always ASCII)
244 /* LE (Little Endian) byte order */
245 struct challenge_message {
246 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
247 guint32 type; /* 0x00000002 */
248 struct smb_header target_name;
249 guint32 flags; /* 0x8201 */
250 guint8 nonce[8];
251 guint8 zero1[8];
252 struct smb_header target_info;
253 struct version ver;
254 /* payload
255 * - TargetName (negotiated encoding)
256 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
260 /* LE (Little Endian) byte order */
261 struct authenticate_message {
262 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
263 guint32 type; /* 0x00000003 */
264 /** LmChallengeResponseFields */
265 struct smb_header lm_resp;
266 /** NtChallengeResponseFields */
267 struct smb_header nt_resp;
268 /** DomainNameFields */
269 struct smb_header domain;
270 /** UserNameFields */
271 struct smb_header user;
272 /** WorkstationFields */
273 struct smb_header host;
274 /** EncryptedRandomSessionKeyFields */
275 struct smb_header session_key;
276 guint32 flags;
277 struct version ver;
278 //guint8 mic[16];
279 /* payload
280 * - LmChallengeResponse
281 * - NtChallengeResponse
282 * - DomainName (negotiated encoding)
283 * - UserName (negotiated encoding)
284 * - Workstation (negotiated encoding)
285 * - EncryptedRandomSessionKey
289 #ifndef HAVE_LANGINFO_CODESET
290 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
291 #endif
293 /* Private Methods */
295 /* Utility Functions */
296 static GIConv convert_from_utf16le = (GIConv)-1;
297 static GIConv convert_to_utf16le = (GIConv)-1;
299 static gsize
300 unicode_strconvcopy(gchar *dest, const gchar *source, gsize remlen)
302 gsize inbytes = strlen(source);
303 gsize outbytes = remlen;
304 g_iconv(convert_to_utf16le, (gchar **)&source, &inbytes, &dest, &outbytes);
305 return(remlen - outbytes);
308 /* UTF-16LE to native encoding
309 * Must be g_free'd after use */
310 static gchar *
311 unicode_strconvcopy_back(const gchar *source, gsize len)
313 gsize outbytes = 2 * len;
314 gchar *dest = g_new0(gchar, outbytes + 1);
315 gchar *outbuf = dest;
316 g_iconv(convert_from_utf16le, (gchar **)&source, &len, &outbuf, &outbytes);
317 return dest;
320 /* crc32 source copy from gg's common.c */
321 static guint32 crc32_table[256];
322 static int crc32_initialized = 0;
324 static void crc32_make_table()
326 guint32 h = 1;
327 unsigned int i, j;
329 memset(crc32_table, 0, sizeof(crc32_table));
331 for (i = 128; i; i >>= 1) {
332 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
334 for (j = 0; j < 256; j += 2 * i)
335 crc32_table[i + j] = crc32_table[j] ^ h;
338 crc32_initialized = 1;
341 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
343 if (!crc32_initialized)
344 crc32_make_table();
346 if (!buf || len < 0)
347 return crc;
349 crc ^= 0xffffffffL;
351 while (len--)
352 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
354 return crc ^ 0xffffffffL;
357 static guint32
358 CRC32 (const char *msg, int len)
360 guint32 crc = 0L;
361 crc = crc32(crc, (guint8 *) msg, len);
362 return crc;
365 /* Cyphers */
367 #ifdef _SIPE_COMPILING_TESTS
368 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
370 key[0] = key_56[0];
371 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
372 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
373 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
374 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
375 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
376 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
377 key[7] = (key_56[6] << 1) & 0xFF;
380 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
382 PurpleCipherContext *context;
383 size_t outlen;
385 context = purple_cipher_context_new_by_name("des", NULL);
386 purple_cipher_context_set_key(context, (guchar*)key);
387 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
388 purple_cipher_context_destroy(context);
391 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
392 static void
393 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
395 unsigned char key[8];
396 setup_des_key(k, key);
397 des_ecb_encrypt(d, results, key);
400 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
401 static void
402 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
404 unsigned char keys[21];
406 /* Copy the first 16 bytes */
407 memcpy(keys, k, 16);
409 /* Zero out the last 5 bytes of the key */
410 memset(keys + 16, 0, 5);
412 DES(keys, d, results);
413 DES(keys + 7, d, results + 8);
414 DES(keys + 14, d, results + 16);
416 #endif
418 static void
419 RC4K (const unsigned char * k, unsigned long key_len, const unsigned char * d, int len, unsigned char * result)
421 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
422 purple_cipher_context_set_option(context, "key_len", (gpointer)key_len);
423 purple_cipher_context_set_key(context, k);
424 purple_cipher_context_encrypt(context, (const guchar *)d, len, result, NULL);
425 purple_cipher_context_destroy(context);
428 /* out 16 bytes */
429 #define MD4(d, len, result) sipe_backend_digest_md4((d), (len), (result))
431 /* out 16 bytes */
432 #define MD5(d, len, result) sipe_backend_digest_md5((d), (len), (result))
434 /* out 16 bytes */
436 static void
437 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
439 int i;
440 unsigned char ibuff[64 + data_len];
441 unsigned char obuff[64 + 16];
443 if (key_len > 64)
444 key_len = 64;
446 for (i = 0; i < key_len; i++) {
447 ibuff[i] = key[i] ^ 0x36;
448 obuff[i] = key[i] ^ 0x5c;
450 for (i = key_len; i < 64; i++) {
451 ibuff[i] = 0x36;
452 obuff[i] = 0x5c;
455 memcpy(ibuff+64, data, data_len);
457 MD5 (ibuff, 64 + data_len, obuff+64);
458 MD5 (obuff, 64 + 16, result);
460 #define HMAC_MD5 HMACT64
463 /* out 16 bytes */
464 static void
465 HMAC_MD5 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
467 PurpleCipherContext *context = purple_cipher_context_new_by_name("hmac", NULL);
469 purple_cipher_context_set_option(context, "hash", "md5");
470 purple_cipher_context_set_key_with_len(context, (guchar *)key, (key_len));
472 purple_cipher_context_append(context, (guchar *)data, data_len);
473 purple_cipher_context_digest(context, 16, (guchar*)result, NULL);
474 purple_cipher_context_destroy(context);
477 /* NTLM Core Methods */
479 static void
480 NONCE(unsigned char *buffer, int num)
482 int i;
483 for (i = 0; i < num; i++) {
484 buffer[i] = (rand() & 0xff);
488 #ifdef _SIPE_COMPILING_TESTS
489 static void
490 Z(unsigned char *buffer, int num)
492 memset(buffer, 0, num);
495 static void
496 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
498 /* "KGS!@#$%" */
499 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
500 unsigned char uppercase_password[14];
501 int i;
503 int len = strlen(password);
504 if (len > 14) {
505 len = 14;
508 // Uppercase password
509 for (i = 0; i < len; i++) {
510 uppercase_password[i] = g_ascii_toupper(password[i]);
513 // Zero the rest
514 for (; i < 14; i++) {
515 uppercase_password[i] = 0;
518 DES (uppercase_password, magic, result);
519 DES (uppercase_password + 7, magic, result + 8);
521 #endif
524 Define NTOWFv1(Passwd, User, UserDom) as
525 MD4(UNICODE(Passwd))
526 EndDefine
528 /* out 16 bytes */
529 static void
530 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
532 int len_u = 2 * strlen(password); // utf16 should not be more
533 unsigned char unicode_password[len_u];
535 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
536 MD4 (unicode_password, len_u, result);
540 Define NTOWFv2(Passwd, User, UserDom) as
541 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
542 EndDefine
544 /* out 16 bytes */
545 void
546 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
548 unsigned char response_key_nt_v1 [16];
549 int len_user = user ? strlen(user) : 0;
550 int len_domain = domain ? strlen(domain) : 0;
551 unsigned char user_upper[len_user + 1];
552 int len_user_u = 2 * len_user; // utf16 should not be more
553 int len_domain_u = 2 * len_domain; // utf16 should not be more
554 unsigned char buff[(len_user + len_domain)*2];
555 int i;
557 /* Uppercase user */
558 for (i = 0; i < len_user; i++) {
559 user_upper[i] = g_ascii_toupper(user[i]);
561 user_upper[len_user] = 0;
563 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
564 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
566 NTOWFv1(password, user, domain, response_key_nt_v1);
568 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
571 static void
572 compute_response(const guint32 neg_flags,
573 const unsigned char *response_key_nt,
574 const unsigned char *response_key_lm,
575 const guint8 *server_challenge,
576 const guint8 *client_challenge,
577 const guint64 time_val,
578 const guint8 *target_info,
579 int target_info_len,
580 unsigned char *lm_challenge_response,
581 unsigned char *nt_challenge_response,
582 unsigned char *session_base_key)
584 #ifdef _SIPE_COMPILING_TESTS
585 if (use_ntlm_v2)
587 #endif
589 Responserversion - The 1-byte response version. Currently set to 1.
590 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
591 Time - The 8-byte little-endian time in GMT.
592 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
593 ClientChallenge - The 8-byte challenge message generated by the client.
594 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
596 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
597 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
598 Time, //8bytes - 8
599 ClientChallenge, //8bytes - 16
600 Z(4), //4bytes - 24
601 ServerName, //variable - 28
602 Z(4)) //4bytes - 28+target_info_len
603 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
604 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
605 Set LmChallengeResponse to ConcatenationOf(
606 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
607 ClientChallenge )
608 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
609 EndDefine
611 guint8 tmp [16];
612 guint8 nt_proof_str [16];
614 /* client_challenge (8) & temp (temp_len) buff */
615 int temp_len = 8+8+8+4+target_info_len+4;
616 guint8 temp2 [8 + temp_len];
617 memset(temp2, 0, 8 + temp_len); /* init to 0 */
618 temp2[8+0] = 1;
619 temp2[8+1] = 1;
620 *((guint64 *)(temp2+8+8)) = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
621 memcpy(temp2+8+16, client_challenge, 8);
622 memcpy(temp2+8+28, target_info, target_info_len);
624 /* NTProofStr */
625 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
626 memcpy(temp2, server_challenge, 8);
627 HMAC_MD5(response_key_nt, 16, temp2, 8+temp_len, nt_proof_str);
629 /* NtChallengeResponse */
630 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
631 memcpy(nt_challenge_response, nt_proof_str, 16);
632 memcpy(nt_challenge_response+16, temp2+8, temp_len);
634 /* SessionBaseKey */
635 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
636 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
638 /* lm_challenge_response */
639 memcpy(tmp, server_challenge, 8);
640 memcpy(tmp+8, client_challenge, 8);
641 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
642 memcpy(lm_challenge_response+16, client_challenge, 8);
644 #ifndef _SIPE_COMPILING_TESTS
645 /* Not used in NTLMv2 */
646 (void)neg_flags;
647 #else
649 else
651 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
652 // @TODO do not even reference nt_challenge_response
653 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
654 DESL (response_key_lm, server_challenge, lm_challenge_response);
655 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
656 unsigned char prehash [16];
657 unsigned char hash [16];
659 /* nt_challenge_response */
660 memcpy(prehash, server_challenge, 8);
661 memcpy(prehash + 8, client_challenge, 8);
662 MD5 (prehash, 16, hash);
663 DESL (response_key_nt, hash, nt_challenge_response);
665 /* lm_challenge_response */
666 memcpy(lm_challenge_response, client_challenge, 8);
667 Z (lm_challenge_response+8, 16);
668 } else {
669 DESL (response_key_nt, server_challenge, nt_challenge_response);
670 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
671 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
672 } else {
673 DESL (response_key_lm, server_challenge, lm_challenge_response);
677 /* Session Key */
678 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
680 #endif
683 static void
684 KXKEY ( guint32 flags,
685 const unsigned char * session_base_key,
686 const unsigned char * lm_challenge_resonse,
687 const guint8 * server_challenge, /* 8-bytes, nonce */
688 unsigned char * key_exchange_key)
690 #ifdef _SIPE_COMPILING_TESTS
691 if (use_ntlm_v2)
693 #else
694 /* Not used in NTLMv2 */
695 (void)flags;
696 (void)lm_challenge_resonse;
697 (void)server_challenge;
698 #endif
699 memcpy(key_exchange_key, session_base_key, 16);
700 #ifdef _SIPE_COMPILING_TESTS
702 else
704 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
705 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
706 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
707 EndDefine
709 guint8 tmp[16];
710 memcpy(tmp, server_challenge, 8);
711 memcpy(tmp+8, lm_challenge_resonse, 8);
712 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
713 } else {
714 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
715 memcpy(key_exchange_key, session_base_key, 16);
718 #endif
722 If (Mode equals "Client")
723 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
724 "session key to client-to-server signing key magic constant"))
725 Else
726 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
727 "session key to server-to-client signing key magic constant"))
728 Endif
730 static void
731 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
733 char * magic = client
734 ? "session key to client-to-server signing key magic constant"
735 : "session key to server-to-client signing key magic constant";
737 int len = strlen(magic) + 1;
738 unsigned char md5_input [16 + len];
739 memcpy(md5_input, random_session_key, 16);
740 memcpy(md5_input + 16, magic, len);
742 MD5 (md5_input, len + 16, result);
746 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
747 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
748 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
749 Set SealKey to RandomSessionKey
750 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
751 Set SealKey to RandomSessionKey[0..6]
752 Else
753 Set SealKey to RandomSessionKey[0..4]
754 Endif
756 If (Mode equals "Client")
757 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
758 Else
759 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
760 Endif
762 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
763 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
764 Else
765 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
766 Endif
767 EndDefine
769 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
770 static void
771 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
773 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
775 char * magic = client
776 ? "session key to client-to-server sealing key magic constant"
777 : "session key to server-to-client sealing key magic constant";
779 int len = strlen(magic) + 1;
780 unsigned char md5_input [16 + len];
781 int key_len;
783 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
784 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
785 key_len = 16;
786 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
787 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
788 key_len = 7;
789 } else {
790 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
791 key_len = 5;
794 memcpy(md5_input, random_session_key, key_len);
795 memcpy(md5_input + key_len, magic, len);
797 MD5 (md5_input, key_len + len, result);
799 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
801 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
802 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
803 memcpy(result, random_session_key, 7);
804 result[7] = 0xA0;
805 } else {
806 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
807 memcpy(result, random_session_key, 5);
808 result[5] = 0xE5;
809 result[6] = 0x38;
810 result[7] = 0xB0;
813 else
815 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
816 memcpy(result, random_session_key, 16);
821 = for Extended Session Security =
822 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
823 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
824 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
826 = if Extended Session Security is NOT negotiated =
827 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
828 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
829 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
830 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
832 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
834 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
835 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
837 /** MAC(Handle, SigningKey, SeqNum, Message) */
838 /* out 16 bytes */
839 static void
840 MAC (guint32 flags,
841 const char *buf,
842 int buf_len,
843 unsigned char *sign_key,
844 unsigned long sign_key_len,
845 unsigned char *seal_key,
846 unsigned long seal_key_len,
847 guint32 random_pad,
848 guint32 sequence,
849 unsigned char *result)
851 guint32 *res_ptr;
853 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
855 Define MAC(Handle, SigningKey, SeqNum, Message) as
856 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
857 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
858 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
859 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
860 Set SeqNum to SeqNum + 1
861 EndDefine
863 /* If a key exchange key is negotiated
864 Define MAC(Handle, SigningKey, SeqNum, Message) as
865 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
866 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
867 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
868 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
869 Set SeqNum to SeqNum + 1
870 EndDefine
873 unsigned char seal_key_ [16];
874 guchar hmac[16];
875 guchar tmp[4 + buf_len];
877 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
878 RC4Init(Handle, SealingKey')
880 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
881 unsigned char tmp2 [16+4];
883 memcpy(tmp2, seal_key, seal_key_len);
884 *((guint32 *)(tmp2+16)) = GUINT32_TO_LE(sequence);
885 MD5 (tmp2, 16+4, seal_key_);
886 } else {
887 memcpy(seal_key_, seal_key, seal_key_len);
890 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extented Session Security");
892 res_ptr = (guint32 *)result;
893 res_ptr[0] = GUINT32_TO_LE(1); // 4 bytes
894 res_ptr[3] = GUINT32_TO_LE(sequence);
896 res_ptr = (guint32 *)tmp;
897 res_ptr[0] = GUINT32_TO_LE(sequence);
898 memcpy(tmp+4, buf, buf_len);
900 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
902 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
903 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
904 RC4K(seal_key_, seal_key_len, hmac, 8, result+4);
905 } else {
906 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
907 memcpy(result+4, hmac, 8);
909 } else {
910 /* The content of the first 4 bytes is irrelevant */
911 guint32 crc = CRC32(buf, strlen(buf));
912 guint32 plaintext [] = {
913 GUINT32_TO_LE(0),
914 GUINT32_TO_LE(crc),
915 GUINT32_TO_LE(sequence)
916 }; // 4, 4, 4 bytes
918 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extented Session Security");
920 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, result+4);
922 res_ptr = (guint32 *)result;
923 // Highest four bytes are the Version
924 res_ptr[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
926 // Replace the first four bytes of the ciphertext with the random_pad
927 res_ptr[1] = GUINT32_TO_LE(random_pad); // 4 bytes
931 /* End Core NTLM Methods */
934 * @param flags (out) flags received from server
935 * @param server_challenge must be g_free()'d after use if requested
936 * @param target_info must be g_free()'d after use if requested
938 static void
939 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff,
940 guint32 *flags,
941 guchar **server_challenge, /* 8 bytes */
942 guint64 *time_val,
943 guchar **target_info,
944 int *target_info_len)
946 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
947 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
949 /* server challenge (nonce) */
950 if (server_challenge) {
951 *server_challenge = g_memdup(cmsg->nonce, 8);
954 /* flags */
955 if (flags) {
956 *flags = host_flags;
959 /* target_info */
960 if (cmsg->target_info.len && cmsg->target_info.offset) {
961 void *content = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
962 void *av = content;
963 guint16 len = GUINT16_FROM_LE(cmsg->target_info.len);
965 ALIGN_AV_LOOP_START
967 /* @since Vista */
968 case MsvAvTimestamp:
969 if (time_val) {
970 guint64 tmp;
972 /* to meet sparc's alignment requirement */
973 memcpy(&tmp, av_value, sizeof(tmp));
974 *time_val = GUINT64_FROM_LE(tmp);
976 break;
978 ALIGN_AV_LOOP_END;
980 if (target_info_len) {
981 *target_info_len = len;
983 if (target_info) {
984 *target_info = g_memdup(content, len);
990 * @param client_sign_key (out) must be g_free()'d after use
991 * @param server_sign_key (out) must be g_free()'d after use
992 * @param client_seal_key (out) must be g_free()'d after use
993 * @param server_seal_key (out) must be g_free()'d after use
994 * @param flags (in, out) negotiated flags
996 static sip_uint32
997 sip_sec_ntlm_gen_authenticate(guchar **client_sign_key,
998 guchar **server_sign_key,
999 guchar **client_seal_key,
1000 guchar **server_seal_key,
1001 const gchar *user,
1002 const gchar *password,
1003 const gchar *hostname,
1004 const gchar *domain,
1005 const guint8 *server_challenge, /* nonce */
1006 const guint64 time_val,
1007 const guint8 *target_info,
1008 int target_info_len,
1009 gboolean is_connection_based,
1010 SipSecBuffer *out_buff,
1011 guint32 *flags)
1013 guint32 orig_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS_CONNLESS;
1014 guint32 neg_flags = (*flags & orig_flags) | NTLMSSP_REQUEST_TARGET;
1015 int ntlmssp_nt_resp_len =
1016 #ifdef _SIPE_COMPILING_TESTS
1017 use_ntlm_v2 ?
1018 #endif
1019 (16 + (32+target_info_len))
1020 #ifdef _SIPE_COMPILING_TESTS
1021 : NTLMSSP_LM_RESP_LEN
1022 #endif
1024 gsize msglen = sizeof(struct authenticate_message)
1025 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1026 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1027 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1028 struct authenticate_message *tmsg;
1029 char *tmp;
1030 guint32 offset;
1031 guint16 len;
1032 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1033 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1034 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1035 unsigned char nt_challenge_response [ntlmssp_nt_resp_len]; /* variable or 24 */
1036 unsigned char session_base_key [16];
1037 unsigned char key_exchange_key [16];
1038 unsigned char exported_session_key[16];
1039 unsigned char encrypted_random_session_key [16];
1040 unsigned char key [16];
1041 unsigned char client_challenge [8];
1042 guint64 time_vl = time_val ? time_val : TIME_T_TO_VAL(time(NULL));
1044 if (!IS_FLAG(*flags, NEGOTIATE_FLAGS_COMMON_MIN) ||
1045 !(is_connection_based || IS_FLAG(*flags, NEGOTIATE_FLAGS_CONNLESS_EXTRA)))
1047 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1048 return SIP_SEC_E_INTERNAL_ERROR;
1051 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_128)) {
1052 neg_flags = neg_flags & ~NTLMSSP_NEGOTIATE_56;
1055 tmsg = g_malloc0(msglen);
1057 NONCE (client_challenge, 8);
1059 #ifdef _SIPE_COMPILING_TESTS
1060 memcpy(client_challenge, test_client_challenge, 8);
1061 time_vl = test_time_val ? test_time_val : time_vl;
1063 if (use_ntlm_v2) {
1065 #endif
1066 NTOWFv2 (password, user, domain, response_key_nt);
1067 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1068 #ifdef _SIPE_COMPILING_TESTS
1069 } else {
1070 NTOWFv1 (password, user, domain, response_key_nt);
1071 LMOWFv1 (password, user, domain, response_key_lm);
1073 #endif
1075 compute_response(neg_flags,
1076 response_key_nt,
1077 response_key_lm,
1078 server_challenge,
1079 client_challenge,
1080 time_vl,
1081 target_info,
1082 target_info_len,
1083 lm_challenge_response, /* out */
1084 nt_challenge_response, /* out */
1085 session_base_key); /* out */
1087 /* same as session_base_key for
1088 * - NTLNv1 w/o Ext.Sess.Sec and
1089 * - NTLMv2
1091 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1093 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1094 NONCE (exported_session_key, 16); // random master key
1095 #ifdef _SIPE_COMPILING_TESTS
1096 memcpy(exported_session_key, test_random_session_key, 16);
1097 #endif
1098 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1099 } else {
1100 memcpy(exported_session_key, key_exchange_key, 16);
1103 tmp = buff_to_hex_str(exported_session_key, 16);
1104 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp);
1105 g_free(tmp);
1107 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SIGN) ||
1108 IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_SEAL))
1110 /* p.46
1111 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1112 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1114 SIGNKEY(exported_session_key, TRUE, key);
1115 *client_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1116 SIGNKEY(exported_session_key, FALSE, key);
1117 *server_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1118 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1119 *client_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1120 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1121 *server_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1124 /* @TODO: */
1125 /* @since Vista
1126 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1127 the client SHOULD provide a MIC:
1128 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1129 - then in the Value field, set bit 0x2 to 1.
1130 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1131 and the Value field bit 0x2 to 1.
1132 - Populate the MIC field with the MIC.
1135 /* Connection-oriented:
1136 Set MIC to HMAC_MD5(ExportedSessionKey,
1137 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1138 Connectionless:
1139 Set MIC to HMAC_MD5(ExportedSessionKey,
1140 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1143 /* on the server-side:
1144 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1145 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1146 Set MIC to HMAC_MD5(ExportedSessionKey,
1147 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1148 Else
1149 Set ExportedSessionKey to KeyExchangeKey
1150 Set MIC to HMAC_MD5(KeyExchangeKey,
1151 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1152 =====
1153 @since Vista
1154 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1155 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1156 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1157 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1158 an AV_PAIR structure whose two fields:
1159 - AvId == MsvAvFlags
1160 - Value bit 0x2 == 1
1161 @supported NT, 2000, XP
1162 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1163 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1164 the server time, then the server SHOULD return a failure.
1166 Connectionless:
1167 Set MIC to HMAC_MD5(ResponseKeyNT,
1168 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1171 /* authenticate message initialization */
1172 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1173 tmsg->type = GUINT32_TO_LE(3);
1175 /* Initial offset */
1176 offset = sizeof(struct authenticate_message);
1177 tmp = ((char*) tmsg) + offset;
1179 #define _FILL_SMB_HEADER(header) \
1180 tmsg->header.offset = GUINT32_TO_LE(offset); \
1181 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1182 tmp += len; \
1183 offset += len
1184 #define _APPEND_STRING(header, src) \
1185 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1186 _FILL_SMB_HEADER(header)
1187 #define _APPEND_DATA(header, src, srclen) \
1188 len = (srclen); \
1189 memcpy(tmp, (src), len); \
1190 _FILL_SMB_HEADER(header)
1192 /* Domain */
1193 _APPEND_STRING(domain, domain);
1195 /* User */
1196 _APPEND_STRING(user, user);
1198 /* Host */
1199 _APPEND_STRING(host, hostname);
1201 /* LM */
1202 /* @since Windows 7
1203 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1204 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1205 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1207 _APPEND_DATA(lm_resp, lm_challenge_response, NTLMSSP_LM_RESP_LEN);
1209 /* NT */
1210 _APPEND_DATA(nt_resp, nt_challenge_response, ntlmssp_nt_resp_len);
1212 /* Session Key */
1213 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1215 _APPEND_DATA(session_key, encrypted_random_session_key, NTLMSSP_SESSION_KEY_LEN);
1217 else
1219 tmsg->session_key.offset = GUINT32_TO_LE(offset);
1220 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1223 /* Version */
1224 #ifdef _SIPE_COMPILING_TESTS
1225 memcpy(&(tmsg->ver), &test_version, sizeof(struct version));
1226 #else
1227 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_VERSION)) {
1228 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1229 tmsg->ver.product_minor_version = 1;
1230 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1231 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1233 #endif
1235 /* Set Negotiate Flags */
1236 tmsg->flags = GUINT32_TO_LE(neg_flags);
1237 *flags = neg_flags;
1239 out_buff->value = (guint8 *)tmsg;
1240 out_buff->length = msglen;
1242 return SIP_SEC_E_OK;
1246 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1248 static void
1249 sip_sec_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1251 guint32 offset;
1252 guint16 len;
1253 int msglen = sizeof(struct negotiate_message);
1254 struct negotiate_message *tmsg = g_malloc0(msglen);
1256 /* negotiate message initialization */
1257 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1258 tmsg->type = GUINT32_TO_LE(1);
1260 /* Set Negotiate Flags */
1261 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1263 /* Domain */
1264 offset = sizeof(struct negotiate_message);
1265 tmsg->domain.offset = GUINT32_TO_LE(offset);
1266 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1268 /* Host */
1269 offset += len;
1270 tmsg->host.offset = GUINT32_TO_LE(offset);
1271 tmsg->host.len = tmsg->host.maxlen = len = 0;
1273 /* Version */
1274 tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1275 tmsg->ver.product_minor_version = 1;
1276 tmsg->ver.product_build = GUINT16_FROM_LE(2600);
1277 tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1279 out_buff->value = (guint8 *)tmsg;
1280 out_buff->length = msglen;
1283 static void
1284 sip_sec_ntlm_sipe_signature_make(guint32 flags,
1285 const char *msg,
1286 guint32 random_pad,
1287 unsigned char *sign_key,
1288 unsigned char *seal_key,
1289 unsigned char *result)
1291 char *res;
1293 MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100, result);
1295 res = buff_to_hex_str(result, 16);
1296 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res);
1297 g_free(res);
1301 /* Describe NTLM messages functions */
1303 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1304 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1306 static gchar *
1307 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1309 GString* str = g_string_new(NULL);
1311 flags = GUINT32_FROM_LE(flags);
1313 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1314 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1315 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1316 APPEND_NEG_FLAG(str, flags, r9, "r9");
1317 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1318 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1319 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1320 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1321 APPEND_NEG_FLAG(str, flags, r8, "r8");
1322 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1323 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1324 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1325 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1326 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1327 APPEND_NEG_FLAG(str, flags, r7, "r7");
1328 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1329 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1330 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1331 APPEND_NEG_FLAG(str, flags, r6, "r6");
1332 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1333 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1334 APPEND_NEG_FLAG(str, flags, r5, "r5");
1335 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1336 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1337 APPEND_NEG_FLAG(str, flags, r4, "r4");
1338 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1339 APPEND_NEG_FLAG(str, flags, r3, "r3");
1340 APPEND_NEG_FLAG(str, flags, r2, "r2");
1341 APPEND_NEG_FLAG(str, flags, r1, "r1");
1342 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1343 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1344 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1346 return g_string_free(str, FALSE);
1349 static gchar *
1350 sip_sec_ntlm_describe_version(struct version *ver) {
1351 GString* str = g_string_new(NULL);
1352 gchar *ver_desc = "";
1353 gchar *ntlm_revision_desc = "";
1355 if (ver->product_major_version == 6) {
1356 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1357 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1358 ver_desc = "Windows Server 2003";
1359 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1360 ver_desc = "Windows XP SP2";
1363 if (ver->ntlm_revision_current == 0x0F) {
1364 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1365 } else if (ver->ntlm_revision_current == 0x0A) {
1366 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1369 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1370 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1371 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1373 return g_string_free(str, FALSE);
1376 static gchar *
1377 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1378 const char* name)
1380 GString* str = g_string_new(NULL);
1382 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1383 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1384 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1386 return g_string_free(str, FALSE);
1389 static gchar *
1390 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1392 GString* str = g_string_new(NULL);
1393 char *tmp;
1395 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1396 g_free(tmp);
1398 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1399 g_free(tmp);
1401 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1402 g_free(tmp);
1404 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1405 g_string_append(str, tmp);
1406 g_free(tmp);
1408 if (cmsg->domain.len && cmsg->domain.offset) {
1409 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1410 g_string_append_printf(str, "\tdomain: %s\n", domain);
1411 g_free(domain);
1414 if (cmsg->host.len && cmsg->host.offset) {
1415 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1416 g_string_append_printf(str, "\thost: %s\n", host);
1417 g_free(host);
1420 return g_string_free(str, FALSE);
1423 static void
1424 describe_av_pairs(GString* str, const void *av)
1426 #define AV_DESC(av_name) \
1428 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1429 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1430 g_free(tmp); \
1433 ALIGN_AV_LOOP_START
1435 case MsvAvNbComputerName:
1436 AV_DESC("MsvAvNbComputerName");
1437 break;
1438 case MsvAvNbDomainName:
1439 AV_DESC("MsvAvNbDomainName");
1440 break;
1441 case MsvAvDnsComputerName:
1442 AV_DESC("MsvAvDnsComputerName");
1443 break;
1444 case MsvAvDnsDomainName:
1445 AV_DESC("MsvAvDnsDomainName");
1446 break;
1447 case MsvAvDnsTreeName:
1448 AV_DESC("MsvAvDnsTreeName");
1449 break;
1450 case MsvAvFlags:
1452 guint32 flags;
1454 /* to meet sparc's alignment requirement */
1455 memcpy(&flags, av_value, sizeof(guint32));
1456 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags));
1458 break;
1459 case MsvAvTimestamp:
1461 char *tmp;
1462 guint64 time_val;
1463 time_t time_t_val;
1465 /* to meet sparc's alignment requirement */
1466 memcpy(&time_val, av_value, sizeof(time_val));
1467 time_t_val = TIME_VAL_TO_T(time_val);
1469 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = buff_to_hex_str((guint8 *) av_value, 8)),
1470 asctime(gmtime(&time_t_val)));
1471 g_free(tmp);
1473 break;
1474 case MsAvRestrictions:
1475 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1476 break;
1477 case MsvAvTargetName:
1478 AV_DESC("MsvAvTargetName");
1479 break;
1480 case MsvChannelBindings:
1481 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1482 break;
1484 ALIGN_AV_LOOP_END;
1487 static gchar *
1488 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1490 GString* str = g_string_new(NULL);
1491 char *tmp;
1492 gsize value_len;
1493 guint8 *value;
1495 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1496 g_free(tmp);
1498 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1499 g_free(tmp);
1501 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1502 g_free(tmp);
1504 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1505 g_free(tmp);
1507 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1508 g_free(tmp);
1510 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1511 g_free(tmp);
1513 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1514 g_free(tmp);
1516 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1517 g_string_append(str, tmp);
1518 g_free(tmp);
1520 /* mic */
1521 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1522 //g_free(tmp);
1524 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1525 value_len = GUINT16_FROM_LE(cmsg->lm_resp.len);
1526 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1527 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = buff_to_hex_str(value, value_len)));
1528 g_free(tmp);
1531 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1532 guint16 nt_resp_len_full = GUINT16_FROM_LE(cmsg->nt_resp.len);
1533 int nt_resp_len = nt_resp_len_full;
1535 value_len = nt_resp_len_full;
1536 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1537 g_string_append_printf(str, "\t%s: %s\n", "nt_resp raw", (tmp = buff_to_hex_str(value, value_len)));
1538 g_free(tmp);
1540 if (nt_resp_len > 24) { /* NTLMv2 */
1541 nt_resp_len = 16;
1544 value_len = nt_resp_len;
1545 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1546 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = buff_to_hex_str(value, value_len)));
1547 g_free(tmp);
1549 if (nt_resp_len_full > 24) { /* NTLMv2 */
1550 /* Work around Debian/x86_64 compiler bug */
1551 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1552 const guint offset = GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1553 const guint8 *temp = (guint8 *)cmsg + offset;
1554 const guint response_version = temp[0];
1555 const guint hi_response_version = temp[1];
1556 const guint8 *client_challenge = temp + 16;
1557 const guint8 *target_info = temp + 28;
1558 guint16 target_info_len = nt_resp_len_full - 16 - 32;
1559 guint64 time_val;
1560 time_t time_t_val;
1561 char *tmp;
1563 g_string_append_printf(str, "\t%s: %s\n", "target_info raw",
1564 (tmp = buff_to_hex_str((guint8 *)target_info, target_info_len)));
1565 g_free(tmp);
1567 /* This is not int64 aligned on sparc */
1568 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1569 time_t_val = TIME_VAL_TO_T(time_val);
1571 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1572 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1574 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = buff_to_hex_str((guint8 *)&time_val, 8)),
1575 asctime(gmtime(&time_t_val)));
1576 g_free(tmp);
1578 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = buff_to_hex_str((guint8 *)client_challenge, 8)));
1579 g_free(tmp);
1581 describe_av_pairs(str, target_info);
1583 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1587 if (cmsg->domain.len && cmsg->domain.offset) {
1588 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1589 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1590 g_free(domain);
1593 if (cmsg->user.len && cmsg->user.offset) {
1594 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1595 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1596 g_free(user);
1599 if (cmsg->host.len && cmsg->host.offset) {
1600 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1601 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1602 g_free(host);
1605 if (cmsg->session_key.len && cmsg->session_key.offset) {
1606 value_len = GUINT16_FROM_LE(cmsg->session_key.len);
1607 value = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1608 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = buff_to_hex_str(value, value_len)));
1609 g_free(tmp);
1612 return g_string_free(str, FALSE);
1615 static gchar *
1616 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1618 GString* str = g_string_new(NULL);
1619 char *tmp;
1621 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1622 g_free(tmp);
1624 /* nonce (server_challenge) */
1625 g_string_append_printf(str, "\t%s: %s\n", "server_challenge", (tmp = buff_to_hex_str(cmsg->nonce, 8)));
1626 g_free(tmp);
1628 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1629 g_free(tmp);
1631 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1632 g_free(tmp);
1634 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1635 g_free(tmp);
1637 if (cmsg->target_name.len && cmsg->target_name.offset) {
1638 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1639 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1640 g_free(target_name);
1643 if (cmsg->target_info.len && cmsg->target_info.offset) {
1644 guint8 *target_info = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset);
1645 guint16 target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1647 g_string_append_printf(str, "\t%s: %s\n", "target_info raw", (tmp = buff_to_hex_str(target_info, target_info_len)));
1648 g_free(tmp);
1650 describe_av_pairs(str, target_info);
1653 return g_string_free(str, FALSE);
1656 gchar *
1657 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1659 struct ntlm_message *msg;
1660 gchar *res = NULL;
1662 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1664 msg = (struct ntlm_message *)buff.value;
1665 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1667 switch (GUINT32_FROM_LE(msg->type)) {
1668 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1669 break;
1670 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1671 break;
1672 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1673 break;
1676 return res;
1679 /* sip-sec-mech.h API implementation for NTLM */
1681 /* Security context for NTLM */
1682 typedef struct _context_ntlm {
1683 struct sip_sec_context common;
1684 char* domain;
1685 char *username;
1686 char *password;
1687 int step;
1688 guchar *client_sign_key;
1689 guchar *server_sign_key;
1690 guchar *client_seal_key;
1691 guchar *server_seal_key;
1692 guint32 flags;
1693 } *context_ntlm;
1696 static sip_uint32
1697 sip_sec_acquire_cred__ntlm(SipSecContext context,
1698 const char *domain,
1699 const char *username,
1700 const char *password)
1702 context_ntlm ctx = (context_ntlm)context;
1704 /* NTLM requires a domain, username & password */
1705 if (!domain || !username || !password)
1706 return SIP_SEC_E_INTERNAL_ERROR;
1708 ctx->domain = g_strdup(domain);
1709 ctx->username = g_strdup(username);
1710 ctx->password = g_strdup(password);
1712 return SIP_SEC_E_OK;
1715 static sip_uint32
1716 sip_sec_init_sec_context__ntlm(SipSecContext context,
1717 SipSecBuffer in_buff,
1718 SipSecBuffer *out_buff,
1719 SIPE_UNUSED_PARAMETER const char *service_name)
1721 context_ntlm ctx = (context_ntlm) context;
1723 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
1725 ctx->step++;
1726 if (ctx->step == 1) {
1727 if (!context->is_connection_based) {
1728 out_buff->length = 0;
1729 out_buff->value = NULL;
1730 } else {
1731 sip_sec_ntlm_gen_negotiate(out_buff);
1733 return SIP_SEC_I_CONTINUE_NEEDED;
1735 } else {
1736 sip_uint32 res;
1737 guchar *client_sign_key = NULL;
1738 guchar *server_sign_key = NULL;
1739 guchar *client_seal_key = NULL;
1740 guchar *server_seal_key = NULL;
1741 guchar *server_challenge = NULL;
1742 guint64 time_val = 0;
1743 guchar *target_info = NULL;
1744 int target_info_len = 0;
1745 guint32 flags;
1746 gchar *tmp;
1748 if (!in_buff.value || !in_buff.length) {
1749 return SIP_SEC_E_INTERNAL_ERROR;
1752 sip_sec_ntlm_parse_challenge(in_buff,
1753 &flags,
1754 &server_challenge, /* 8 bytes */
1755 &time_val,
1756 &target_info,
1757 &target_info_len);
1759 res = sip_sec_ntlm_gen_authenticate(
1760 &client_sign_key,
1761 &server_sign_key,
1762 &client_seal_key,
1763 &server_seal_key,
1764 ctx->username,
1765 ctx->password,
1766 (tmp = g_ascii_strup(g_get_host_name(), -1)),
1767 ctx->domain,
1768 server_challenge,
1769 time_val,
1770 target_info,
1771 target_info_len,
1772 context->is_connection_based,
1773 out_buff,
1774 &flags);
1775 g_free(server_challenge);
1776 g_free(target_info);
1777 g_free(tmp);
1779 if (res != SIP_SEC_E_OK) {
1780 g_free(client_sign_key);
1781 g_free(server_sign_key);
1782 g_free(client_seal_key);
1783 g_free(server_seal_key);
1784 return res;
1787 g_free(ctx->client_sign_key);
1788 ctx->client_sign_key = client_sign_key;
1790 g_free(ctx->server_sign_key);
1791 ctx->server_sign_key = server_sign_key;
1793 g_free(ctx->client_seal_key);
1794 ctx->client_seal_key = client_seal_key;
1796 g_free(ctx->server_seal_key);
1797 ctx->server_seal_key = server_seal_key;
1799 ctx->flags = flags;
1800 return SIP_SEC_E_OK;
1805 * @param message a NULL terminated string to sign
1808 static sip_uint32
1809 sip_sec_make_signature__ntlm(SipSecContext context,
1810 const char *message,
1811 SipSecBuffer *signature)
1813 signature->length = 16;
1814 signature->value = g_malloc0(16);
1816 /* FIXME? We always use a random_pad of 0 */
1817 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1818 message,
1820 ((context_ntlm) context)->client_sign_key,
1821 ((context_ntlm) context)->client_seal_key,
1822 signature->value);
1823 return SIP_SEC_E_OK;
1827 * @param message a NULL terminated string to check signature of
1828 * @return SIP_SEC_E_OK on success
1830 static sip_uint32
1831 sip_sec_verify_signature__ntlm(SipSecContext context,
1832 const char *message,
1833 SipSecBuffer signature)
1835 guint8 mac[16];
1836 guint32 random_pad = GUINT32_FROM_LE(((guint32 *) signature.value)[1]);
1838 sip_sec_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1839 message,
1840 random_pad,
1841 ((context_ntlm) context)->server_sign_key,
1842 ((context_ntlm) context)->server_seal_key,
1843 mac);
1844 return(memcmp(signature.value, mac, 16) ?
1845 SIP_SEC_E_INTERNAL_ERROR :
1846 SIP_SEC_E_OK);
1849 static void
1850 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1852 context_ntlm ctx = (context_ntlm) context;
1854 g_free(ctx->domain);
1855 g_free(ctx->username);
1856 g_free(ctx->password);
1857 g_free(ctx->client_sign_key);
1858 g_free(ctx->server_sign_key);
1859 g_free(ctx->client_seal_key);
1860 g_free(ctx->server_seal_key);
1861 g_free(ctx);
1864 SipSecContext
1865 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1867 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1868 if (!context) return(NULL);
1870 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1871 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1872 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1873 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1874 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1876 return((SipSecContext) context);
1879 void sip_sec_init__ntlm(void)
1881 #ifdef HAVE_LANGINFO_CODESET
1882 const char *sys_cp = nl_langinfo(CODESET);
1883 #else
1884 const char *sys_cp = SIPE_DEFAULT_CODESET;
1885 #endif /* HAVE_LANGINFO_CODESET */
1887 /* fall back to utf-8 */
1888 if (!sys_cp) sys_cp = "UTF-8";
1890 convert_from_utf16le = g_iconv_open(sys_cp, "UTF-16LE");
1891 if (convert_from_utf16le == (GIConv)-1) {
1892 SIPE_DEBUG_ERROR("g_iconv_open from UTF-16LE to %s failed",
1893 sys_cp);
1896 convert_to_utf16le = g_iconv_open("UTF-16LE", sys_cp);
1897 if (convert_from_utf16le == (GIConv)-1) {
1898 SIPE_DEBUG_ERROR("g_iconv_open from %s to UTF-16LE failed",
1899 sys_cp);
1903 void sip_sec_destroy__ntlm(void)
1905 g_iconv_close(convert_to_utf16le);
1906 g_iconv_close(convert_from_utf16le);
1910 Local Variables:
1911 mode: c
1912 c-file-style: "bsd"
1913 indent-tabs-mode: t
1914 tab-width: 8
1915 End: