6 * Copyright (C) 2009 pier11 <pier11@kinozal.tv>
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 #include <glib/gprintf.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <sys/types.h>
43 #include <netinet/in.h>
46 #include "libc_interface.h"
50 #define _LIBC_INTERNAL_
56 #ifdef HAVE_LANGINFO_CODESET
58 #endif /* HAVE_LANGINFO_CODESET */
64 #include "sip-sec-mech.h"
65 #include "sip-sec-ntlm.h"
68 /***********************************************
70 * Start of merged code from original sip-ntlm.c
72 ***********************************************/
74 /* Negotiate flag required in connectionless NTLM
75 * 0x00000001 = NTLMSSP_NEGOTIATE_UNICODE (A)
76 * 0x00000010 = NTLMSSP_NEGOTIATE_SIGN (D)
77 * 0x00000040 = NTLMSSP_NEGOTIATE_DATAGRAM (F)
78 * 0x00000200 = NTLMSSP_NEGOTIATE_NTLM (H)
79 * 0x00008000 = NTLMSSP_NEGOTIATE_ALWAYS_SIGN (M)
80 * 0x40000000 = NTLMSSP_NEGOTIATE_KEY_EXCH (W)
82 #define NEGOTIATE_FLAGS 0x40008251
83 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
85 #define NTLMSSP_NT_OR_LM_KEY_LEN 24
86 #define NTLMSSP_SESSION_KEY_LEN 16
87 #define MD4_DIGEST_LEN 16
89 struct challenge_message
{
90 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
91 guint8 type
; /* 0x02 */
93 short msg_len
; /* 0x28 */
95 guint32 flags
; /* 0x8201 */
101 struct authenticate_message
{
102 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
103 //guint32 type; /* 0x03 */
104 guint8 type
; /* 0x03 */
107 guint16 lm_resp_len1
; /* LanManager response length (always 0x18)*/
108 guint16 lm_resp_len2
; /* LanManager response length (always 0x18)*/
109 //guint32 lm_resp_off; /* LanManager response offset */
110 guint16 lm_resp_off
; /* LanManager response offset */
113 /* NtChallengeResponseFields */
114 guint16 nt_resp_len1
; /* NT response length (always 0x18) */
115 guint16 nt_resp_len2
; /* NT response length (always 0x18) */
116 //guint32 nt_resp_off; /* NT response offset */
117 guint16 nt_resp_off
; /* NT response offset */
120 /* DomainNameFields */
121 guint16 dom_len1
; /* domain string length */
122 guint16 dom_len2
; /* domain string length */
123 //guint32 dom_off; /* domain string offset (always 0x40) */
124 guint16 dom_off
; /* domain string offset (always 0x40) */
128 guint16 user_len1
; /* username string length */
129 guint16 user_len2
; /* username string length */
130 //guint32 user_off; /* username string offset */
131 guint16 user_off
; /* username string offset */
134 /* WorkstationFields */
135 guint16 host_len1
; /* host string length */
136 guint16 host_len2
; /* host string length */
137 //guint32 host_off; /* host string offset */
138 guint16 host_off
; /* host string offset */
141 /* EncryptedRandomSessionKeyFields */
155 /* guint32 flags2; unknown, used in windows messenger
159 guint8 dom
[*]; /* domain string (unicode UTF-16LE) */
160 guint8 user
[*]; /* username string (unicode UTF-16LE) */
161 guint8 host
[*]; /* host string (unicode UTF-16LE) */
162 guint8 lm_resp
[*]; /* LanManager response */
163 guint8 nt_resp
[*]; /* NT response */
167 #ifndef HAVE_LANGINFO_CODESET
168 static char SIPE_DEFAULT_CODESET
[] = "ANSI_X3.4-1968";
171 /* Private Methods */
173 static void setup_des_key(const unsigned char key_56
[], unsigned char *key
)
176 key
[1] = ((key_56
[0] << 7) & 0xFF) | (key_56
[1] >> 1);
177 key
[2] = ((key_56
[1] << 6) & 0xFF) | (key_56
[2] >> 2);
178 key
[3] = ((key_56
[2] << 5) & 0xFF) | (key_56
[3] >> 3);
179 key
[4] = ((key_56
[3] << 4) & 0xFF) | (key_56
[4] >> 4);
180 key
[5] = ((key_56
[4] << 3) & 0xFF) | (key_56
[5] >> 5);
181 key
[6] = ((key_56
[5] << 2) & 0xFF) | (key_56
[6] >> 6);
182 key
[7] = (key_56
[6] << 1) & 0xFF;
185 static void des_ecb_encrypt(const unsigned char *plaintext
, unsigned char *result
, const unsigned char *key
)
187 PurpleCipher
*cipher
;
188 PurpleCipherContext
*context
;
191 cipher
= purple_ciphers_find_cipher("des");
192 context
= purple_cipher_context_new(cipher
, NULL
);
193 purple_cipher_context_set_key(context
, (guchar
*)key
);
194 purple_cipher_context_encrypt(context
, (guchar
*)plaintext
, 8, (guchar
*)result
, &outlen
);
195 purple_cipher_context_destroy(context
);
199 unicode_strconvcopy(gchar
*dest
, const gchar
*source
, int remlen
)
202 gchar
*inbuf
= (gchar
*) source
;
203 gchar
*outbuf
= dest
;
204 size_t inbytes
= strlen(source
);
205 size_t outbytes
= remlen
;
206 #ifdef HAVE_LANGINFO_CODESET
207 char *sys_cp
= nl_langinfo(CODESET
);
209 char *sys_cp
= SIPE_DEFAULT_CODESET
;
210 #endif /* HAVE_LANGINFO_CODESET */
212 /* fall back to utf-8 */
213 if (!sys_cp
) sys_cp
= "UTF-8";
215 fd
= g_iconv_open("UTF-16LE", sys_cp
);
216 if( fd
== (GIConv
)-1 ) {
217 purple_debug_error( "sipe", "iconv_open returned -1, cannot continue\n" );
219 g_iconv(fd
, &inbuf
, &inbytes
, &outbuf
, &outbytes
);
221 return (remlen
- outbytes
);
224 // (k = 7 byte key, d = 8 byte data) returns 8 bytes in results
226 DES (const unsigned char *k
, const unsigned char *d
, unsigned char * results
)
228 unsigned char key
[8];
229 setup_des_key(k
, key
);
230 des_ecb_encrypt(d
, results
, key
);
233 // (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results:
235 DESL (unsigned char *k
, const unsigned char *d
, unsigned char * results
)
237 unsigned char keys
[21];
239 // Copy the first 16 bytes
242 // Zero out the last 5 bytes of the key
243 memset(keys
+ 16, 0, 5);
245 DES(keys
, d
, results
);
246 DES(keys
+ 7, d
, results
+ 8);
247 DES(keys
+ 14, d
, results
+ 16);
251 MD4 (const unsigned char * d
, int len
, unsigned char * result
)
253 PurpleCipher
* cipher
= purple_ciphers_find_cipher("md4");
254 PurpleCipherContext
* context
= purple_cipher_context_new(cipher
, NULL
);
255 purple_cipher_context_append(context
, (guchar
*)d
, len
);
256 purple_cipher_context_digest(context
, MD4_DIGEST_LEN
, (guchar
*)result
, NULL
);
257 purple_cipher_context_destroy(context
);
262 NTOWFv1 (const char* password
, SIPE_UNUSED_PARAMETER
const char *user
, SIPE_UNUSED_PARAMETER
const char *domain
, unsigned char * result
)
264 int len
= 2 * strlen(password
); // utf16 should not be more
265 unsigned char *unicode_password
= g_new0(unsigned char, len
);
267 len
= unicode_strconvcopy((gchar
*) unicode_password
, password
, len
);
268 MD4 (unicode_password
, len
, result
);
269 g_free(unicode_password
);
273 // MD5 (const char * d, int len, char * result)
275 // PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
276 // PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
277 // purple_cipher_context_append(context, (guchar*)d, len);
278 // purple_cipher_context_digest(context, len, (guchar*)result, NULL);
279 // purple_cipher_context_destroy(context);
283 RC4K (const unsigned char * k
, const unsigned char * d
, unsigned char * result
)
285 PurpleCipherContext
* context
= purple_cipher_context_new_by_name("rc4", NULL
);
286 purple_cipher_context_set_option(context
, "key_len", (gpointer
)16);
287 purple_cipher_context_set_key(context
, k
);
288 purple_cipher_context_encrypt(context
, (const guchar
*)d
, 16, result
, NULL
);
289 purple_cipher_context_destroy(context
);
293 KXKEY (const unsigned char * session_base_key
, SIPE_UNUSED_PARAMETER
const unsigned char * lm_challenge_resonse
, unsigned char * key_exchange_key
)
295 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
296 memcpy(key_exchange_key
, session_base_key
, 16);
299 // This method is only used for NTLM v2 session security w/ enhanced security negotiated
301 SIGNKEY (const char * random_session_key, gboolean client, char * result)
303 char * magic = client
304 ? "session key to client-to-server signing key magic constant"
305 : "session key to server-to-client signing key magic constant";
307 int len = strlen(magic);
308 char md5_input [16 + len];
309 memcpy(md5_input, random_session_key, 16);
310 memcpy(md5_input + 16, magic, len);
312 MD5 (md5_input, len + 16, result);
316 LMOWFv1 (const char *password
, SIPE_UNUSED_PARAMETER
const char *user
, SIPE_UNUSED_PARAMETER
const char *domain
, unsigned char *result
)
319 unsigned char magic
[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
320 unsigned char uppercase_password
[14];
323 int len
= strlen(password
);
328 // Uppercase password
329 for (i
= 0; i
< len
; i
++) {
330 uppercase_password
[i
] = g_ascii_toupper(password
[i
]);
334 for (; i
< 14; i
++) {
335 uppercase_password
[i
] = 0;
338 DES (uppercase_password
, magic
, result
);
339 DES (uppercase_password
+ 7, magic
, result
+ 8);
343 NONCE(unsigned char *buffer
, int num
)
346 for (i
= 0; i
< num
; i
++) {
347 buffer
[i
] = (rand() & 0xff);
351 /* End Private Methods */
353 static gchar
*purple_ntlm_parse_challenge(const char *challenge
, guint32
*flags
) {
355 static gchar nonce
[8];
356 struct challenge_message
*tmsg
= (struct challenge_message
*)purple_base64_decode(challenge
, &retlen
);
357 memcpy(nonce
, tmsg
->nonce
, 8);
359 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", tmsg
->flags
, (tmsg
->flags
& NEGOTIATE_FLAGS
) == NEGOTIATE_FLAGS
);
362 *flags
= tmsg
->flags
;
369 // print_hex_array(char * msg, int num)
372 // for (k = 0; k < num; k++) {
373 // printf("0x%02X, ", msg[k]&0xff);
379 // print_hex_array_title(char * title, char * msg, int num)
381 // printf("%s:\n", title);
382 // print_hex_array(msg, num);
385 /* source copy from gg's common.c */
386 static guint32 crc32_table
[256];
387 static int crc32_initialized
= 0;
389 static void crc32_make_table()
394 memset(crc32_table
, 0, sizeof(crc32_table
));
396 for (i
= 128; i
; i
>>= 1) {
397 h
= (h
>> 1) ^ ((h
& 1) ? 0xedb88320L
: 0);
399 for (j
= 0; j
< 256; j
+= 2 * i
)
400 crc32_table
[i
+ j
] = crc32_table
[j
] ^ h
;
403 crc32_initialized
= 1;
406 static guint32
crc32(guint32 crc
, const guint8
*buf
, int len
)
408 if (!crc32_initialized
)
417 crc
= (crc
>> 8) ^ crc32_table
[(crc
^ *buf
++) & 0xff];
419 return crc
^ 0xffffffffL
;
423 CRC32 (const char * msg
)
425 guint32 crc
= 0L;//crc32(0L, Z_NULL, 0);
426 crc
= crc32(crc
, (guint8
*) msg
, strlen(msg
));
427 //char * ptr = (char*) &crc;
428 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
433 purple_ntlm_gen_signature (const char * buf
, unsigned char * signing_key
, guint32 random_pad
, long sequence
, int key_len
)
436 gint32 plaintext
[] = {0, CRC32(buf
), sequence
};
439 gchar signature
[32];
441 PurpleCipherContext
*rc4
= purple_cipher_context_new_by_name("rc4", NULL
);
442 purple_cipher_context_set_option(rc4
,"key_len", GINT_TO_POINTER(key_len
));
444 purple_cipher_context_set_key(rc4
, signing_key
);
445 purple_cipher_context_encrypt(rc4
, (const guchar
*)plaintext
, 12, result
+4, NULL
);
446 purple_cipher_context_destroy(rc4
);
448 res_ptr
= (gint32
*)result
;
449 // Highest four bytes are the Version
450 res_ptr
[0] = 0x00000001;
452 // Replace the first four bytes of the ciphertext with a counter value
453 // currently set to this hardcoded value
454 res_ptr
[1] = random_pad
;
456 for (i
= 0, j
= 0; i
< 16; i
++, j
+=2) {
457 g_sprintf(&signature
[j
], "%02X", result
[i
]);
460 //printf("sig: %s\n", signature);
461 return g_strdup(signature
);
465 purple_ntlm_sipe_signature_make (const char * msg
, unsigned char * signing_key
)
467 return purple_ntlm_gen_signature(msg
, signing_key
, 0, 100, 16);
471 purple_ntlm_verify_signature (char * a
, char * b
)
473 // Make sure the last 16 bytes match
474 gboolean ret
= g_ascii_strncasecmp(a
+ 16, b
+ 16, 16) == 0;
479 purple_ntlm_gen_authenticate(guchar
**ntlm_key
, const gchar
*user
, const gchar
*password
, const gchar
*hostname
, const gchar
*domain
, const guint8
*nonce
, SIPE_UNUSED_PARAMETER guint32
*flags
)
481 int msglen
= sizeof(struct authenticate_message
) + 2*(strlen(domain
)
482 + strlen(user
)+ strlen(hostname
) + NTLMSSP_NT_OR_LM_KEY_LEN
)
483 + NTLMSSP_SESSION_KEY_LEN
;
484 struct authenticate_message
*tmsg
= g_malloc0(msglen
);
487 unsigned char response_key_lm
[16];
488 unsigned char lm_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
489 unsigned char response_key_nt
[16];
490 unsigned char nt_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
491 unsigned char session_base_key
[16];
492 unsigned char key_exchange_key
[16];
493 unsigned char exported_session_key
[16];
494 unsigned char encrypted_random_session_key
[16];
496 /* authenticate message initialization */
497 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
500 /* Set Negotiate Flags */
501 tmsg
->flags
= NEGOTIATE_FLAGS
;
504 tmsg
->dom_off
= sizeof(struct authenticate_message
);
505 tmp
= ((char*) tmsg
) + sizeof(struct authenticate_message
);
506 remlen
= ((char *)tmsg
)+msglen
-tmp
;
507 tmsg
->dom_len1
= tmsg
->dom_len2
= unicode_strconvcopy(tmp
, domain
, remlen
);
508 tmp
+= tmsg
->dom_len1
;
509 remlen
= ((char *)tmsg
)+msglen
-tmp
;
512 tmsg
->user_off
= tmsg
->dom_off
+ tmsg
->dom_len1
;
513 tmsg
->user_len1
= tmsg
->user_len2
= unicode_strconvcopy(tmp
, user
, remlen
);
514 tmp
+= tmsg
->user_len1
;
515 remlen
= ((char *)tmsg
)+msglen
-tmp
;
518 tmsg
->host_off
= tmsg
->user_off
+ tmsg
->user_len1
;
519 tmsg
->host_len1
= tmsg
->host_len2
= unicode_strconvcopy(tmp
, hostname
, remlen
);
520 tmp
+= tmsg
->host_len1
;
523 tmsg
->lm_resp_len1
= tmsg
->lm_resp_len2
= NTLMSSP_NT_OR_LM_KEY_LEN
;
524 tmsg
->lm_resp_off
= tmsg
->host_off
+ tmsg
->host_len1
;
526 LMOWFv1 (password
, user
, domain
, response_key_lm
);
527 DESL (response_key_lm
, nonce
, lm_challenge_response
);
528 memcpy(tmp
, lm_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
529 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
532 tmsg
->nt_resp_len1
= tmsg
->nt_resp_len2
= NTLMSSP_NT_OR_LM_KEY_LEN
;
533 tmsg
->nt_resp_off
= tmsg
->lm_resp_off
+ tmsg
->lm_resp_len1
;
535 NTOWFv1 (password
, user
, domain
, response_key_nt
);
536 DESL (response_key_nt
, nonce
, nt_challenge_response
);
537 memcpy(tmp
, nt_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
538 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
541 tmsg
->sess_len1
= tmsg
->sess_len2
= NTLMSSP_SESSION_KEY_LEN
;
542 tmsg
->sess_off
= tmsg
->nt_resp_off
+ tmsg
->nt_resp_len1
;
544 MD4(response_key_nt
, 16, session_base_key
);
546 KXKEY(session_base_key
, lm_challenge_response
, key_exchange_key
);
548 NONCE (exported_session_key
, 16);
550 *ntlm_key
= (guchar
*) g_strndup ((gchar
*) exported_session_key
, 16);
552 RC4K (key_exchange_key
, exported_session_key
, encrypted_random_session_key
);
553 memcpy(tmp
, encrypted_random_session_key
, 16);
554 tmp
+= NTLMSSP_SESSION_KEY_LEN
;
556 tmp
= purple_base64_encode(exported_session_key
, 16);
557 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE message (%s)\n", tmp
);
560 tmp
= purple_base64_encode((guchar
*) tmsg
, msglen
);
565 /***********************************************
567 * End of merged code from original sip-ntlm.c
569 ***********************************************/
571 /* sip-sec-mech.h API implementation for NTLM */
572 static char *sipe_get_host_name();
574 /* Security context for NTLM */
575 typedef struct _context_ntlm
{
576 struct sip_sec_context common
;
586 sip_sec_acquire_cred__ntlm(SipSecContext context
,
588 const char *username
,
589 const char *password
)
591 context_ntlm ctx
= (context_ntlm
)context
;
593 ctx
->domain
= strdup(domain
);
594 ctx
->username
= strdup(username
);
595 ctx
->password
= strdup(password
);
601 sip_sec_init_sec_context__ntlm(SipSecContext context
,
602 SipSecBuffer in_buff
,
603 SipSecBuffer
*out_buff
,
604 SIPE_UNUSED_PARAMETER
const char *service_name
)
606 context_ntlm ctx
= (context_ntlm
) context
;
608 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
611 if (ctx
->step
== 1) {
612 out_buff
->length
= 0;
613 out_buff
->value
= NULL
;
614 // same behaviour as sspi
615 return SIP_SEC_I_CONTINUE_NEEDED
;
621 gchar
*input_toked_base64
;
624 input_toked_base64
= purple_base64_encode(in_buff
.value
,
627 nonce
= g_memdup(purple_ntlm_parse_challenge(input_toked_base64
, &flags
), 8);
628 g_free(input_toked_base64
);
630 gssapi_data
= purple_ntlm_gen_authenticate(&ntlm_key
,
633 sipe_get_host_name(),
639 out_buff
->value
= purple_base64_decode(gssapi_data
, &(out_buff
->length
));
649 * @param message a NULL terminated string to sign
653 sip_sec_make_signature__ntlm(SipSecContext context
,
655 SipSecBuffer
*signature
)
657 gchar
*signature_hex
= purple_ntlm_sipe_signature_make(message
,
658 ((context_ntlm
) context
)->key
);
660 hex_str_to_bytes(signature_hex
, signature
);
661 g_free(signature_hex
);
667 * @param message a NULL terminated string to check signature of
668 * @return SIP_SEC_E_OK on success
671 sip_sec_verify_signature__ntlm(SipSecContext context
,
673 SipSecBuffer signature
)
675 char *signature_hex
= bytes_to_hex_str(&signature
);
676 gchar
*signature_calc
= purple_ntlm_sipe_signature_make(message
,
677 ((context_ntlm
) context
)->key
);
680 if (purple_ntlm_verify_signature(signature_calc
, signature_hex
)) {
683 res
= SIP_SEC_E_INTERNAL_ERROR
;
685 g_free(signature_calc
);
686 g_free(signature_hex
);
691 sip_sec_destroy_sec_context__ntlm(SipSecContext context
)
693 context_ntlm ctx
= (context_ntlm
) context
;
696 g_free(ctx
->username
);
697 g_free(ctx
->password
);
703 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type
)
705 context_ntlm context
= g_malloc0(sizeof(struct _context_ntlm
));
706 if (!context
) return(NULL
);
708 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__ntlm
;
709 context
->common
.init_context_func
= sip_sec_init_sec_context__ntlm
;
710 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__ntlm
;
711 context
->common
.make_signature_func
= sip_sec_make_signature__ntlm
;
712 context
->common
.verify_signature_func
= sip_sec_verify_signature__ntlm
;
714 return((SipSecContext
) context
);
717 //@TODO refactor it somewhere to utils. Do we need compat with glib < 2.8 ?
718 char *sipe_get_host_name()
720 #if GLIB_CHECK_VERSION(2,8,0)
721 const gchar
* hostname
= g_get_host_name();
723 static char hostname
[256];
724 int ret
= gethostname(hostname
, sizeof(hostname
));
725 hostname
[sizeof(hostname
) - 1] = '\0';
726 if (ret
== -1 || hostname
[0] == '\0') {
727 purple_debug(PURPLE_DEBUG_MISC
, "sipe", "Error when getting host name. Using \"localhost.\"\n");
729 strcpy(hostname
, "localhost");
732 /*const gchar * hostname = purple_get_host_name();*/
733 return (char *)hostname
;