NTLM: connection-based Negotiation Flags
[siplcs.git] / src / core / sip-sec-ntlm.c
blobb6e998367f26d20eceeece512aea313af338c214
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2009 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 */
103 /***********************************************
105 * Start of merged code from original sip-ntlm.c
107 ***********************************************/
109 /* Negotiate flags required in connection-oriented NTLM */
110 #define NEGOTIATE_FLAGS_CONN \
111 ( NTLMSSP_NEGOTIATE_UNICODE | \
112 NTLMSSP_REQUEST_TARGET | \
113 NTLMSSP_NEGOTIATE_NTLM | \
114 NTLMSSP_NEGOTIATE_ALWAYS_SIGN )
116 /* Negotiate flags required in connectionless NTLM */
117 #define NEGOTIATE_FLAGS \
118 ( NTLMSSP_NEGOTIATE_UNICODE | \
119 NTLMSSP_NEGOTIATE_SIGN | \
120 NTLMSSP_NEGOTIATE_DATAGRAM | \
121 NTLMSSP_NEGOTIATE_NTLM | \
122 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
123 NTLMSSP_NEGOTIATE_KEY_EXCH )
125 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
127 #define NTLMSSP_NT_OR_LM_KEY_LEN 24
128 #define NTLMSSP_SESSION_KEY_LEN 16
129 #define MD4_DIGEST_LEN 16
131 struct negotiate_message {
132 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
133 guint8 type; /* 0x01 */
134 guint8 zero1[3];
135 guint32 flags; /* 0xb203 */
137 guint16 dom_len1; /* domain string length */
138 guint16 dom_len2; /* domain string length */
139 guint16 dom_off; /* domain string offset */
140 guint8 zero2[2];
142 guint16 host_len1; /* host string length */
143 guint16 host_len2; /* host string length */
144 guint16 host_off; /* host string offset (always 0x20) */
145 guint8 zero3[2];
147 #if 0
148 guint8 host[*]; /* host string (ASCII) */
149 guint8 dom[*]; /* domain string (ASCII) */
150 #endif
153 struct challenge_message {
154 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
155 guint8 type; /* 0x02 */
156 guint8 zero1[7];
157 guint16 msg_len; /* 0x28 */
158 guint8 zero2[2];
159 guint32 flags; /* 0x8201 */
161 guint8 nonce[8];
162 guint8 zero3[8];
165 struct authenticate_message {
166 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
167 //guint32 type; /* 0x03 */
168 guint8 type; /* 0x03 */
169 guint8 zero1[3];
171 guint16 lm_resp_len1; /* LanManager response length (always 0x18)*/
172 guint16 lm_resp_len2; /* LanManager response length (always 0x18)*/
173 //guint32 lm_resp_off; /* LanManager response offset */
174 guint16 lm_resp_off; /* LanManager response offset */
175 guint8 zero2[2];
177 /* NtChallengeResponseFields */
178 guint16 nt_resp_len1; /* NT response length (always 0x18) */
179 guint16 nt_resp_len2; /* NT response length (always 0x18) */
180 //guint32 nt_resp_off; /* NT response offset */
181 guint16 nt_resp_off; /* NT response offset */
182 guint8 zero3[2];
184 /* DomainNameFields */
185 guint16 dom_len1; /* domain string length */
186 guint16 dom_len2; /* domain string length */
187 //guint32 dom_off; /* domain string offset (always 0x40) */
188 guint16 dom_off; /* domain string offset (always 0x40) */
189 guint8 zero4[2];
191 /* UserNameFields */
192 guint16 user_len1; /* username string length */
193 guint16 user_len2; /* username string length */
194 //guint32 user_off; /* username string offset */
195 guint16 user_off; /* username string offset */
196 guint8 zero5[2];
198 /* WorkstationFields */
199 guint16 host_len1; /* host string length */
200 guint16 host_len2; /* host string length */
201 //guint32 host_off; /* host string offset */
202 guint16 host_off; /* host string offset */
203 guint8 zero6[2];
205 /* EncryptedRandomSessionKeyFields */
206 guint16 sess_len1;
207 guint16 sess_len2;
208 //guint32 sess_off;
209 guint16 sess_off;
210 guint8 zero7[2];
212 guint32 flags;
214 // don't care values
215 // version
216 // mic
218 // payload
219 /* guint32 flags2; unknown, used in windows messenger
220 guint32 flags3; */
222 #if 0
223 guint8 dom[*]; /* domain string (unicode UTF-16LE) */
224 guint8 user[*]; /* username string (unicode UTF-16LE) */
225 guint8 host[*]; /* host string (unicode UTF-16LE) */
226 guint8 lm_resp[*]; /* LanManager response */
227 guint8 nt_resp[*]; /* NT response */
228 #endif
231 #ifndef HAVE_LANGINFO_CODESET
232 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
233 #endif
235 /* Private Methods */
237 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
239 key[0] = key_56[0];
240 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
241 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
242 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
243 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
244 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
245 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
246 key[7] = (key_56[6] << 1) & 0xFF;
249 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
251 PurpleCipher *cipher;
252 PurpleCipherContext *context;
253 size_t outlen;
255 cipher = purple_ciphers_find_cipher("des");
256 context = purple_cipher_context_new(cipher, NULL);
257 purple_cipher_context_set_key(context, (guchar*)key);
258 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
259 purple_cipher_context_destroy(context);
262 static int
263 unicode_strconvcopy(gchar *dest, const gchar *source, int remlen)
265 GIConv fd;
266 gchar *inbuf = (gchar *) source;
267 gchar *outbuf = dest;
268 gsize inbytes = strlen(source);
269 gsize outbytes = remlen;
270 #ifdef HAVE_LANGINFO_CODESET
271 char *sys_cp = nl_langinfo(CODESET);
272 #else
273 char *sys_cp = SIPE_DEFAULT_CODESET;
274 #endif /* HAVE_LANGINFO_CODESET */
276 /* fall back to utf-8 */
277 if (!sys_cp) sys_cp = "UTF-8";
279 fd = g_iconv_open("UTF-16LE", sys_cp);
280 if( fd == (GIConv)-1 ) {
281 purple_debug_error( "sipe", "iconv_open returned -1, cannot continue\n" );
283 g_iconv(fd, &inbuf, &inbytes, &outbuf, &outbytes);
284 g_iconv_close(fd);
285 return (remlen - outbytes);
288 // (k = 7 byte key, d = 8 byte data) returns 8 bytes in results
289 static void
290 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
292 unsigned char key[8];
293 setup_des_key(k, key);
294 des_ecb_encrypt(d, results, key);
297 // (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results:
298 static void
299 DESL (unsigned char *k, const unsigned char *d, unsigned char * results)
301 unsigned char keys[21];
303 // Copy the first 16 bytes
304 memcpy(keys, k, 16);
306 // Zero out the last 5 bytes of the key
307 memset(keys + 16, 0, 5);
309 DES(keys, d, results);
310 DES(keys + 7, d, results + 8);
311 DES(keys + 14, d, results + 16);
314 static void
315 MD4 (const unsigned char * d, int len, unsigned char * result)
317 PurpleCipher * cipher = purple_ciphers_find_cipher("md4");
318 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
319 purple_cipher_context_append(context, (guchar*)d, len);
320 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
321 purple_cipher_context_destroy(context);
325 static void
326 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char * result)
328 int len = 2 * strlen(password); // utf16 should not be more
329 unsigned char *unicode_password = g_new0(unsigned char, len);
331 len = unicode_strconvcopy((gchar *) unicode_password, password, len);
332 MD4 (unicode_password, len, result);
333 g_free(unicode_password);
336 // static void
337 // MD5 (const char * d, int len, char * result)
338 // {
339 // PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
340 // PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
341 // purple_cipher_context_append(context, (guchar*)d, len);
342 // purple_cipher_context_digest(context, len, (guchar*)result, NULL);
343 // purple_cipher_context_destroy(context);
344 // }
346 static void
347 RC4K (const unsigned char * k, const unsigned char * d, unsigned char * result)
349 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
350 purple_cipher_context_set_option(context, "key_len", GUINT_TO_POINTER(16));
351 purple_cipher_context_set_key(context, k);
352 purple_cipher_context_encrypt(context, (const guchar *)d, 16, result, NULL);
353 purple_cipher_context_destroy(context);
356 static void
357 KXKEY (const unsigned char * session_base_key, SIPE_UNUSED_PARAMETER const unsigned char * lm_challenge_resonse, unsigned char * key_exchange_key)
359 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
360 memcpy(key_exchange_key, session_base_key, 16);
363 // This method is only used for NTLM v2 session security w/ enhanced security negotiated
364 /*void
365 SIGNKEY (const char * random_session_key, gboolean client, char * result)
367 char * magic = client
368 ? "session key to client-to-server signing key magic constant"
369 : "session key to server-to-client signing key magic constant";
371 int len = strlen(magic);
372 char md5_input [16 + len];
373 memcpy(md5_input, random_session_key, 16);
374 memcpy(md5_input + 16, magic, len);
376 MD5 (md5_input, len + 16, result);
379 static void
380 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
382 /* "KGS!@#$%" */
383 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
384 unsigned char uppercase_password[14];
385 int i;
387 int len = strlen(password);
388 if (len > 14) {
389 len = 14;
392 // Uppercase password
393 for (i = 0; i < len; i++) {
394 uppercase_password[i] = g_ascii_toupper(password[i]);
397 // Zero the rest
398 for (; i < 14; i++) {
399 uppercase_password[i] = 0;
402 DES (uppercase_password, magic, result);
403 DES (uppercase_password + 7, magic, result + 8);
406 static void
407 NONCE(unsigned char *buffer, int num)
409 int i;
410 for (i = 0; i < num; i++) {
411 buffer[i] = (rand() & 0xff);
415 /* End Private Methods */
417 static gchar *
418 purple_ntlm_parse_challenge(SipSecBuffer in_buff,
419 gboolean is_connection_based,
420 guint32 *flags)
422 guint32 our_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
423 static gchar nonce[8];
424 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
425 memcpy(nonce, cmsg->nonce, 8);
427 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", cmsg->flags, (cmsg->flags & our_flags) == our_flags);
429 if (flags) {
430 *flags = cmsg->flags;
432 return nonce;
435 // static void
436 // print_hex_array(char * msg, int num)
437 // {
438 // int k;
439 // for (k = 0; k < num; k++) {
440 // printf("0x%02X, ", msg[k]&0xff);
441 // }
442 // printf("\n");
443 // }
445 // static void
446 // print_hex_array_title(char * title, char * msg, int num)
447 // {
448 // printf("%s:\n", title);
449 // print_hex_array(msg, num);
450 // }
452 /* source copy from gg's common.c */
453 static guint32 crc32_table[256];
454 static int crc32_initialized = 0;
456 static void crc32_make_table()
458 guint32 h = 1;
459 unsigned int i, j;
461 memset(crc32_table, 0, sizeof(crc32_table));
463 for (i = 128; i; i >>= 1) {
464 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
466 for (j = 0; j < 256; j += 2 * i)
467 crc32_table[i + j] = crc32_table[j] ^ h;
470 crc32_initialized = 1;
473 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
475 if (!crc32_initialized)
476 crc32_make_table();
478 if (!buf || len < 0)
479 return crc;
481 crc ^= 0xffffffffL;
483 while (len--)
484 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
486 return crc ^ 0xffffffffL;
489 static guint32
490 CRC32 (const char * msg)
492 guint32 crc = 0L;//crc32(0L, Z_NULL, 0);
493 crc = crc32(crc, (guint8 *) msg, strlen(msg));
494 //char * ptr = (char*) &crc;
495 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
496 return crc;
499 static gchar *
500 purple_ntlm_gen_signature (const char * buf, unsigned char * signing_key, guint32 random_pad, long sequence, unsigned long key_len)
502 gint32 *res_ptr;
503 gint32 plaintext [] = {0, CRC32(buf), sequence};
505 guchar result [16];
506 gchar signature [33];
507 int i, j;
508 PurpleCipherContext *rc4 = purple_cipher_context_new_by_name("rc4", NULL);
509 purple_cipher_context_set_option(rc4, "key_len", GUINT_TO_POINTER(key_len));
511 purple_cipher_context_set_key(rc4, signing_key);
512 purple_cipher_context_encrypt(rc4, (const guchar *)plaintext, 12, result+4, NULL);
513 purple_cipher_context_destroy(rc4);
515 res_ptr = (gint32 *)result;
516 // Highest four bytes are the Version
517 res_ptr[0] = 0x00000001;
519 // Replace the first four bytes of the ciphertext with a counter value
520 // currently set to this hardcoded value
521 res_ptr[1] = random_pad;
523 for (i = 0, j = 0; i < 16; i++, j+=2) {
524 g_sprintf(&signature[j], "%02X", result[i]);
527 //printf("sig: %s\n", signature);
528 return g_strdup(signature);
531 static gchar *
532 purple_ntlm_sipe_signature_make (const char * msg, unsigned char * signing_key)
534 return purple_ntlm_gen_signature(msg, signing_key, 0, 100, 16);
537 static gboolean
538 purple_ntlm_verify_signature (char * a, char * b)
540 // Make sure the last 16 bytes match
541 gboolean ret = g_ascii_strncasecmp(a + 16, b + 16, 16) == 0;
542 return ret;
545 static void
546 purple_ntlm_gen_authenticate(guchar **ntlm_key,
547 const gchar *user,
548 const gchar *password,
549 const gchar *hostname,
550 const gchar *domain,
551 const guint8 *nonce,
552 gboolean is_connection_based,
553 SipSecBuffer *out_buff,
554 SIPE_UNUSED_PARAMETER guint32 *flags)
556 int msglen = sizeof(struct authenticate_message) + 2*(strlen(domain)
557 + strlen(user)+ strlen(hostname) + NTLMSSP_NT_OR_LM_KEY_LEN)
558 + NTLMSSP_SESSION_KEY_LEN;
559 struct authenticate_message *tmsg = g_malloc0(msglen);
560 char *tmp;
561 int remlen;
562 unsigned char response_key_lm [16];
563 unsigned char lm_challenge_response [NTLMSSP_NT_OR_LM_KEY_LEN];
564 unsigned char response_key_nt [16];
565 unsigned char nt_challenge_response [NTLMSSP_NT_OR_LM_KEY_LEN];
566 unsigned char session_base_key [16];
567 unsigned char key_exchange_key [16];
568 unsigned char exported_session_key[16];
569 unsigned char encrypted_random_session_key [16];
571 /* authenticate message initialization */
572 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
573 tmsg->type = 3;
575 /* Set Negotiate Flags */
576 tmsg->flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
578 /* Domain */
579 tmsg->dom_off = sizeof(struct authenticate_message);
580 tmp = ((char*) tmsg) + sizeof(struct authenticate_message);
581 remlen = ((char *)tmsg)+msglen-tmp;
582 tmsg->dom_len1 = tmsg->dom_len2 = unicode_strconvcopy(tmp, domain, remlen);
583 tmp += tmsg->dom_len1;
584 remlen = ((char *)tmsg)+msglen-tmp;
586 /* User */
587 tmsg->user_off = tmsg->dom_off + tmsg->dom_len1;
588 tmsg->user_len1 = tmsg->user_len2 = unicode_strconvcopy(tmp, user, remlen);
589 tmp += tmsg->user_len1;
590 remlen = ((char *)tmsg)+msglen-tmp;
592 /* Host */
593 tmsg->host_off = tmsg->user_off + tmsg->user_len1;
594 tmsg->host_len1 = tmsg->host_len2 = unicode_strconvcopy(tmp, hostname, remlen);
595 tmp += tmsg->host_len1;
597 /* LM */
598 tmsg->lm_resp_len1 = tmsg->lm_resp_len2 = NTLMSSP_NT_OR_LM_KEY_LEN;
599 tmsg->lm_resp_off = tmsg->host_off + tmsg->host_len1;
601 LMOWFv1 (password, user, domain, response_key_lm);
602 DESL (response_key_lm, nonce, lm_challenge_response);
603 memcpy(tmp, lm_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
604 tmp += NTLMSSP_NT_OR_LM_KEY_LEN;
606 /* NT */
607 tmsg->nt_resp_len1 = tmsg->nt_resp_len2 = NTLMSSP_NT_OR_LM_KEY_LEN;
608 tmsg->nt_resp_off = tmsg->lm_resp_off + tmsg->lm_resp_len1;
610 NTOWFv1 (password, user, domain, response_key_nt);
611 DESL (response_key_nt, nonce, nt_challenge_response);
612 memcpy(tmp, nt_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
613 tmp += NTLMSSP_NT_OR_LM_KEY_LEN;
615 /* Session Key */
616 tmsg->sess_len1 = tmsg->sess_len2 = NTLMSSP_SESSION_KEY_LEN;
617 tmsg->sess_off = tmsg->nt_resp_off + tmsg->nt_resp_len1;
619 MD4(response_key_nt, 16, session_base_key);
621 KXKEY(session_base_key, lm_challenge_response, key_exchange_key);
623 NONCE (exported_session_key, 16);
625 *ntlm_key = (guchar *) g_strndup ((gchar *) exported_session_key, 16);
627 RC4K (key_exchange_key, exported_session_key, encrypted_random_session_key);
628 memcpy(tmp, encrypted_random_session_key, 16);
629 tmp += NTLMSSP_SESSION_KEY_LEN;
631 tmp = purple_base64_encode(exported_session_key, 16);
632 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE message (%s)\n", tmp);
633 g_free(tmp);
635 out_buff->value = tmsg;
636 out_buff->length = msglen;
640 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
642 static void
643 purple_ntlm_gen_negotiate(SipSecBuffer *out_buff)
645 int msglen = sizeof(struct negotiate_message);
646 struct negotiate_message *tmsg = g_malloc0(msglen);
648 /* negotiate message initialization */
649 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
650 tmsg->type = 1;
652 /* Set Negotiate Flags */
653 tmsg->flags = NEGOTIATE_FLAGS_CONN;
655 /* Domain */
656 tmsg->dom_off = sizeof(struct negotiate_message);
657 tmsg->dom_len1 = tmsg->dom_len2 = 0;
659 /* Host */
660 tmsg->host_off = tmsg->dom_off + tmsg->dom_len1;
661 tmsg->host_len1 = tmsg->host_len2 = 0;
663 out_buff->value = tmsg;
664 out_buff->length = msglen;
667 /***********************************************
669 * End of merged code from original sip-ntlm.c
671 ***********************************************/
673 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
674 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
676 static gchar *
677 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
679 GString* str = g_string_new(NULL);
681 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
682 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
683 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
684 APPEND_NEG_FLAG(str, flags, r9, "r9");
685 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
686 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
687 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
688 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
689 APPEND_NEG_FLAG(str, flags, r8, "r8");
690 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
691 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
692 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
693 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
694 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
695 APPEND_NEG_FLAG(str, flags, r7, "r7");
696 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
697 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
698 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
699 APPEND_NEG_FLAG(str, flags, r6, "r6");
700 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
701 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
702 APPEND_NEG_FLAG(str, flags, r5, "r5");
703 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
704 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
705 APPEND_NEG_FLAG(str, flags, r4, "r4");
706 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
707 APPEND_NEG_FLAG(str, flags, r3, "r3");
708 APPEND_NEG_FLAG(str, flags, r2, "r2");
709 APPEND_NEG_FLAG(str, flags, r1, "r1");
710 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
711 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
712 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
714 return g_string_free(str, FALSE);
717 /* sip-sec-mech.h API implementation for NTLM */
719 /* Security context for NTLM */
720 typedef struct _context_ntlm {
721 struct sip_sec_context common;
722 char* domain;
723 char *username;
724 char *password;
725 int step;
726 guchar *key;
727 } *context_ntlm;
730 static sip_uint32
731 sip_sec_acquire_cred__ntlm(SipSecContext context,
732 const char *domain,
733 const char *username,
734 const char *password)
736 context_ntlm ctx = (context_ntlm)context;
738 /* NTLM requires a password */
739 if (!password) return SIP_SEC_E_INTERNAL_ERROR;
741 ctx->domain = g_strdup(domain);
742 ctx->username = g_strdup(username);
743 ctx->password = g_strdup(password);
745 return SIP_SEC_E_OK;
748 static sip_uint32
749 sip_sec_init_sec_context__ntlm(SipSecContext context,
750 SipSecBuffer in_buff,
751 SipSecBuffer *out_buff,
752 SIPE_UNUSED_PARAMETER const char *service_name)
754 context_ntlm ctx = (context_ntlm) context;
756 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
758 ctx->step++;
759 if (ctx->step == 1) {
760 if (!context->is_connection_based) {
761 out_buff->length = 0;
762 out_buff->value = NULL;
763 } else {
764 purple_ntlm_gen_negotiate(out_buff);
766 return SIP_SEC_I_CONTINUE_NEEDED;
768 } else {
769 guchar *ntlm_key;
770 guchar *nonce;
771 guint32 flags;
772 gchar *flags_desc;
774 if (!in_buff.value || !in_buff.length) {
775 return SIP_SEC_E_INTERNAL_ERROR;
778 nonce = g_memdup(purple_ntlm_parse_challenge(in_buff, context->is_connection_based, &flags), 8);
780 flags_desc = sip_sec_ntlm_negotiate_flags_describe(flags);
781 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: Negotiate flags are:\n%s", flags_desc ? flags_desc : "");
782 g_free(flags_desc);
784 purple_ntlm_gen_authenticate(&ntlm_key,
785 ctx->username,
786 ctx->password,
787 sipe_get_host_name(),
788 ctx->domain,
789 nonce,
790 context->is_connection_based,
791 out_buff,
792 &flags);
793 g_free(nonce);
795 g_free(ctx->key);
796 ctx->key = ntlm_key;
797 return SIP_SEC_E_OK;
802 * @param message a NULL terminated string to sign
805 static sip_uint32
806 sip_sec_make_signature__ntlm(SipSecContext context,
807 const char *message,
808 SipSecBuffer *signature)
810 gchar *signature_hex = purple_ntlm_sipe_signature_make(message,
811 ((context_ntlm) context)->key);
813 hex_str_to_bytes(signature_hex, signature);
814 g_free(signature_hex);
816 return SIP_SEC_E_OK;
820 * @param message a NULL terminated string to check signature of
821 * @return SIP_SEC_E_OK on success
823 static sip_uint32
824 sip_sec_verify_signature__ntlm(SipSecContext context,
825 const char *message,
826 SipSecBuffer signature)
828 char *signature_hex = bytes_to_hex_str(&signature);
829 gchar *signature_calc = purple_ntlm_sipe_signature_make(message,
830 ((context_ntlm) context)->key);
831 sip_uint32 res;
833 if (purple_ntlm_verify_signature(signature_calc, signature_hex)) {
834 res = SIP_SEC_E_OK;
835 } else {
836 res = SIP_SEC_E_INTERNAL_ERROR;
838 g_free(signature_calc);
839 g_free(signature_hex);
840 return(res);
843 static void
844 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
846 context_ntlm ctx = (context_ntlm) context;
848 g_free(ctx->domain);
849 g_free(ctx->username);
850 g_free(ctx->password);
851 g_free(ctx->key);
852 g_free(ctx);
855 SipSecContext
856 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
858 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
859 if (!context) return(NULL);
861 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
862 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
863 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
864 context->common.make_signature_func = sip_sec_make_signature__ntlm;
865 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
867 return((SipSecContext) context);
872 Local Variables:
873 mode: c
874 c-file-style: "bsd"
875 indent-tabs-mode: t
876 tab-width: 8
877 End: