NTLM: remove random pad from v1 plaintext
[siplcs.git] / src / core / sip-sec-ntlm.c
blob64c6b812bb1934cbbc53453828f1fa186df18305
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
31 #include <glib.h>
32 #include <glib/gprintf.h>
33 #include <stdio.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include "debug.h"
39 #ifndef _WIN32
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <sys/types.h>
43 #include <netinet/in.h>
44 #include <net/if.h>
45 #else /* _WIN32 */
46 #include "libc_interface.h"
47 #ifdef _DLL
48 #define _WS2TCPIP_H_
49 #define _WINSOCK2API_
50 #define _LIBC_INTERNAL_
51 #endif /* _DLL */
52 #include "network.h"
53 #include "internal.h"
54 #endif /* _WIN32 */
56 #ifdef HAVE_LANGINFO_CODESET
57 #include <langinfo.h>
58 #endif /* HAVE_LANGINFO_CODESET */
60 #include "util.h"
61 #include "cipher.h"
63 #include "sipe.h"
64 #include "sipe-utils.h"
65 #include "sip-sec-mech.h"
66 #include "sip-sec-ntlm.h"
68 /* [MS-NLMP] */
69 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
70 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
71 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
72 #define r9 0x00000008 /* r9 */
73 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
74 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
75 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
76 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
77 #define r8 0x00000100 /* r8 */
78 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
79 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
80 #define anonymous 0x00000800 /* J */
81 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
82 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
83 #define r7 0x00004000 /* r7 */
84 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
85 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
86 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
87 #define r6 0x00040000 /* r6 */
88 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
89 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
90 #define r5 0x00200000 /* r5 */
91 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
92 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
93 #define r4 0x01000000 /* r4 */
94 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
95 #define r3 0x04000000 /* r3 */
96 #define r2 0x08000000 /* r2 */
97 #define r1 0x10000000 /* r1 */
98 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
99 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
100 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
102 /* AvId */
103 #define MsvAvEOL 0
104 #define MsvAvNbComputerName 1
105 #define MsvAvNbDomainName 2
106 #define MsvAvDnsComputerName 3
107 #define MsvAvDnsDomainName 4
108 /** @since Windows XP */
109 #define MsvAvDnsTreeName 5
110 /** @since Windows XP */
111 #define MsvAvFlags 6
112 /** @since Windows Vista */
113 #define MsvAvTimestamp 7
114 /** @since Windows Vista */
115 #define MsAvRestrictions 8
116 /** @since Windows 7 */
117 #define MsvAvTargetName 9
118 /** @since Windows 7 */
119 #define MsvChannelBindings 10
121 /***********************************************
123 * Start of merged code from original sip-ntlm.c
125 ***********************************************/
127 /* Negotiate flags required in connection-oriented NTLM */
128 #define NEGOTIATE_FLAGS_CONN \
129 ( NTLMSSP_NEGOTIATE_UNICODE | \
130 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
131 NTLMSSP_REQUEST_TARGET | \
132 NTLMSSP_NEGOTIATE_NTLM | \
133 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
136 /* Negotiate flags required in connectionless NTLM */
137 #define NEGOTIATE_FLAGS \
138 ( NTLMSSP_NEGOTIATE_UNICODE | \
139 NTLMSSP_NEGOTIATE_SIGN | \
140 NTLMSSP_NEGOTIATE_DATAGRAM | \
141 NTLMSSP_NEGOTIATE_NTLM | \
142 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
143 NTLMSSP_NEGOTIATE_KEY_EXCH )
145 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
147 #define NTLMSSP_NT_OR_LM_KEY_LEN 24
148 #define NTLMSSP_SESSION_KEY_LEN 16
149 #define MD4_DIGEST_LEN 16
150 #define MD5_DIGEST_LEN 16
152 #define IS_FLAG(flags, flag) ((flags & flag) == flag)
154 struct av_pair {
155 guint16 av_id;
156 guint16 av_len;
157 /* value */
160 /* 8 bytes */
161 struct version {
162 guint8 product_major_version;
163 guint8 product_minor_version;
164 guint16 product_build;
165 guint8 zero2[3];
166 guint8 ntlm_revision_current;
169 /* 8 bytes */
170 struct smb_header {
171 guint16 len;
172 guint16 maxlen;
173 guint32 offset;
176 struct ntlm_message {
177 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
178 guint32 type; /* 0x00000003 */
181 struct negotiate_message {
182 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
183 guint32 type; /* 0x00000001 */
184 guint32 flags; /* 0xb203 */
185 struct smb_header domain;
186 struct smb_header host;
187 struct version ver;
188 /* payload
189 * - DomainName (always ASCII)
190 * - WorkstationName (always ASCII)
194 struct challenge_message {
195 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
196 guint32 type; /* 0x00000002 */
197 struct smb_header target_name;
198 guint32 flags; /* 0x8201 */
199 guint8 nonce[8];
200 guint8 zero1[8];
201 struct smb_header target_info;
202 struct version ver;
203 /* payload
204 * - TargetName (negotiated encoding)
205 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
209 struct authenticate_message {
210 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
211 guint32 type; /* 0x00000003 */
212 /** LmChallengeResponseFields */
213 struct smb_header lm_resp;
214 /** NtChallengeResponseFields */
215 struct smb_header nt_resp;
216 /** DomainNameFields */
217 struct smb_header domain;
218 /** UserNameFields */
219 struct smb_header user;
220 /** WorkstationFields */
221 struct smb_header host;
222 /** EncryptedRandomSessionKeyFields */
223 struct smb_header session_key;
224 guint32 flags;
225 struct version ver;
226 guint8 mic[16];
227 /* payload
228 * - LmChallengeResponse
229 * - NtChallengeResponse
230 * - DomainName (negotiated encoding)
231 * - UserName (negotiated encoding)
232 * - Workstation (negotiated encoding)
233 * - EncryptedRandomSessionKey
237 #ifndef HAVE_LANGINFO_CODESET
238 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
239 #endif
241 /* Private Methods */
243 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
245 key[0] = key_56[0];
246 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
247 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
248 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
249 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
250 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
251 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
252 key[7] = (key_56[6] << 1) & 0xFF;
255 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
257 PurpleCipher *cipher;
258 PurpleCipherContext *context;
259 size_t outlen;
261 cipher = purple_ciphers_find_cipher("des");
262 context = purple_cipher_context_new(cipher, NULL);
263 purple_cipher_context_set_key(context, (guchar*)key);
264 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
265 purple_cipher_context_destroy(context);
268 static int
269 unicode_strconvcopy_dir(gchar *dest, const gchar *source, int remlen, gsize source_len, gboolean to_16LE)
271 GIConv fd;
272 gchar *inbuf = (gchar *) source;
273 gchar *outbuf = dest;
274 gsize inbytes = source_len;
275 gsize outbytes = remlen;
276 #ifdef HAVE_LANGINFO_CODESET
277 char *sys_cp = nl_langinfo(CODESET);
278 #else
279 char *sys_cp = SIPE_DEFAULT_CODESET;
280 #endif /* HAVE_LANGINFO_CODESET */
282 /* fall back to utf-8 */
283 if (!sys_cp) sys_cp = "UTF-8";
285 fd = to_16LE ? g_iconv_open("UTF-16LE", sys_cp) : g_iconv_open(sys_cp, "UTF-16LE");
286 if( fd == (GIConv)-1 ) {
287 purple_debug_error( "sipe", "iconv_open returned -1, cannot continue\n" );
289 g_iconv(fd, &inbuf, &inbytes, &outbuf, &outbytes);
290 g_iconv_close(fd);
291 return (remlen - outbytes);
294 static int
295 unicode_strconvcopy(gchar *dest, const gchar *source, int remlen)
297 return unicode_strconvcopy_dir(dest, source, remlen, strlen(source), TRUE);
300 /* UTF-16LE to native encoding
301 * Must be g_free'd after use */
302 static gchar *
303 unicode_strconvcopy_back(const gchar *source,
304 int len)
306 char *res = NULL;
307 int dest_len = 2 * len;
308 gchar *dest = g_new0(gchar, dest_len);
310 dest_len = unicode_strconvcopy_dir(dest, source, dest_len, len, FALSE);
311 res = g_strndup(dest, dest_len);
312 g_free(dest);
314 return res;
317 // (k = 7 byte key, d = 8 byte data) returns 8 bytes in results
318 static void
319 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
321 unsigned char key[8];
322 setup_des_key(k, key);
323 des_ecb_encrypt(d, results, key);
326 // (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results:
327 static void
328 DESL (unsigned char *k, const unsigned char *d, unsigned char * results)
330 unsigned char keys[21];
332 // Copy the first 16 bytes
333 memcpy(keys, k, 16);
335 // Zero out the last 5 bytes of the key
336 memset(keys + 16, 0, 5);
338 DES(keys, d, results);
339 DES(keys + 7, d, results + 8);
340 DES(keys + 14, d, results + 16);
343 /* out 16 bytes */
344 static void
345 MD4 (const unsigned char * d, int len, unsigned char * result)
347 PurpleCipher * cipher = purple_ciphers_find_cipher("md4");
348 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
349 purple_cipher_context_append(context, (guchar*)d, len);
350 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
351 purple_cipher_context_destroy(context);
354 /* out 16 bytes */
355 static void
356 MD5 (const unsigned char * d, int len, unsigned char * result)
358 PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
359 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
360 purple_cipher_context_append(context, (guchar*)d, len);
361 purple_cipher_context_digest(context, MD5_DIGEST_LEN, (guchar*)result, NULL);
362 purple_cipher_context_destroy(context);
365 /* out 16 bytes */
367 static void
368 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
370 int i;
371 unsigned char ibuff[64 + data_len];
372 unsigned char obuff[64 + 16];
374 if (key_len > 64)
375 key_len = 64;
377 for (i = 0; i < key_len; i++) {
378 ibuff[i] = key[i] ^ 0x36;
379 obuff[i] = key[i] ^ 0x5c;
381 for (i = key_len; i < 64; i++) {
382 ibuff[i] = 0x36;
383 obuff[i] = 0x5c;
386 memcpy(ibuff+64, data, data_len);
388 MD5 (ibuff, 64 + data_len, obuff+64);
389 MD5 (obuff, 64 + 16, result);
391 #define HMAC_MD5 HMACT64
394 /* out 16 bytes */
395 static void
396 HMAC_MD5 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
398 PurpleCipher *cipher = purple_ciphers_find_cipher("hmac");
399 PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL);
401 purple_cipher_context_set_option(context, "hash", "md5");
402 purple_cipher_context_set_key_with_len(context, (guchar *)key, (key_len));
404 purple_cipher_context_append(context, (guchar *)data, data_len);
405 purple_cipher_context_digest(context, 16, (guchar*)result, NULL);
406 purple_cipher_context_destroy(context);
410 Define NTOWFv1(Passwd, User, UserDom) as
411 MD4(UNICODE(Passwd))
412 EndDefine
414 /* out 16 bytes */
415 static void
416 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
418 int len = 2 * strlen(password); // utf16 should not be more
419 unsigned char *unicode_password = g_new0(unsigned char, len);
421 len = unicode_strconvcopy((gchar *) unicode_password, password, len);
422 MD4 (unicode_password, len, result);
423 g_free(unicode_password);
427 Define NTOWFv2(Passwd, User, UserDom) as
428 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
429 EndDefine
431 /* out 16 bytes */
432 void
433 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
435 unsigned char response_key_nt_v1 [16];
436 int len_user = user ? strlen(user) : 0;
437 int len_domain = domain ? strlen(domain) : 0;
438 unsigned char user_upper[len_user + 1];
439 int len_user_u = 2 * len_user; // utf16 should not be more
440 int len_domain_u = 2 * len_domain; // utf16 should not be more
441 unsigned char buff[(len_user + len_domain)*2];
442 int i;
444 /* Uppercase user */
445 for (i = 0; i < len_user; i++) {
446 user_upper[i] = g_ascii_toupper(user[i]);
448 user_upper[len_user] = 0;
450 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
451 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), (gchar *)domain, len_domain_u);
453 NTOWFv1(password, user, domain, response_key_nt_v1);
455 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
458 static void
459 RC4K (const unsigned char * k, unsigned long key_len, const unsigned char * d, int len, unsigned char * result)
461 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
462 purple_cipher_context_set_option(context, "key_len", (gpointer)key_len);
463 purple_cipher_context_set_key(context, k);
464 purple_cipher_context_encrypt(context, (const guchar *)d, len, result, NULL);
465 purple_cipher_context_destroy(context);
468 static void
469 KXKEY ( guint32 flags,
470 const unsigned char * session_base_key,
471 const unsigned char * lm_challenge_resonse,
472 const guint8 * server_challenge, /* 8-bytes, nonce */
473 unsigned char * key_exchange_key)
475 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
476 // Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
477 // Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
478 // EndDefine
479 guint8 tmp[16];
480 memcpy(tmp, server_challenge, 8);
481 memcpy(tmp+8, lm_challenge_resonse, 8);
482 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
483 } else {
484 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
485 memcpy(key_exchange_key, session_base_key, 16);
490 // This method is only used for NTLMv2 and extended session security
492 If (Mode equals "Client")
493 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
494 "session key to client-to-server signing key magic constant"))
495 Else
496 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
497 "session key to server-to-client signing key magic constant"))
498 Endif
500 void
501 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
503 char * magic = client
504 ? "session key to client-to-server signing key magic constant"
505 : "session key to server-to-client signing key magic constant";
507 int len = strlen(magic) + 1;
508 unsigned char md5_input [16 + len];
509 memcpy(md5_input, random_session_key, 16);
510 memcpy(md5_input + 16, magic, len);
512 MD5 (md5_input, len + 16, result);
516 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
517 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
518 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
519 Set SealKey to RandomSessionKey
520 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
521 Set SealKey to RandomSessionKey[0..6]
522 Else
523 Set SealKey to RandomSessionKey[0..4]
524 Endif
526 If (Mode equals "Client")
527 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
528 Else
529 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
530 Endif
532 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
533 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
534 Else
535 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
536 Endif
537 EndDefine
539 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
540 void
541 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
543 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
545 char * magic = client
546 ? "session key to client-to-server sealing key magic constant"
547 : "session key to server-to-client sealing key magic constant";
549 int len = strlen(magic) + 1;
550 unsigned char md5_input [16 + len];
551 int key_len;
553 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
554 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key (Extended session security)\n");
555 key_len = 16;
556 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
557 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key (Extended session security)\n");
558 key_len = 7;
559 } else {
560 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key (Extended session security)\n");
561 key_len = 5;
564 memcpy(md5_input, random_session_key, key_len);
565 memcpy(md5_input + key_len, magic, len);
567 MD5 (md5_input, key_len + len, result);
569 else
571 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
572 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key\n");
573 memcpy(result, random_session_key, 7);
574 result[7] = 0xA0;
575 } else {
576 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key\n");
577 memcpy(result, random_session_key, 5);
578 result[5] = 0xE5;
579 result[6] = 0x38;
580 result[7] = 0xB0;
585 static void
586 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
588 /* "KGS!@#$%" */
589 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
590 unsigned char uppercase_password[14];
591 int i;
593 int len = strlen(password);
594 if (len > 14) {
595 len = 14;
598 // Uppercase password
599 for (i = 0; i < len; i++) {
600 uppercase_password[i] = g_ascii_toupper(password[i]);
603 // Zero the rest
604 for (; i < 14; i++) {
605 uppercase_password[i] = 0;
608 DES (uppercase_password, magic, result);
609 DES (uppercase_password + 7, magic, result + 8);
612 static void
613 NONCE(unsigned char *buffer, int num)
615 int i;
616 for (i = 0; i < num; i++) {
617 buffer[i] = (rand() & 0xff);
621 static void
622 Z(unsigned char *buffer, int num)
624 int i;
625 for (i = 0; i < num; i++) {
626 buffer[i] = 0;
630 /* End Private Methods */
632 static gchar *
633 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg);
635 static gchar *
636 purple_ntlm_parse_challenge(SipSecBuffer in_buff,
637 gboolean is_connection_based,
638 guint32 *flags)
640 guint32 our_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
641 static gchar nonce[8];
642 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
644 memcpy(nonce, cmsg->nonce, 8);
646 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", cmsg->flags, (cmsg->flags & our_flags) == our_flags);
648 if (flags) {
649 *flags = cmsg->flags;
651 return nonce;
654 /* source copy from gg's common.c */
655 static guint32 crc32_table[256];
656 static int crc32_initialized = 0;
658 static void crc32_make_table()
660 guint32 h = 1;
661 unsigned int i, j;
663 memset(crc32_table, 0, sizeof(crc32_table));
665 for (i = 128; i; i >>= 1) {
666 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
668 for (j = 0; j < 256; j += 2 * i)
669 crc32_table[i + j] = crc32_table[j] ^ h;
672 crc32_initialized = 1;
675 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
677 if (!crc32_initialized)
678 crc32_make_table();
680 if (!buf || len < 0)
681 return crc;
683 crc ^= 0xffffffffL;
685 while (len--)
686 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
688 return crc ^ 0xffffffffL;
691 static guint32
692 CRC32 (const char *msg, int len)
694 guint32 crc = 0L;//crc32(0L, Z_NULL, 0);
695 crc = crc32(crc, (guint8 *) msg, len);
696 //char * ptr = (char*) &crc;
697 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
698 return crc;
702 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
703 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
704 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
705 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
707 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
708 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
709 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
711 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
713 // Version(4), RandomPad(4), Checksum(4), SeqNum(4)
714 // Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
715 // MAC(Handle, SigningKey, SeqNum, Message)
716 static gchar *
717 MAC (guint32 flags,
718 const char *buf,
719 int buf_len,
720 unsigned char *sign_key,
721 unsigned long sign_key_len,
722 unsigned char *seal_key,
723 unsigned long seal_key_len,
724 guint32 random_pad,
725 long sequence)
727 guchar result [16];
728 gint32 *res_ptr;
729 gchar signature [33];
730 int i, j;
732 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
734 Define MAC(Handle, SigningKey, SeqNum, Message) as
735 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
736 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
737 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
738 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
739 Set SeqNum to SeqNum + 1
740 EndDefine
742 /* If a key exchange key is negotiated
743 Define MAC(Handle, SigningKey, SeqNum, Message) as
744 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
745 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
746 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
747 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
748 Set SeqNum to SeqNum + 1
749 EndDefine
751 guchar hmac[16];
752 guchar tmp[4 + buf_len];
754 purple_debug_info("sipe", "NTLM MAC(): Extented Session Security\n");
756 res_ptr = (gint32 *)result;
757 res_ptr[0] = 0x00000001; // 4 bytes
758 res_ptr[3] = sequence;
760 res_ptr = (gint32 *)tmp;
761 res_ptr[0] = sequence;
762 memcpy(tmp+4, buf, buf_len);
764 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
766 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
767 purple_debug_info("sipe", "NTLM MAC(): Key Exchange\n");
768 RC4K(seal_key, seal_key_len, hmac, 8, result+4);
769 //RC4K(sign_key, sign_key_len, hmac, 8, result+4);
770 } else {
771 purple_debug_info("sipe", "NTLM MAC(): *NO* Key Exchange\n");
772 memcpy(result+4, hmac, 8);
774 } else {
775 //SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
776 //RC4Init(Handle, SealingKey')
777 ///MD5 (seal_key, 8, seal_key_);
779 /* The content of the first 4 bytes is irrelevant */
780 gint32 plaintext [] = {0, CRC32(buf, strlen(buf)), sequence}; // 4, 4, 4 bytes
782 purple_debug_info("sipe", "NTLM MAC(): *NO* Extented Session Security\n");
784 RC4K(sign_key, sign_key_len, (const guchar *)plaintext, 12, result+4);
785 //RC4K(seal_key, 8, (const guchar *)plaintext, 12, result+4);
787 res_ptr = (gint32 *)result;
788 // Highest four bytes are the Version
789 res_ptr[0] = 0x00000001; // 4 bytes
791 // Replace the first four bytes of the ciphertext with the random_pad
792 res_ptr[1] = random_pad; // 4 bytes
795 for (i = 0, j = 0; i < 16; i++, j+=2) {
796 g_sprintf(&signature[j], "%02X", result[i]);
799 return g_strdup(signature);
802 static gchar *
803 purple_ntlm_sipe_signature_make (guint32 flags, const char * msg, guint32 random_pad, unsigned char * signing_key)
805 return MAC(flags, msg, strlen(msg), signing_key, 16, 0,16, random_pad, 100);
808 static gboolean
809 purple_ntlm_verify_signature (char * a, char * b)
812 * Make sure the last 24 bytes match
813 * 8 bytes random pad
814 * 16 bytes signature
816 return g_ascii_strncasecmp(a + 8, b + 8, 24) == 0;
819 static void
820 purple_ntlm_gen_authenticate(guchar **ntlm_key, /* signing key */
821 const gchar *user,
822 const gchar *password,
823 const gchar *hostname,
824 const gchar *domain,
825 const guint8 *nonce, /* server challenge */
826 gboolean is_connection_based,
827 SipSecBuffer *out_buff,
828 guint32 *flags)
830 guint32 neg_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
831 gboolean is_key_exch = IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH);
832 int msglen = sizeof(struct authenticate_message) + 2*(strlen(domain)
833 + strlen(user)+ strlen(hostname) + NTLMSSP_NT_OR_LM_KEY_LEN)
834 + (is_key_exch ? NTLMSSP_SESSION_KEY_LEN : 0);
835 struct authenticate_message *tmsg = g_malloc0(msglen);
836 char *tmp;
837 int remlen;
838 unsigned char response_key_lm [16];
839 unsigned char lm_challenge_response [NTLMSSP_NT_OR_LM_KEY_LEN];
840 unsigned char response_key_nt [16];
841 unsigned char nt_challenge_response [NTLMSSP_NT_OR_LM_KEY_LEN];
842 unsigned char session_base_key [16];
843 unsigned char key_exchange_key [16];
844 unsigned char exported_session_key[16];
845 unsigned char encrypted_random_session_key [16];
846 unsigned char client_signing_key [16];
848 NTOWFv1 (password, user, domain, response_key_nt);
849 LMOWFv1 (password, user, domain, response_key_lm);
851 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
852 // @TODO do not even reference nt_challenge_response
853 Z (nt_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
854 DESL (response_key_lm, nonce, lm_challenge_response);
855 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
856 unsigned char client_challenge [8];
857 unsigned char prehash [16];
858 unsigned char hash [16];
860 NONCE (client_challenge, 8);
862 /* nt_challenge_response */
863 memcpy(prehash, nonce, 8);
864 memcpy(prehash + 8, client_challenge, 8);
865 MD5 (prehash, 16, hash);
866 DESL (response_key_nt, hash, nt_challenge_response);
868 /* lm_challenge_response */
869 memcpy(lm_challenge_response, client_challenge, 8);
870 Z (lm_challenge_response+8, 16);
871 } else {
872 DESL (response_key_nt, nonce, nt_challenge_response);
873 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
874 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
875 } else {
876 DESL (response_key_lm, nonce, lm_challenge_response);
880 /* authenticate message initialization */
881 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
882 tmsg->type = 3;
884 /* Set Negotiate Flags */
885 tmsg->flags = neg_flags;
887 /* Domain */
888 tmsg->domain.offset = sizeof(struct authenticate_message);
889 tmp = ((char*) tmsg) + sizeof(struct authenticate_message);
890 remlen = ((char *)tmsg)+msglen-tmp;
891 tmsg->domain.len = tmsg->domain.maxlen = unicode_strconvcopy(tmp, domain, remlen);
892 tmp += tmsg->domain.len;
893 remlen = ((char *)tmsg)+msglen-tmp;
895 /* User */
896 tmsg->user.offset = tmsg->domain.offset + tmsg->domain.len;
897 tmsg->user.len = tmsg->user.maxlen = unicode_strconvcopy(tmp, user, remlen);
898 tmp += tmsg->user.len;
899 remlen = ((char *)tmsg)+msglen-tmp;
901 /* Host */
902 tmsg->host.offset = tmsg->user.offset + tmsg->user.len;
903 tmsg->host.len = tmsg->host.maxlen = unicode_strconvcopy(tmp, hostname, remlen);
904 tmp += tmsg->host.len;
906 /* LM */
907 tmsg->lm_resp.len = tmsg->lm_resp.maxlen = NTLMSSP_NT_OR_LM_KEY_LEN;
908 tmsg->lm_resp.offset = tmsg->host.offset + tmsg->host.len;
909 memcpy(tmp, lm_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
910 tmp += NTLMSSP_NT_OR_LM_KEY_LEN;
912 /* NT */
913 tmsg->nt_resp.len = tmsg->nt_resp.maxlen = NTLMSSP_NT_OR_LM_KEY_LEN;
914 tmsg->nt_resp.offset = tmsg->lm_resp.offset + tmsg->lm_resp.len;
915 memcpy(tmp, nt_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
916 tmp += NTLMSSP_NT_OR_LM_KEY_LEN;
918 /* Session Key */
919 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
920 KXKEY(neg_flags, session_base_key, lm_challenge_response, nonce, key_exchange_key); // same for NTLNv1 w/o Ext.Sess.Sec
922 if (is_key_exch)
924 tmsg->session_key.len = tmsg->session_key.maxlen = NTLMSSP_SESSION_KEY_LEN;
925 tmsg->session_key.offset = tmsg->nt_resp.offset + tmsg->nt_resp.len;
927 NONCE (exported_session_key, 16); // random master key
928 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
930 memcpy(tmp, encrypted_random_session_key, 16);
931 tmp += NTLMSSP_SESSION_KEY_LEN;
933 else
935 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
936 tmsg->session_key.offset = tmsg->nt_resp.offset + tmsg->nt_resp.len;
938 memcpy(exported_session_key, key_exchange_key, 16);
940 // p.46
941 //Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
942 //Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
943 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
944 SIGNKEY(exported_session_key, FALSE, client_signing_key); //Server
945 } else {
946 memcpy(client_signing_key, exported_session_key, 16);
948 *ntlm_key = (guchar *)g_strndup((gchar *)client_signing_key, 16);
950 *flags = neg_flags;
952 tmp = purple_base64_encode(exported_session_key, 16);
953 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE session key: %s\n", tmp);
954 g_free(tmp);
956 out_buff->value = tmsg;
957 out_buff->length = msglen;
961 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
963 static void
964 purple_ntlm_gen_negotiate(SipSecBuffer *out_buff)
966 int msglen = sizeof(struct negotiate_message);
967 struct negotiate_message *tmsg = g_malloc0(msglen);
969 /* negotiate message initialization */
970 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
971 tmsg->type = 1;
973 /* Set Negotiate Flags */
974 tmsg->flags = NEGOTIATE_FLAGS_CONN;
976 /* Domain */
977 tmsg->domain.offset = sizeof(struct negotiate_message);
978 tmsg->domain.len = tmsg->domain.maxlen = 0;
980 /* Host */
981 tmsg->host.offset = tmsg->domain.offset + tmsg->domain.len;
982 tmsg->host.len = tmsg->host.maxlen = 0;
984 /* Version */
985 //tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
986 //tmsg->ver.product_minor_version = 1;
987 //tmsg->ver.product_build = 2600;
988 //tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
990 out_buff->value = tmsg;
991 out_buff->length = msglen;
994 /***********************************************
996 * End of merged code from original sip-ntlm.c
998 ***********************************************/
1000 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1001 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1003 static gchar *
1004 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1006 GString* str = g_string_new(NULL);
1008 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1009 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1010 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1011 APPEND_NEG_FLAG(str, flags, r9, "r9");
1012 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1013 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1014 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1015 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1016 APPEND_NEG_FLAG(str, flags, r8, "r8");
1017 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1018 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1019 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1020 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1021 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1022 APPEND_NEG_FLAG(str, flags, r7, "r7");
1023 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1024 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1025 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1026 APPEND_NEG_FLAG(str, flags, r6, "r6");
1027 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1028 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1029 APPEND_NEG_FLAG(str, flags, r5, "r5");
1030 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1031 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1032 APPEND_NEG_FLAG(str, flags, r4, "r4");
1033 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1034 APPEND_NEG_FLAG(str, flags, r3, "r3");
1035 APPEND_NEG_FLAG(str, flags, r2, "r2");
1036 APPEND_NEG_FLAG(str, flags, r1, "r1");
1037 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1038 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1039 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1041 return g_string_free(str, FALSE);
1044 #define AV_DESC(av, av_value, av_len, av_name) \
1045 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1046 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1047 g_free(tmp);
1049 static gchar *
1050 sip_sec_ntlm_describe_version(struct version *ver) {
1051 GString* str = g_string_new(NULL);
1052 gchar *ver_desc = "";
1053 gchar *ntlm_revision_desc = "";
1055 if (ver->product_major_version == 6) {
1056 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1057 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1058 ver_desc = "Windows Server 2003";
1059 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1060 ver_desc = "Windows XP SP2";
1063 if (ver->ntlm_revision_current == 0x0F) {
1064 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1065 } else if (ver->ntlm_revision_current == 0x0A) {
1066 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1069 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1070 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1071 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1073 return g_string_free(str, FALSE);
1076 static gchar *
1077 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1078 const char* name)
1080 GString* str = g_string_new(NULL);
1082 g_string_append_printf(str, "\t%s.len : %d\n", name, header->len);
1083 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, header->maxlen);
1084 g_string_append_printf(str, "\t%s.offset: %d\n", name, header->offset);
1086 return g_string_free(str, FALSE);
1089 static gchar *
1090 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1092 GString* str = g_string_new(NULL);
1093 char *tmp;
1095 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1096 g_free(tmp);
1098 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1099 g_free(tmp);
1101 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1102 g_free(tmp);
1104 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1105 g_string_append(str, tmp);
1106 g_free(tmp);
1108 if (cmsg->domain.len && cmsg->domain.offset) {
1109 gchar *domain = g_strndup(((gchar *)cmsg + cmsg->domain.offset), cmsg->domain.len);
1110 g_string_append_printf(str, "\tdomain: %s\n", domain);
1111 g_free(domain);
1114 if (cmsg->host.len && cmsg->host.offset) {
1115 gchar *host = g_strndup(((gchar *)cmsg + cmsg->host.offset), cmsg->host.len);
1116 g_string_append_printf(str, "\thost: %s\n", host);
1117 g_free(host);
1120 return g_string_free(str, FALSE);
1123 static gchar *
1124 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1126 GString* str = g_string_new(NULL);
1127 char *tmp;
1128 SipSecBuffer buff;
1130 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1131 g_free(tmp);
1133 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1134 g_free(tmp);
1136 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1137 g_free(tmp);
1139 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1140 g_free(tmp);
1142 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1143 g_free(tmp);
1145 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1146 g_free(tmp);
1148 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1149 g_free(tmp);
1151 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1152 g_string_append(str, tmp);
1153 g_free(tmp);
1155 /* mic */
1156 buff.length = 16;
1157 buff.value = cmsg->mic;
1158 g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = bytes_to_hex_str(&buff)));
1159 g_free(tmp);
1161 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1162 buff.length = cmsg->lm_resp.len;
1163 buff.value = (gchar *)cmsg + cmsg->lm_resp.offset;
1164 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = bytes_to_hex_str(&buff)));
1165 g_free(tmp);
1168 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1169 buff.length = cmsg->nt_resp.len;
1170 buff.value = (gchar *)cmsg + cmsg->nt_resp.offset;
1171 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = bytes_to_hex_str(&buff)));
1172 g_free(tmp);
1175 if (cmsg->domain.len && cmsg->domain.offset) {
1176 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + cmsg->domain.offset), cmsg->domain.len);
1177 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1178 g_free(domain);
1181 if (cmsg->user.len && cmsg->user.offset) {
1182 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + cmsg->user.offset), cmsg->user.len);
1183 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1184 g_free(user);
1187 if (cmsg->host.len && cmsg->host.offset) {
1188 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + cmsg->host.offset), cmsg->host.len);
1189 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1190 g_free(host);
1193 if (cmsg->session_key.len && cmsg->session_key.offset) {
1194 buff.length = cmsg->session_key.len;
1195 buff.value = (gchar *)cmsg + cmsg->session_key.offset;
1196 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = bytes_to_hex_str(&buff)));
1197 g_free(tmp);
1200 return g_string_free(str, FALSE);
1203 static gchar *
1204 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1206 GString* str = g_string_new(NULL);
1207 char *tmp;
1209 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1210 g_free(tmp);
1212 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1213 g_free(tmp);
1215 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1216 g_free(tmp);
1218 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1219 g_free(tmp);
1221 if (cmsg->target_name.len && cmsg->target_name.offset) {
1222 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + cmsg->target_name.offset), cmsg->target_name.len);
1223 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1224 g_free(target_name);
1227 if (cmsg->target_info.len && cmsg->target_info.offset) {
1228 void *target_info = ((gchar *)cmsg + cmsg->target_info.offset);
1229 struct av_pair *av = (struct av_pair*)target_info;
1231 while (av->av_id != MsvAvEOL) {
1232 gchar *av_value = ((gchar *)av) + 4;
1234 switch (av->av_id) {
1235 case MsvAvEOL:
1236 g_string_append_printf(str, "\t%s\n", "MsvAvEOL");
1237 break;
1238 case MsvAvNbComputerName:
1239 { AV_DESC(av, av_value, av->av_len, "MsvAvNbComputerName") break; }
1240 case MsvAvNbDomainName:
1241 { AV_DESC(av, av_value, av->av_len, "MsvAvNbDomainName") break; }
1242 case MsvAvDnsComputerName:
1243 { AV_DESC(av, av_value, av->av_len, "MsvAvDnsComputerName") break; }
1244 case MsvAvDnsDomainName:
1245 { AV_DESC(av, av_value, av->av_len, "MsvAvDnsDomainName") break; }
1246 case MsvAvDnsTreeName:
1247 { AV_DESC(av, av_value, av->av_len, "MsvAvDnsTreeName") break; }
1248 case MsvAvFlags:
1249 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", *((guint32*)av_value));
1250 break;
1251 case MsvAvTimestamp:
1252 g_string_append_printf(str, "\t%s\n", "MsvAvTimestamp");
1253 break;
1254 case MsAvRestrictions:
1255 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1256 break;
1257 case MsvAvTargetName:
1258 { AV_DESC(av, av_value, av->av_len, "MsvAvTargetName") break; }
1259 case MsvChannelBindings:
1260 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1261 break;
1264 av = (struct av_pair*)(((guint8*)av) + 4 + av->av_len);
1268 return g_string_free(str, FALSE);
1271 gchar *
1272 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1274 struct ntlm_message *msg;
1276 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1278 msg = buff.value;
1279 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1281 if (msg->type == 1) return sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1282 if (msg->type == 2) return sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1283 if (msg->type == 3) return sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1285 return NULL;
1288 /* sip-sec-mech.h API implementation for NTLM */
1290 /* Security context for NTLM */
1291 typedef struct _context_ntlm {
1292 struct sip_sec_context common;
1293 char* domain;
1294 char *username;
1295 char *password;
1296 int step;
1297 /* signing key */
1298 guchar *key;
1299 guint32 flags;
1300 } *context_ntlm;
1303 static sip_uint32
1304 sip_sec_acquire_cred__ntlm(SipSecContext context,
1305 const char *domain,
1306 const char *username,
1307 const char *password)
1309 context_ntlm ctx = (context_ntlm)context;
1311 /* NTLM requires a domain, username & password */
1312 if (!domain || !username || !password)
1313 return SIP_SEC_E_INTERNAL_ERROR;
1315 ctx->domain = g_strdup(domain);
1316 ctx->username = g_strdup(username);
1317 ctx->password = g_strdup(password);
1319 return SIP_SEC_E_OK;
1322 static sip_uint32
1323 sip_sec_init_sec_context__ntlm(SipSecContext context,
1324 SipSecBuffer in_buff,
1325 SipSecBuffer *out_buff,
1326 SIPE_UNUSED_PARAMETER const char *service_name)
1328 context_ntlm ctx = (context_ntlm) context;
1330 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1332 ctx->step++;
1333 if (ctx->step == 1) {
1334 if (!context->is_connection_based) {
1335 out_buff->length = 0;
1336 out_buff->value = NULL;
1337 } else {
1338 purple_ntlm_gen_negotiate(out_buff);
1340 return SIP_SEC_I_CONTINUE_NEEDED;
1342 } else {
1343 guchar *ntlm_key;
1344 guchar *nonce;
1345 guint32 flags;
1346 gchar *tmp;
1348 if (!in_buff.value || !in_buff.length) {
1349 return SIP_SEC_E_INTERNAL_ERROR;
1352 nonce = g_memdup(purple_ntlm_parse_challenge(in_buff, context->is_connection_based, &flags), 8);
1354 purple_ntlm_gen_authenticate(&ntlm_key,
1355 ctx->username,
1356 ctx->password,
1357 (tmp = g_ascii_strup(sipe_get_host_name(), -1)),
1358 ctx->domain,
1359 nonce,
1360 context->is_connection_based,
1361 out_buff,
1362 &flags);
1363 g_free(nonce);
1364 g_free(tmp);
1366 g_free(ctx->key);
1367 ctx->key = ntlm_key;
1368 ctx->flags = flags;
1369 return SIP_SEC_E_OK;
1374 * @param message a NULL terminated string to sign
1377 static sip_uint32
1378 sip_sec_make_signature__ntlm(SipSecContext context,
1379 const char *message,
1380 SipSecBuffer *signature)
1382 /* FIXME? We always use a random_pad of 0 */
1383 gchar *signature_hex = purple_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1384 message,
1386 ((context_ntlm) context)->key);
1388 hex_str_to_bytes(signature_hex, signature);
1389 g_free(signature_hex);
1391 return SIP_SEC_E_OK;
1395 * @param message a NULL terminated string to check signature of
1396 * @return SIP_SEC_E_OK on success
1398 static sip_uint32
1399 sip_sec_verify_signature__ntlm(SipSecContext context,
1400 const char *message,
1401 SipSecBuffer signature)
1403 guint32 random_pad = ((guint32 *) signature.value)[1];
1404 char *signature_hex = bytes_to_hex_str(&signature);
1405 gchar *signature_calc = purple_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1406 message,
1407 random_pad,
1408 ((context_ntlm) context)->key);
1409 sip_uint32 res;
1411 if (purple_ntlm_verify_signature(signature_calc, signature_hex)) {
1412 res = SIP_SEC_E_OK;
1413 } else {
1414 res = SIP_SEC_E_INTERNAL_ERROR;
1416 g_free(signature_calc);
1417 g_free(signature_hex);
1418 return(res);
1421 static void
1422 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1424 context_ntlm ctx = (context_ntlm) context;
1426 g_free(ctx->domain);
1427 g_free(ctx->username);
1428 g_free(ctx->password);
1429 g_free(ctx->key);
1430 g_free(ctx);
1433 SipSecContext
1434 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1436 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1437 if (!context) return(NULL);
1439 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1440 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1441 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1442 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1443 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1445 return((SipSecContext) context);
1450 Local Variables:
1451 mode: c
1452 c-file-style: "bsd"
1453 indent-tabs-mode: t
1454 tab-width: 8
1455 End: