NTLM: just reordered methods in logical way
[siplcs.git] / src / core / sip-sec-ntlm.c
blob36d09940359ae18235b2e9080a08b075c8598c53
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 GINT32_FROM_LE
40 * - All calculations should be made in dedicated local variables (system-endian),
41 * not in NTLM (LE) structures.
44 #include <glib.h>
45 #include <glib/gprintf.h>
46 #include <stdio.h>
47 #include <errno.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include "debug.h"
52 #ifndef _WIN32
53 #include <sys/types.h>
54 #ifdef __sun__
55 #include <sys/sockio.h>
56 #endif
57 #include <sys/socket.h>
58 #include <sys/ioctl.h>
59 #include <netinet/in.h>
60 #include <net/if.h>
61 #else /* _WIN32 */
62 #include "libc_interface.h"
63 #ifdef _DLL
64 #define _WS2TCPIP_H_
65 #define _WINSOCK2API_
66 #define _LIBC_INTERNAL_
67 #endif /* _DLL */
68 #include "network.h"
69 #include "internal.h"
70 #endif /* _WIN32 */
72 #ifdef HAVE_LANGINFO_CODESET
73 #include <langinfo.h>
74 #endif /* HAVE_LANGINFO_CODESET */
76 #include "util.h"
77 #include "cipher.h"
79 #include "sipe.h"
80 #include "sipe-utils.h"
81 #include "sip-sec-mech.h"
82 #include "sip-sec-ntlm.h"
84 /* [MS-NLMP] */
85 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
86 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
87 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
88 #define r9 0x00000008 /* r9 */
89 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
90 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
91 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
92 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
93 #define r8 0x00000100 /* r8 */
94 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
95 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
96 #define anonymous 0x00000800 /* J */
97 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
98 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
99 #define r7 0x00004000 /* r7 */
100 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
101 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
102 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
103 #define r6 0x00040000 /* r6 */
104 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
105 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
106 #define r5 0x00200000 /* r5 */
107 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
108 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
109 #define r4 0x01000000 /* r4 */
110 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
111 #define r3 0x04000000 /* r3 */
112 #define r2 0x08000000 /* r2 */
113 #define r1 0x10000000 /* r1 */
114 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
115 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
116 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
118 /* AvId */
119 #define MsvAvEOL 0
120 #define MsvAvNbComputerName 1
121 #define MsvAvNbDomainName 2
122 #define MsvAvDnsComputerName 3
123 #define MsvAvDnsDomainName 4
124 /** @since Windows XP */
125 #define MsvAvDnsTreeName 5
126 /** @since Windows XP */
127 #define MsvAvFlags 6
128 /** @since Windows Vista */
129 #define MsvAvTimestamp 7
130 /** @since Windows Vista */
131 #define MsAvRestrictions 8
132 /** @since Windows 7 */
133 #define MsvAvTargetName 9
134 /** @since Windows 7 */
135 #define MsvChannelBindings 10
137 /* time_t <-> (guint64) time_val conversion */
138 #define TIME_VAL_FACTOR 10000000
139 #define TIME_VAL_OFFSET 116444736000000000LL
140 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
141 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
144 * NTLMv1 is no longer used except in tests. R.I.P.
146 * It remains in this file only for documentary purposes
148 #ifdef _SIPE_COMPILING_TESTS
149 static gboolean use_ntlm_v2 = FALSE;
150 #endif
152 /* Common negotiate flags */
153 #define NEGOTIATE_FLAGS_CONN \
154 NTLMSSP_NEGOTIATE_UNICODE | \
155 NTLMSSP_NEGOTIATE_56 | \
156 NTLMSSP_NEGOTIATE_128 | \
157 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
158 NTLMSSP_NEGOTIATE_NTLM | \
159 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
160 NTLMSSP_NEGOTIATE_KEY_EXCH | \
161 NTLMSSP_REQUEST_TARGET
163 /* Negotiate flags required in connectionless NTLM */
164 #define NEGOTIATE_FLAGS \
165 ( NEGOTIATE_FLAGS_CONN | \
166 NTLMSSP_NEGOTIATE_SIGN | \
167 NTLMSSP_NEGOTIATE_DATAGRAM )
169 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
170 #define NTLMSSP_LM_RESP_LEN 24
171 #define NTLMSSP_SESSION_KEY_LEN 16
172 #define MD4_DIGEST_LEN 16
173 #define MD5_DIGEST_LEN 16
175 #define IS_FLAG(flags, flag) ((flags & flag) == flag)
177 struct av_pair {
178 guint16 av_id;
179 guint16 av_len;
180 /* value */
183 /* 8 bytes */
184 struct version {
185 guint8 product_major_version;
186 guint8 product_minor_version;
187 guint16 product_build;
188 guint8 zero2[3];
189 guint8 ntlm_revision_current;
192 /* 8 bytes */
193 struct smb_header {
194 guint16 len;
195 guint16 maxlen;
196 guint32 offset;
199 struct ntlm_message {
200 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
201 guint32 type; /* 0x00000003 */
204 struct negotiate_message {
205 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
206 guint32 type; /* 0x00000001 */
207 guint32 flags; /* 0xb203 */
208 struct smb_header domain;
209 struct smb_header host;
210 struct version ver;
211 /* payload
212 * - DomainName (always ASCII)
213 * - WorkstationName (always ASCII)
217 struct challenge_message {
218 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
219 guint32 type; /* 0x00000002 */
220 struct smb_header target_name;
221 guint32 flags; /* 0x8201 */
222 guint8 nonce[8];
223 guint8 zero1[8];
224 struct smb_header target_info;
225 struct version ver;
226 /* payload
227 * - TargetName (negotiated encoding)
228 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
232 struct authenticate_message {
233 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
234 guint32 type; /* 0x00000003 */
235 /** LmChallengeResponseFields */
236 struct smb_header lm_resp;
237 /** NtChallengeResponseFields */
238 struct smb_header nt_resp;
239 /** DomainNameFields */
240 struct smb_header domain;
241 /** UserNameFields */
242 struct smb_header user;
243 /** WorkstationFields */
244 struct smb_header host;
245 /** EncryptedRandomSessionKeyFields */
246 struct smb_header session_key;
247 guint32 flags;
248 struct version ver;
249 guint8 mic[16];
250 /* payload
251 * - LmChallengeResponse
252 * - NtChallengeResponse
253 * - DomainName (negotiated encoding)
254 * - UserName (negotiated encoding)
255 * - Workstation (negotiated encoding)
256 * - EncryptedRandomSessionKey
260 #ifndef HAVE_LANGINFO_CODESET
261 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
262 #endif
264 /* Private Methods */
266 /* Utility Functions */
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 /* crc32 source copy from gg's common.c */
318 static guint32 crc32_table[256];
319 static int crc32_initialized = 0;
321 static void crc32_make_table()
323 guint32 h = 1;
324 unsigned int i, j;
326 memset(crc32_table, 0, sizeof(crc32_table));
328 for (i = 128; i; i >>= 1) {
329 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
331 for (j = 0; j < 256; j += 2 * i)
332 crc32_table[i + j] = crc32_table[j] ^ h;
335 crc32_initialized = 1;
338 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
340 if (!crc32_initialized)
341 crc32_make_table();
343 if (!buf || len < 0)
344 return crc;
346 crc ^= 0xffffffffL;
348 while (len--)
349 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
351 return crc ^ 0xffffffffL;
354 static guint32
355 CRC32 (const char *msg, int len)
357 guint32 crc = 0L;//crc32(0L, Z_NULL, 0);
358 crc = crc32(crc, (guint8 *) msg, len);
359 //char * ptr = (char*) &crc;
360 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
361 return crc;
364 /* Cyphers */
366 #ifdef _SIPE_COMPILING_TESTS
367 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
369 key[0] = key_56[0];
370 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
371 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
372 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
373 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
374 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
375 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
376 key[7] = (key_56[6] << 1) & 0xFF;
379 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
381 PurpleCipher *cipher;
382 PurpleCipherContext *context;
383 size_t outlen;
385 cipher = purple_ciphers_find_cipher("des");
386 context = purple_cipher_context_new(cipher, NULL);
387 purple_cipher_context_set_key(context, (guchar*)key);
388 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
389 purple_cipher_context_destroy(context);
391 #endif
393 #ifdef _SIPE_COMPILING_TESTS
394 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
395 static void
396 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
398 unsigned char key[8];
399 setup_des_key(k, key);
400 des_ecb_encrypt(d, results, key);
403 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
404 static void
405 DESL (const unsigned char *k, const unsigned char *d, unsigned char * results)
407 unsigned char keys[21];
409 /* Copy the first 16 bytes */
410 memcpy(keys, k, 16);
412 /* Zero out the last 5 bytes of the key */
413 memset(keys + 16, 0, 5);
415 DES(keys, d, results);
416 DES(keys + 7, d, results + 8);
417 DES(keys + 14, d, results + 16);
419 #endif
421 static void
422 RC4K (const unsigned char * k, unsigned long key_len, const unsigned char * d, int len, unsigned char * result)
424 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
425 purple_cipher_context_set_option(context, "key_len", (gpointer)key_len);
426 purple_cipher_context_set_key(context, k);
427 purple_cipher_context_encrypt(context, (const guchar *)d, len, result, NULL);
428 purple_cipher_context_destroy(context);
431 /* out 16 bytes */
432 static void
433 MD4 (const unsigned char * d, int len, unsigned char * result)
435 PurpleCipher * cipher = purple_ciphers_find_cipher("md4");
436 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
437 purple_cipher_context_append(context, (guchar*)d, len);
438 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
439 purple_cipher_context_destroy(context);
442 /* out 16 bytes */
443 static void
444 MD5 (const unsigned char * d, int len, unsigned char * result)
446 PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
447 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
448 purple_cipher_context_append(context, (guchar*)d, len);
449 purple_cipher_context_digest(context, MD5_DIGEST_LEN, (guchar*)result, NULL);
450 purple_cipher_context_destroy(context);
453 /* out 16 bytes */
455 static void
456 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
458 int i;
459 unsigned char ibuff[64 + data_len];
460 unsigned char obuff[64 + 16];
462 if (key_len > 64)
463 key_len = 64;
465 for (i = 0; i < key_len; i++) {
466 ibuff[i] = key[i] ^ 0x36;
467 obuff[i] = key[i] ^ 0x5c;
469 for (i = key_len; i < 64; i++) {
470 ibuff[i] = 0x36;
471 obuff[i] = 0x5c;
474 memcpy(ibuff+64, data, data_len);
476 MD5 (ibuff, 64 + data_len, obuff+64);
477 MD5 (obuff, 64 + 16, result);
479 #define HMAC_MD5 HMACT64
482 /* out 16 bytes */
483 static void
484 HMAC_MD5 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
486 PurpleCipher *cipher = purple_ciphers_find_cipher("hmac");
487 PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL);
489 purple_cipher_context_set_option(context, "hash", "md5");
490 purple_cipher_context_set_key_with_len(context, (guchar *)key, (key_len));
492 purple_cipher_context_append(context, (guchar *)data, data_len);
493 purple_cipher_context_digest(context, 16, (guchar*)result, NULL);
494 purple_cipher_context_destroy(context);
497 /* NTLM Core Methods */
499 static void
500 NONCE(unsigned char *buffer, int num)
502 int i;
503 for (i = 0; i < num; i++) {
504 buffer[i] = (rand() & 0xff);
508 static void
509 Z(unsigned char *buffer, int num)
511 int i;
512 for (i = 0; i < num; i++) {
513 buffer[i] = 0;
517 #ifdef _SIPE_COMPILING_TESTS
518 static void
519 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
521 /* "KGS!@#$%" */
522 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
523 unsigned char uppercase_password[14];
524 int i;
526 int len = strlen(password);
527 if (len > 14) {
528 len = 14;
531 // Uppercase password
532 for (i = 0; i < len; i++) {
533 uppercase_password[i] = g_ascii_toupper(password[i]);
536 // Zero the rest
537 for (; i < 14; i++) {
538 uppercase_password[i] = 0;
541 DES (uppercase_password, magic, result);
542 DES (uppercase_password + 7, magic, result + 8);
544 #endif
547 Define NTOWFv1(Passwd, User, UserDom) as
548 MD4(UNICODE(Passwd))
549 EndDefine
551 /* out 16 bytes */
552 static void
553 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
555 int len_u = 2 * strlen(password); // utf16 should not be more
556 unsigned char unicode_password[len_u];
558 len_u = unicode_strconvcopy((gchar *)unicode_password, password, len_u);
559 MD4 (unicode_password, len_u, result);
563 Define NTOWFv2(Passwd, User, UserDom) as
564 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
565 EndDefine
567 /* out 16 bytes */
568 void
569 NTOWFv2 (const char* password, const char *user, const char *domain, unsigned char *result)
571 unsigned char response_key_nt_v1 [16];
572 int len_user = user ? strlen(user) : 0;
573 int len_domain = domain ? strlen(domain) : 0;
574 unsigned char user_upper[len_user + 1];
575 int len_user_u = 2 * len_user; // utf16 should not be more
576 int len_domain_u = 2 * len_domain; // utf16 should not be more
577 unsigned char buff[(len_user + len_domain)*2];
578 int i;
580 /* Uppercase user */
581 for (i = 0; i < len_user; i++) {
582 user_upper[i] = g_ascii_toupper(user[i]);
584 user_upper[len_user] = 0;
586 len_user_u = unicode_strconvcopy((gchar *)buff, (gchar *)user_upper, len_user_u);
587 len_domain_u = unicode_strconvcopy((gchar *)(buff+len_user_u), domain ? (gchar *)domain : "", len_domain_u);
589 NTOWFv1(password, user, domain, response_key_nt_v1);
591 HMAC_MD5(response_key_nt_v1, 16, buff, len_user_u + len_domain_u, result);
594 static void
595 compute_response(const guint32 neg_flags,
596 const unsigned char *response_key_nt,
597 const unsigned char *response_key_lm,
598 const guint8 *server_challenge,
599 const guint8 *client_challenge,
600 const guint64 time_val,
601 const guint8 *target_info,
602 int target_info_len,
603 unsigned char *lm_challenge_response,
604 unsigned char *nt_challenge_response,
605 unsigned char *session_base_key)
607 #ifdef _SIPE_COMPILING_TESTS
608 if (use_ntlm_v2)
610 #endif
612 Responserversion - The 1-byte response version. Currently set to 1.
613 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
614 Time - The 8-byte little-endian time in GMT.
615 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
616 ClientChallenge - The 8-byte challenge message generated by the client.
617 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
619 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
620 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
621 Time, //8bytes - 8
622 ClientChallenge, //8bytes - 16
623 Z(4), //4bytes - 24
624 ServerName, //variable - 28
625 Z(4)) //4bytes - 28+target_info_len
626 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
627 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
628 Set LmChallengeResponse to ConcatenationOf(
629 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
630 ClientChallenge )
631 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
632 EndDefine
634 guint8 tmp [16];
635 guint8 nt_proof_str [16];
637 /* temp */
638 int temp_len = 8+8+8+4+target_info_len+4;
639 guint8 temp [temp_len];
640 guint8 temp2 [8 + temp_len];
641 temp[0] = 1;
642 temp[1] = 1;
643 Z(temp+2, 6);
644 *((guint64 *)(temp+8)) = GUINT64_TO_LE(time_val); /* should be int64 aligned: OK for sparc */
645 memcpy(temp+16, client_challenge, 8);
646 Z(temp+24, 4);
647 memcpy(temp+28, target_info, target_info_len);
648 Z(temp+28+target_info_len, 4);
650 /* NTProofStr */
651 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
652 memcpy(temp2, server_challenge, 8);
653 memcpy(temp2+8, temp, temp_len);
654 HMAC_MD5(response_key_nt, 16, temp2, 8+temp_len, nt_proof_str);
656 /* NtChallengeResponse */
657 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
658 memcpy(nt_challenge_response, nt_proof_str, 16);
659 memcpy(nt_challenge_response+16, temp, temp_len);
661 /* SessionBaseKey */
662 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
663 HMAC_MD5(response_key_nt, 16, nt_proof_str, 16, session_base_key);
665 /* lm_challenge_response */
666 memcpy(tmp, server_challenge, 8);
667 memcpy(tmp+8, client_challenge, 8);
668 HMAC_MD5(response_key_lm, 16, tmp, 16, lm_challenge_response);
669 memcpy(lm_challenge_response+16, client_challenge, 8);
671 #ifndef _SIPE_COMPILING_TESTS
672 /* Not used in NTLMv2 */
673 (void)neg_flags;
674 #else
676 else
678 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
679 // @TODO do not even reference nt_challenge_response
680 Z (nt_challenge_response, NTLMSSP_LM_RESP_LEN);
681 DESL (response_key_lm, server_challenge, lm_challenge_response);
682 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
683 unsigned char prehash [16];
684 unsigned char hash [16];
686 /* nt_challenge_response */
687 memcpy(prehash, server_challenge, 8);
688 memcpy(prehash + 8, client_challenge, 8);
689 MD5 (prehash, 16, hash);
690 DESL (response_key_nt, hash, nt_challenge_response);
692 /* lm_challenge_response */
693 memcpy(lm_challenge_response, client_challenge, 8);
694 Z (lm_challenge_response+8, 16);
695 } else {
696 DESL (response_key_nt, server_challenge, nt_challenge_response);
697 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
698 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_LM_RESP_LEN);
699 } else {
700 DESL (response_key_lm, server_challenge, lm_challenge_response);
704 /* Session Key */
705 MD4(response_key_nt, 16, session_base_key); // "User Session Key" -> "master key"
707 #endif
710 static void
711 KXKEY ( guint32 flags,
712 const unsigned char * session_base_key,
713 const unsigned char * lm_challenge_resonse,
714 const guint8 * server_challenge, /* 8-bytes, nonce */
715 unsigned char * key_exchange_key)
717 #ifdef _SIPE_COMPILING_TESTS
718 if (use_ntlm_v2)
720 #else
721 /* Not used in NTLMv2 */
722 (void)flags;
723 (void)lm_challenge_resonse;
724 (void)server_challenge;
725 #endif
726 memcpy(key_exchange_key, session_base_key, 16);
727 #ifdef _SIPE_COMPILING_TESTS
729 else
731 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
732 // Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
733 // Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
734 // EndDefine
735 guint8 tmp[16];
736 memcpy(tmp, server_challenge, 8);
737 memcpy(tmp+8, lm_challenge_resonse, 8);
738 HMAC_MD5(session_base_key, 16, tmp, 16, key_exchange_key);
739 } else {
740 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
741 memcpy(key_exchange_key, session_base_key, 16);
744 #endif
748 If (Mode equals "Client")
749 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
750 "session key to client-to-server signing key magic constant"))
751 Else
752 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
753 "session key to server-to-client signing key magic constant"))
754 Endif
756 static void
757 SIGNKEY (const unsigned char * random_session_key, gboolean client, unsigned char * result)
759 char * magic = client
760 ? "session key to client-to-server signing key magic constant"
761 : "session key to server-to-client signing key magic constant";
763 int len = strlen(magic) + 1;
764 unsigned char md5_input [16 + len];
765 memcpy(md5_input, random_session_key, 16);
766 memcpy(md5_input + 16, magic, len);
768 MD5 (md5_input, len + 16, result);
772 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
773 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
774 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
775 Set SealKey to RandomSessionKey
776 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
777 Set SealKey to RandomSessionKey[0..6]
778 Else
779 Set SealKey to RandomSessionKey[0..4]
780 Endif
782 If (Mode equals "Client")
783 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
784 Else
785 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
786 Endif
788 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
789 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
790 Else
791 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
792 Endif
793 EndDefine
795 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
796 static void
797 SEALKEY (guint32 flags, const unsigned char * random_session_key, gboolean client, unsigned char * result)
799 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY))
801 char * magic = client
802 ? "session key to client-to-server sealing key magic constant"
803 : "session key to server-to-client sealing key magic constant";
805 int len = strlen(magic) + 1;
806 unsigned char md5_input [16 + len];
807 int key_len;
809 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_128)) {
810 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key (Extended session security)\n");
811 key_len = 16;
812 } else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
813 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key (Extended session security)\n");
814 key_len = 7;
815 } else {
816 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key (Extended session security)\n");
817 key_len = 5;
820 memcpy(md5_input, random_session_key, key_len);
821 memcpy(md5_input + key_len, magic, len);
823 MD5 (md5_input, key_len + len, result);
825 else if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_LM_KEY)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
827 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_56)) {
828 purple_debug_info("sipe", "NTLM SEALKEY(): 56-bit key\n");
829 memcpy(result, random_session_key, 7);
830 result[7] = 0xA0;
831 } else {
832 purple_debug_info("sipe", "NTLM SEALKEY(): 40-bit key\n");
833 memcpy(result, random_session_key, 5);
834 result[5] = 0xE5;
835 result[6] = 0x38;
836 result[7] = 0xB0;
839 else
841 purple_debug_info("sipe", "NTLM SEALKEY(): 128-bit key\n");
842 memcpy(result, random_session_key, 16);
847 = for Extended Session Security =
848 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
849 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
850 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
852 = if Extended Session Security is NOT negotiated =
853 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
854 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
855 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
856 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
858 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
860 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
861 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
863 /** MAC(Handle, SigningKey, SeqNum, Message) */
864 static gchar *
865 MAC (guint32 flags,
866 const char *buf,
867 int buf_len,
868 unsigned char *sign_key,
869 unsigned long sign_key_len,
870 unsigned char *seal_key,
871 unsigned long seal_key_len,
872 guint32 random_pad,
873 guint32 sequence)
875 guchar result [16];
876 gint32 *res_ptr;
877 gchar signature [33];
878 int i, j;
880 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
882 Define MAC(Handle, SigningKey, SeqNum, Message) as
883 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
884 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
885 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
886 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
887 Set SeqNum to SeqNum + 1
888 EndDefine
890 /* If a key exchange key is negotiated
891 Define MAC(Handle, SigningKey, SeqNum, Message) as
892 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
893 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
894 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
895 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
896 Set SeqNum to SeqNum + 1
897 EndDefine
900 unsigned char seal_key_ [16];
901 guchar hmac[16];
902 guchar tmp[4 + buf_len];
904 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
905 RC4Init(Handle, SealingKey')
907 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_DATAGRAM)) {
908 unsigned char tmp2 [16+4];
910 memcpy(tmp2, seal_key, seal_key_len);
911 *((guint32 *)(tmp2+16)) = GINT32_TO_LE(sequence);
912 MD5 (tmp2, 16+4, seal_key_);
913 } else {
914 memcpy(seal_key_, seal_key, seal_key_len);
917 purple_debug_info("sipe", "NTLM MAC(): Extented Session Security\n");
919 res_ptr = (gint32 *)result;
920 res_ptr[0] = GINT32_TO_LE(1); // 4 bytes
921 res_ptr[3] = GINT32_TO_LE(sequence);
923 res_ptr = (gint32 *)tmp;
924 res_ptr[0] = GINT32_TO_LE(sequence);
925 memcpy(tmp+4, buf, buf_len);
927 HMAC_MD5(sign_key, sign_key_len, tmp, 4 + buf_len, hmac);
929 if (IS_FLAG(flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
930 purple_debug_info("sipe", "NTLM MAC(): Key Exchange\n");
931 RC4K(seal_key_, seal_key_len, hmac, 8, result+4);
932 } else {
933 purple_debug_info("sipe", "NTLM MAC(): *NO* Key Exchange\n");
934 memcpy(result+4, hmac, 8);
936 } else {
937 /* The content of the first 4 bytes is irrelevant */
938 gint32 plaintext [] = {
939 GINT32_TO_LE(0),
940 GINT32_TO_LE(CRC32(buf, strlen(buf))),
941 GINT32_TO_LE(sequence)
942 }; // 4, 4, 4 bytes
944 purple_debug_info("sipe", "NTLM MAC(): *NO* Extented Session Security\n");
946 RC4K(seal_key, seal_key_len, (const guchar *)plaintext, 12, result+4);
947 //RC4K(seal_key, 8, (const guchar *)plaintext, 12, result+4);
949 res_ptr = (gint32 *)result;
950 // Highest four bytes are the Version
951 res_ptr[0] = GINT32_TO_LE(0x00000001); // 4 bytes
953 // Replace the first four bytes of the ciphertext with the random_pad
954 res_ptr[1] = GINT32_TO_LE(random_pad); // 4 bytes
957 for (i = 0, j = 0; i < 16; i++, j+=2) {
958 g_sprintf(&signature[j], "%02X", result[i]);
961 return g_strdup(signature);
964 /* End Core NTLM Methods */
967 * @param server_challenge must be g_free()'d after use if requested
968 * @param target_info must be g_free()'d after use if requested
970 static void
971 purple_ntlm_parse_challenge(SipSecBuffer in_buff,
972 gboolean is_connection_based,
973 guint32 *flags,
974 guchar **server_challenge, /* 8 bytes */
975 guint64 *time_val,
976 guchar **target_info,
977 int *target_info_len)
979 guint32 our_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
980 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
981 guint32 host_flags = GUINT32_FROM_LE(cmsg->flags);
983 /* server challenge (nonce) */
984 if (server_challenge) {
985 *server_challenge = (guchar *)g_new0(gchar, 8);
986 memcpy(*server_challenge, cmsg->nonce, 8);
989 /* flags */
990 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", host_flags, (host_flags & our_flags) == our_flags);
991 if (flags) {
992 *flags = host_flags;
995 /* target_info */
996 if (cmsg->target_info.len && cmsg->target_info.offset) {
997 const gchar *target_info_content = (((gchar *)cmsg) + GUINT32_FROM_LE(cmsg->target_info.offset));
998 struct av_pair *av = (struct av_pair*)target_info_content;
1000 while (GUINT16_FROM_LE(av->av_id) != MsvAvEOL) {
1001 gchar *av_value = ((gchar *)av) + 4;
1003 switch (GUINT16_FROM_LE(av->av_id)) {
1004 case MsvAvTimestamp:
1005 if (time_val) {
1006 /* This is not int64 aligned on sparc */
1007 guint64 tmp;
1008 memcpy((gchar *)&tmp, av_value, sizeof(tmp));
1009 *time_val = GUINT64_FROM_LE(tmp);
1011 break;
1013 av = (struct av_pair*)(((guint8*)av) + 4 + GUINT16_FROM_LE(av->av_len));
1016 if (target_info_len) {
1017 *target_info_len = GUINT16_FROM_LE(cmsg->target_info.len);
1019 if (target_info) {
1020 *target_info = (guchar *)g_new0(gchar, GUINT16_FROM_LE(cmsg->target_info.len));
1021 memcpy(*target_info, target_info_content, GUINT16_FROM_LE(cmsg->target_info.len));
1026 static void
1027 purple_ntlm_gen_authenticate(guchar **client_sign_key,
1028 guchar **server_sign_key,
1029 guchar **client_seal_key,
1030 guchar **server_seal_key,
1031 const gchar *user,
1032 const gchar *password,
1033 const gchar *hostname,
1034 const gchar *domain,
1035 const guint8 *server_challenge, /* nonce */
1036 const guint64 time_val,
1037 const guint8 *target_info,
1038 int target_info_len,
1039 gboolean is_connection_based,
1040 SipSecBuffer *out_buff,
1041 guint32 *flags)
1043 guint32 neg_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
1044 int ntlmssp_nt_resp_len =
1045 #ifdef _SIPE_COMPILING_TESTS
1046 use_ntlm_v2 ?
1047 #endif
1048 (16 + (32+target_info_len))
1049 #ifdef _SIPE_COMPILING_TESTS
1050 : NTLMSSP_LM_RESP_LEN
1051 #endif
1053 int msglen = sizeof(struct authenticate_message)
1054 + 2*(strlen(domain) + strlen(user)+ strlen(hostname))
1055 + NTLMSSP_LM_RESP_LEN + ntlmssp_nt_resp_len
1056 + (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH) ? NTLMSSP_SESSION_KEY_LEN : 0);
1057 struct authenticate_message *tmsg = g_malloc0(msglen);
1058 char *tmp;
1059 int remlen;
1060 guint32 offset;
1061 guint16 len;
1062 unsigned char response_key_lm [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1063 unsigned char response_key_nt [NTLMSSP_LN_OR_NT_KEY_LEN]; /* 16 */
1064 unsigned char lm_challenge_response [NTLMSSP_LM_RESP_LEN]; /* 24 */
1065 unsigned char nt_challenge_response [ntlmssp_nt_resp_len]; /* variable or 24 */
1066 unsigned char session_base_key [16];
1067 unsigned char key_exchange_key [16];
1068 unsigned char exported_session_key[16];
1069 unsigned char encrypted_random_session_key [16];
1070 unsigned char key [16];
1071 unsigned char client_challenge [8];
1073 NONCE (client_challenge, 8);
1075 #ifdef _SIPE_COMPILING_TESTS
1076 if (use_ntlm_v2) {
1077 #endif
1078 NTOWFv2 (password, user, domain, response_key_nt);
1079 memcpy(response_key_lm, response_key_nt, NTLMSSP_LN_OR_NT_KEY_LEN);
1080 #ifdef _SIPE_COMPILING_TESTS
1081 } else {
1082 NTOWFv1 (password, user, domain, response_key_nt);
1083 LMOWFv1 (password, user, domain, response_key_lm);
1085 #endif
1087 compute_response(neg_flags,
1088 response_key_nt,
1089 response_key_lm,
1090 server_challenge,
1091 client_challenge,
1092 time_val ? time_val : TIME_T_TO_VAL(time(NULL)),
1093 target_info,
1094 target_info_len,
1095 lm_challenge_response, /* out */
1096 nt_challenge_response, /* out */
1097 session_base_key); /* out */
1099 /* same as session_base_key for
1100 * - NTLNv1 w/o Ext.Sess.Sec and
1101 * - NTLMv2
1103 KXKEY(neg_flags, session_base_key, lm_challenge_response, server_challenge, key_exchange_key);
1105 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH)) {
1106 NONCE (exported_session_key, 16); // random master key
1107 RC4K (key_exchange_key, 16, exported_session_key, 16, encrypted_random_session_key);
1108 } else {
1109 memcpy(exported_session_key, key_exchange_key, 16);
1112 /* p.46
1113 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1114 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1116 SIGNKEY(exported_session_key, TRUE, key);
1117 *client_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1118 SIGNKEY(exported_session_key, FALSE, key);
1119 *server_sign_key = (guchar *)g_strndup((gchar *)key, 16);
1120 SEALKEY(neg_flags, exported_session_key, TRUE, key);
1121 *client_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1122 SEALKEY(neg_flags, exported_session_key, FALSE, key);
1123 *server_seal_key = (guchar *)g_strndup((gchar *)key, 16);
1126 /* authenticate message initialization */
1127 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1128 tmsg->type = GUINT32_TO_LE(3);
1130 /* Set Negotiate Flags */
1131 tmsg->flags = GUINT32_TO_LE(neg_flags);
1133 /* Domain */
1134 tmsg->domain.offset = GUINT32_TO_LE(offset = sizeof(struct authenticate_message));
1135 tmp = ((char*) tmsg) + offset;
1136 remlen = ((char *)tmsg)+msglen-tmp;
1137 tmsg->domain.len = tmsg->domain.maxlen = GUINT16_TO_LE(len = unicode_strconvcopy(tmp, domain, remlen));
1138 tmp += len;
1139 remlen = ((char *)tmsg)+msglen-tmp;
1141 /* User */
1142 tmsg->user.offset = GUINT32_TO_LE(offset += len);
1143 tmsg->user.len = tmsg->user.maxlen = GUINT16_TO_LE(len = unicode_strconvcopy(tmp, user, remlen));
1144 tmp += len;
1145 remlen = ((char *)tmsg)+msglen-tmp;
1147 /* Host */
1148 tmsg->host.offset = GUINT32_TO_LE(offset += len);
1149 tmsg->host.len = tmsg->host.maxlen = GUINT16_TO_LE(len = unicode_strconvcopy(tmp, hostname, remlen));
1150 tmp += len;
1152 /* LM */
1153 tmsg->lm_resp.offset = GUINT32_TO_LE(offset += len);
1154 tmsg->lm_resp.len = tmsg->lm_resp.maxlen = GUINT16_TO_LE(len = NTLMSSP_LM_RESP_LEN);
1155 memcpy(tmp, lm_challenge_response, len);
1156 tmp += len;
1158 /* NT */
1159 tmsg->nt_resp.offset = GUINT32_TO_LE(offset += len);
1160 tmsg->nt_resp.len = tmsg->nt_resp.maxlen = GUINT16_TO_LE(len = ntlmssp_nt_resp_len);
1161 memcpy(tmp, nt_challenge_response, len);
1162 tmp += len;
1164 /* Session Key */
1165 tmsg->session_key.offset = GUINT32_TO_LE(offset += len);
1166 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH))
1168 tmsg->session_key.len = tmsg->session_key.maxlen = GUINT16_TO_LE(len = NTLMSSP_SESSION_KEY_LEN);
1169 memcpy(tmp, encrypted_random_session_key, len);
1170 tmp += len;
1172 else
1174 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
1177 *flags = neg_flags;
1179 tmp = purple_base64_encode(exported_session_key, 16);
1180 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE session key: %s\n", tmp);
1181 g_free(tmp);
1183 out_buff->value = tmsg;
1184 out_buff->length = msglen;
1188 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1190 static void
1191 purple_ntlm_gen_negotiate(SipSecBuffer *out_buff)
1193 guint32 offset;
1194 guint16 len;
1195 int msglen = sizeof(struct negotiate_message);
1196 struct negotiate_message *tmsg = g_malloc0(msglen);
1198 /* negotiate message initialization */
1199 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
1200 tmsg->type = GUINT32_TO_LE(1);
1202 /* Set Negotiate Flags */
1203 tmsg->flags = GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN);
1205 /* Domain */
1206 tmsg->domain.offset = GUINT32_TO_LE(offset = sizeof(struct negotiate_message));
1207 tmsg->domain.len = tmsg->domain.maxlen = len = 0;
1209 /* Host */
1210 tmsg->host.offset = GUINT32_TO_LE(offset += len);
1211 tmsg->host.len = tmsg->host.maxlen = len = 0;
1213 /* Version */
1214 //tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
1215 //tmsg->ver.product_minor_version = 1;
1216 //tmsg->ver.product_build = 2600;
1217 //tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
1219 out_buff->value = tmsg;
1220 out_buff->length = msglen;
1223 static gchar *
1224 purple_ntlm_sipe_signature_make (guint32 flags, const char *msg, guint32 random_pad, unsigned char *sign_key, unsigned char *seal_key)
1226 return MAC(flags, msg,strlen(msg), sign_key,16, seal_key,16, random_pad, 100);
1229 static gboolean
1230 purple_ntlm_verify_signature (char * a, char * b)
1233 * Make sure the last 24 bytes match
1234 * 8 bytes random pad
1235 * 16 bytes signature
1237 return g_ascii_strncasecmp(a + 8, b + 8, 24) == 0;
1241 /* Describe NTLM messages functions */
1243 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1244 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1246 static gchar *
1247 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
1249 GString* str = g_string_new(NULL);
1251 flags = GUINT32_FROM_LE(flags);
1253 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
1254 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
1255 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
1256 APPEND_NEG_FLAG(str, flags, r9, "r9");
1257 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
1258 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
1259 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
1260 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
1261 APPEND_NEG_FLAG(str, flags, r8, "r8");
1262 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
1263 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
1264 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
1265 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1266 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1267 APPEND_NEG_FLAG(str, flags, r7, "r7");
1268 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1269 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
1270 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
1271 APPEND_NEG_FLAG(str, flags, r6, "r6");
1272 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1273 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
1274 APPEND_NEG_FLAG(str, flags, r5, "r5");
1275 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1276 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1277 APPEND_NEG_FLAG(str, flags, r4, "r4");
1278 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
1279 APPEND_NEG_FLAG(str, flags, r3, "r3");
1280 APPEND_NEG_FLAG(str, flags, r2, "r2");
1281 APPEND_NEG_FLAG(str, flags, r1, "r1");
1282 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
1283 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1284 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
1286 return g_string_free(str, FALSE);
1289 static gchar *
1290 sip_sec_ntlm_describe_version(struct version *ver) {
1291 GString* str = g_string_new(NULL);
1292 gchar *ver_desc = "";
1293 gchar *ntlm_revision_desc = "";
1295 if (ver->product_major_version == 6) {
1296 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1297 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
1298 ver_desc = "Windows Server 2003";
1299 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
1300 ver_desc = "Windows XP SP2";
1303 if (ver->ntlm_revision_current == 0x0F) {
1304 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
1305 } else if (ver->ntlm_revision_current == 0x0A) {
1306 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
1309 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
1310 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
1311 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
1313 return g_string_free(str, FALSE);
1316 static gchar *
1317 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
1318 const char* name)
1320 GString* str = g_string_new(NULL);
1322 g_string_append_printf(str, "\t%s.len : %d\n", name, GUINT16_FROM_LE(header->len));
1323 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, GUINT16_FROM_LE(header->maxlen));
1324 g_string_append_printf(str, "\t%s.offset: %d\n", name, GUINT32_FROM_LE(header->offset));
1326 return g_string_free(str, FALSE);
1329 static gchar *
1330 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
1332 GString* str = g_string_new(NULL);
1333 char *tmp;
1335 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1336 g_free(tmp);
1338 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1339 g_free(tmp);
1341 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1342 g_free(tmp);
1344 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1345 g_string_append(str, tmp);
1346 g_free(tmp);
1348 if (cmsg->domain.len && cmsg->domain.offset) {
1349 gchar *domain = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1350 g_string_append_printf(str, "\tdomain: %s\n", domain);
1351 g_free(domain);
1354 if (cmsg->host.len && cmsg->host.offset) {
1355 gchar *host = g_strndup(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1356 g_string_append_printf(str, "\thost: %s\n", host);
1357 g_free(host);
1360 return g_string_free(str, FALSE);
1363 static void
1364 describe_av_pairs(GString* str, const struct av_pair *av)
1366 guint16 av_id = GUINT16_FROM_LE(av->av_id);
1368 while (av_id != MsvAvEOL) {
1369 gchar *av_value = ((gchar *)av) + 4;
1371 #define AV_DESC(av_name) \
1373 gchar *tmp = unicode_strconvcopy_back(av_value, GUINT16_FROM_LE(av->av_len)); \
1374 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1375 g_free(tmp); \
1378 switch (av_id) {
1379 case MsvAvNbComputerName:
1380 AV_DESC("MsvAvNbComputerName");
1381 break;
1382 case MsvAvNbDomainName:
1383 AV_DESC("MsvAvNbDomainName");
1384 break;
1385 case MsvAvDnsComputerName:
1386 AV_DESC("MsvAvDnsComputerName");
1387 break;
1388 case MsvAvDnsDomainName:
1389 AV_DESC("MsvAvDnsDomainName");
1390 break;
1391 case MsvAvDnsTreeName:
1392 AV_DESC("MsvAvDnsTreeName");
1393 break;
1394 case MsvAvFlags:
1395 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(*((guint32*)av_value)));
1396 break;
1397 case MsvAvTimestamp:
1399 SipSecBuffer buff;
1400 char *tmp;
1401 guint64 time_val;
1402 time_t time_t_val;
1404 /* This is not int64 aligned on sparc */
1405 memcpy((gchar *)&time_val, av_value, sizeof(time_val));
1406 time_t_val = TIME_VAL_TO_T(time_val);
1408 buff.length = 8;
1409 buff.value = av_value;
1410 g_string_append_printf(str, "\t%s: %s - %s", "MsvAvTimestamp", (tmp = bytes_to_hex_str(&buff)),
1411 asctime(gmtime(&time_t_val)));
1412 g_free(tmp);
1413 break;
1415 case MsAvRestrictions:
1416 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1417 break;
1418 case MsvAvTargetName:
1419 AV_DESC("MsvAvTargetName");
1420 break;
1421 case MsvChannelBindings:
1422 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1423 break;
1426 av = (struct av_pair *)(((guint8 *)av) + 4 + GUINT16_FROM_LE(av->av_len));
1427 av_id = GUINT16_FROM_LE(av->av_id);
1431 static gchar *
1432 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
1434 GString* str = g_string_new(NULL);
1435 char *tmp;
1436 SipSecBuffer buff;
1438 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1439 g_free(tmp);
1441 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
1442 g_free(tmp);
1444 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
1445 g_free(tmp);
1447 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
1448 g_free(tmp);
1450 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
1451 g_free(tmp);
1453 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
1454 g_free(tmp);
1456 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
1457 g_free(tmp);
1459 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
1460 g_string_append(str, tmp);
1461 g_free(tmp);
1463 /* mic */
1464 buff.length = 16;
1465 buff.value = cmsg->mic;
1466 g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = bytes_to_hex_str(&buff)));
1467 g_free(tmp);
1469 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
1470 buff.length = GUINT16_FROM_LE(cmsg->lm_resp.len);
1471 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->lm_resp.offset);
1472 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = bytes_to_hex_str(&buff)));
1473 g_free(tmp);
1476 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
1477 int nt_resp_len = GUINT16_FROM_LE(cmsg->nt_resp.len);
1479 if (nt_resp_len > 24) { /* NTLMv2 */
1480 nt_resp_len = 16;
1482 buff.length = nt_resp_len;
1483 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset);
1484 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = bytes_to_hex_str(&buff)));
1485 g_free(tmp);
1487 if (GUINT16_FROM_LE(cmsg->nt_resp.len) > 24) { /* NTLMv2 */
1488 char *tmp;
1489 SipSecBuffer buff;
1490 const gchar *temp = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16;
1491 const int response_version = *((guchar*)temp);
1492 const int hi_response_version = *((guchar*)(temp+1));
1493 guint64 time_val;
1494 time_t time_t_val;
1495 const gchar *client_challenge = temp + 16;
1496 const struct av_pair *av = (struct av_pair*)(temp + 28);
1498 /* This is not int64 aligned on sparc */
1499 memcpy((gchar *)&time_val, temp+8, sizeof(time_val));
1500 time_t_val = TIME_VAL_TO_T(time_val);
1502 g_string_append_printf(str, "\t%s: %d\n", "response_version", response_version);
1503 g_string_append_printf(str, "\t%s: %d\n", "hi_response_version", hi_response_version);
1505 buff.length = 8;
1506 buff.value = (gchar*)&time_val;
1507 g_string_append_printf(str, "\t%s: %s - %s", "time", (tmp = bytes_to_hex_str(&buff)),
1508 asctime(gmtime(&time_t_val)));
1509 g_free(tmp);
1511 buff.length = 8;
1512 buff.value = (gchar*)client_challenge;
1513 g_string_append_printf(str, "\t%s: %s\n", "client_challenge", (tmp = bytes_to_hex_str(&buff)));
1514 g_free(tmp);
1516 describe_av_pairs(str, av);
1518 g_string_append_printf(str, "\t%s\n", "----------- end of nt_resp v2 -----------");
1522 if (cmsg->domain.len && cmsg->domain.offset) {
1523 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->domain.offset)), GUINT16_FROM_LE(cmsg->domain.len));
1524 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
1525 g_free(domain);
1528 if (cmsg->user.len && cmsg->user.offset) {
1529 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->user.offset)), GUINT16_FROM_LE(cmsg->user.len));
1530 g_string_append_printf(str, "\t%s: %s\n", "user", user);
1531 g_free(user);
1534 if (cmsg->host.len && cmsg->host.offset) {
1535 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->host.offset)), GUINT16_FROM_LE(cmsg->host.len));
1536 g_string_append_printf(str, "\t%s: %s\n", "host", host);
1537 g_free(host);
1540 if (cmsg->session_key.len && cmsg->session_key.offset) {
1541 buff.length = GUINT16_FROM_LE(cmsg->session_key.len);
1542 buff.value = (gchar *)cmsg + GUINT32_FROM_LE(cmsg->session_key.offset);
1543 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = bytes_to_hex_str(&buff)));
1544 g_free(tmp);
1547 return g_string_free(str, FALSE);
1550 static gchar *
1551 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
1553 GString* str = g_string_new(NULL);
1554 char *tmp;
1556 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
1557 g_free(tmp);
1559 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
1560 g_free(tmp);
1562 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
1563 g_free(tmp);
1565 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
1566 g_free(tmp);
1568 if (cmsg->target_name.len && cmsg->target_name.offset) {
1569 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_name.offset)), GUINT16_FROM_LE(cmsg->target_name.len));
1570 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
1571 g_free(target_name);
1574 if (cmsg->target_info.len && cmsg->target_info.offset) {
1575 void *target_info = ((gchar *)cmsg + GUINT32_FROM_LE(cmsg->target_info.offset));
1576 struct av_pair *av = (struct av_pair*)target_info;
1578 describe_av_pairs(str, av);
1581 return g_string_free(str, FALSE);
1584 gchar *
1585 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1587 struct ntlm_message *msg;
1588 gchar *res = NULL;
1590 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1592 msg = buff.value;
1593 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1595 switch (GUINT32_FROM_LE(msg->type)) {
1596 case 1: res = sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1597 break;
1598 case 2: res = sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1599 break;
1600 case 3: res = sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1601 break;
1604 return res;
1607 /* sip-sec-mech.h API implementation for NTLM */
1609 /* Security context for NTLM */
1610 typedef struct _context_ntlm {
1611 struct sip_sec_context common;
1612 char* domain;
1613 char *username;
1614 char *password;
1615 int step;
1616 guchar *client_sign_key;
1617 guchar *server_sign_key;
1618 guchar *client_seal_key;
1619 guchar *server_seal_key;
1620 guint32 flags;
1621 } *context_ntlm;
1624 static sip_uint32
1625 sip_sec_acquire_cred__ntlm(SipSecContext context,
1626 const char *domain,
1627 const char *username,
1628 const char *password)
1630 context_ntlm ctx = (context_ntlm)context;
1632 /* NTLM requires a domain, username & password */
1633 if (!domain || !username || !password)
1634 return SIP_SEC_E_INTERNAL_ERROR;
1636 ctx->domain = g_strdup(domain);
1637 ctx->username = g_strdup(username);
1638 ctx->password = g_strdup(password);
1640 return SIP_SEC_E_OK;
1643 static sip_uint32
1644 sip_sec_init_sec_context__ntlm(SipSecContext context,
1645 SipSecBuffer in_buff,
1646 SipSecBuffer *out_buff,
1647 SIPE_UNUSED_PARAMETER const char *service_name)
1649 context_ntlm ctx = (context_ntlm) context;
1651 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1653 ctx->step++;
1654 if (ctx->step == 1) {
1655 if (!context->is_connection_based) {
1656 out_buff->length = 0;
1657 out_buff->value = NULL;
1658 } else {
1659 purple_ntlm_gen_negotiate(out_buff);
1661 return SIP_SEC_I_CONTINUE_NEEDED;
1663 } else {
1664 guchar *client_sign_key;
1665 guchar *server_sign_key;
1666 guchar *client_seal_key;
1667 guchar *server_seal_key;
1668 guchar *server_challenge = NULL;
1669 guint64 time_val = 0;
1670 guchar *target_info = NULL;
1671 int target_info_len = 0;
1672 guint32 flags;
1673 gchar *tmp;
1675 if (!in_buff.value || !in_buff.length) {
1676 return SIP_SEC_E_INTERNAL_ERROR;
1679 purple_ntlm_parse_challenge(in_buff,
1680 context->is_connection_based,
1681 &flags,
1682 &server_challenge, /* 8 bytes */
1683 &time_val,
1684 &target_info,
1685 &target_info_len);
1687 purple_ntlm_gen_authenticate(&client_sign_key,
1688 &server_sign_key,
1689 &client_seal_key,
1690 &server_seal_key,
1691 ctx->username,
1692 ctx->password,
1693 (tmp = g_ascii_strup(sipe_get_host_name(), -1)),
1694 ctx->domain,
1695 server_challenge,
1696 time_val,
1697 target_info,
1698 target_info_len,
1699 context->is_connection_based,
1700 out_buff,
1701 &flags);
1702 g_free(server_challenge);
1703 g_free(target_info);
1704 g_free(tmp);
1706 g_free(ctx->client_sign_key);
1707 ctx->client_sign_key = client_sign_key;
1709 g_free(ctx->server_sign_key);
1710 ctx->server_sign_key = server_sign_key;
1712 g_free(ctx->client_seal_key);
1713 ctx->client_seal_key = client_seal_key;
1715 g_free(ctx->server_seal_key);
1716 ctx->server_seal_key = server_seal_key;
1718 ctx->flags = flags;
1719 return SIP_SEC_E_OK;
1724 * @param message a NULL terminated string to sign
1727 static sip_uint32
1728 sip_sec_make_signature__ntlm(SipSecContext context,
1729 const char *message,
1730 SipSecBuffer *signature)
1732 /* FIXME? We always use a random_pad of 0 */
1733 gchar *signature_hex = purple_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1734 message,
1736 ((context_ntlm) context)->client_sign_key,
1737 ((context_ntlm) context)->client_seal_key);
1739 hex_str_to_bytes(signature_hex, signature);
1740 g_free(signature_hex);
1742 return SIP_SEC_E_OK;
1746 * @param message a NULL terminated string to check signature of
1747 * @return SIP_SEC_E_OK on success
1749 static sip_uint32
1750 sip_sec_verify_signature__ntlm(SipSecContext context,
1751 const char *message,
1752 SipSecBuffer signature)
1754 guint32 random_pad = GUINT32_FROM_LE(((guint32 *) signature.value)[1]);
1755 char *signature_hex = bytes_to_hex_str(&signature);
1756 gchar *signature_calc = purple_ntlm_sipe_signature_make(((context_ntlm) context)->flags,
1757 message,
1758 random_pad,
1759 ((context_ntlm) context)->server_sign_key,
1760 ((context_ntlm) context)->server_seal_key);
1761 sip_uint32 res;
1763 if (purple_ntlm_verify_signature(signature_calc, signature_hex)) {
1764 res = SIP_SEC_E_OK;
1765 } else {
1766 res = SIP_SEC_E_INTERNAL_ERROR;
1768 g_free(signature_calc);
1769 g_free(signature_hex);
1770 return(res);
1773 static void
1774 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1776 context_ntlm ctx = (context_ntlm) context;
1778 g_free(ctx->domain);
1779 g_free(ctx->username);
1780 g_free(ctx->password);
1781 g_free(ctx->client_sign_key);
1782 g_free(ctx->server_sign_key);
1783 g_free(ctx->client_seal_key);
1784 g_free(ctx->server_seal_key);
1785 g_free(ctx);
1788 SipSecContext
1789 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1791 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1792 if (!context) return(NULL);
1794 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1795 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1796 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1797 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1798 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1800 return((SipSecContext) context);
1805 Local Variables:
1806 mode: c
1807 c-file-style: "bsd"
1808 indent-tabs-mode: t
1809 tab-width: 8
1810 End: