2003-11-26 04:16:41 +03:00
/*
* Unix SMB / CIFS implementation .
* Version 3.0
* NTLMSSP Signing routines
* Copyright ( C ) Luke Kenneth Casson Leighton 1996 - 2001
2005-04-25 07:37:37 +04:00
* Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2003 - 2005
2003-11-26 04:16:41 +03:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
2007-07-10 06:46:15 +04:00
* the Free Software Foundation ; either version 3 of the License , or
2003-11-26 04:16:41 +03:00
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2007-07-10 07:42:26 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2003-11-26 04:16:41 +03:00
*/
# include "includes.h"
2005-04-25 09:03:50 +04:00
# include "auth/ntlmssp/ntlmssp.h"
2009-04-16 04:17:17 +04:00
# include "../libcli/auth/libcli_auth.h"
2008-09-24 17:30:23 +04:00
# include "../lib/crypto/crypto.h"
2006-11-07 03:48:36 +03:00
# include "auth/gensec/gensec.h"
2003-11-26 04:16:41 +03:00
# define CLI_SIGN "session key to client-to-server signing key magic constant"
# define CLI_SEAL "session key to client-to-server sealing key magic constant"
# define SRV_SIGN "session key to server-to-client signing key magic constant"
# define SRV_SEAL "session key to server-to-client sealing key magic constant"
2004-05-25 18:06:28 +04:00
/**
2006-06-08 19:20:05 +04:00
* Some notes on the NTLM2 code :
2004-05-25 18:06:28 +04:00
*
2005-04-25 07:37:37 +04:00
* NTLM2 is a AEAD system . This means that the data encrypted is not
* all the data that is signed . In DCE - RPC case , the headers of the
* DCE - RPC packets are also signed . This prevents some of the
* fun - and - games one might have by changing them .
2004-05-25 18:06:28 +04:00
*
*/
2004-06-16 17:53:40 +04:00
2004-08-30 05:34:01 +04:00
static void calc_ntlmv2_key ( TALLOC_CTX * mem_ctx ,
DATA_BLOB * subkey ,
2004-06-16 17:53:40 +04:00
DATA_BLOB session_key ,
const char * constant )
2003-11-26 04:16:41 +03:00
{
struct MD5Context ctx3 ;
2004-08-30 05:34:01 +04:00
* subkey = data_blob_talloc ( mem_ctx , NULL , 16 ) ;
2003-11-26 04:16:41 +03:00
MD5Init ( & ctx3 ) ;
MD5Update ( & ctx3 , session_key . data , session_key . length ) ;
2005-08-20 10:14:14 +04:00
MD5Update ( & ctx3 , ( const uint8_t * ) constant , strlen ( constant ) + 1 ) ;
2004-08-30 05:34:01 +04:00
MD5Final ( subkey - > data , & ctx3 ) ;
2003-11-26 04:16:41 +03:00
}
enum ntlmssp_direction {
NTLMSSP_SEND ,
NTLMSSP_RECEIVE
} ;
2005-04-25 14:33:00 +04:00
static NTSTATUS ntlmssp_make_packet_signature ( struct gensec_ntlmssp_state * gensec_ntlmssp_state ,
2009-12-29 19:29:47 +03:00
TALLOC_CTX * sig_mem_ctx ,
const uint8_t * data , size_t length ,
const uint8_t * whole_pdu , size_t pdu_length ,
2003-11-26 04:16:41 +03:00
enum ntlmssp_direction direction ,
2007-10-07 02:16:19 +04:00
DATA_BLOB * sig , bool encrypt_sig )
2003-11-26 04:16:41 +03:00
{
2005-04-25 14:33:00 +04:00
if ( gensec_ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_NTLM2 ) {
2004-05-25 18:06:28 +04:00
2003-11-26 04:16:41 +03:00
HMACMD5Context ctx ;
2004-06-01 12:30:34 +04:00
uint8_t digest [ 16 ] ;
2004-08-30 05:34:01 +04:00
uint8_t seq_num [ 4 ] ;
2003-11-26 04:16:41 +03:00
2004-09-11 19:11:36 +04:00
* sig = data_blob_talloc ( sig_mem_ctx , NULL , NTLMSSP_SIG_SIZE ) ;
if ( ! sig - > data ) {
return NT_STATUS_NO_MEMORY ;
}
2009-12-29 19:29:47 +03:00
2004-05-25 18:06:28 +04:00
switch ( direction ) {
case NTLMSSP_SEND :
2005-05-11 23:22:22 +04:00
SIVAL ( seq_num , 0 , gensec_ntlmssp_state - > crypt . ntlm2 . send_seq_num ) ;
gensec_ntlmssp_state - > crypt . ntlm2 . send_seq_num + + ;
2009-12-29 19:29:47 +03:00
hmac_md5_init_limK_to_64 ( gensec_ntlmssp_state - > crypt . ntlm2 . send_sign_key . data ,
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm2 . send_sign_key . length , & ctx ) ;
2004-05-25 18:06:28 +04:00
break ;
case NTLMSSP_RECEIVE :
2005-05-11 23:22:22 +04:00
SIVAL ( seq_num , 0 , gensec_ntlmssp_state - > crypt . ntlm2 . recv_seq_num ) ;
gensec_ntlmssp_state - > crypt . ntlm2 . recv_seq_num + + ;
2009-12-29 19:29:47 +03:00
hmac_md5_init_limK_to_64 ( gensec_ntlmssp_state - > crypt . ntlm2 . recv_sign_key . data ,
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm2 . recv_sign_key . length , & ctx ) ;
2004-05-25 18:06:28 +04:00
break ;
}
2004-08-30 05:34:01 +04:00
hmac_md5_update ( seq_num , sizeof ( seq_num ) , & ctx ) ;
2004-09-11 19:11:36 +04:00
hmac_md5_update ( whole_pdu , pdu_length , & ctx ) ;
2003-11-26 04:16:41 +03:00
hmac_md5_final ( digest , & ctx ) ;
2005-04-25 14:33:00 +04:00
if ( encrypt_sig & & gensec_ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH ) {
2004-05-02 12:45:00 +04:00
switch ( direction ) {
case NTLMSSP_SEND :
2005-05-11 23:22:22 +04:00
arcfour_crypt_sbox ( gensec_ntlmssp_state - > crypt . ntlm2 . send_seal_arcfour_state , digest , 8 ) ;
2004-05-02 12:45:00 +04:00
break ;
case NTLMSSP_RECEIVE :
2005-05-11 23:22:22 +04:00
arcfour_crypt_sbox ( gensec_ntlmssp_state - > crypt . ntlm2 . recv_seal_arcfour_state , digest , 8 ) ;
2004-05-02 12:45:00 +04:00
break ;
}
2003-11-26 04:16:41 +03:00
}
2004-09-11 19:11:36 +04:00
2004-05-25 18:06:28 +04:00
SIVAL ( sig - > data , 0 , NTLMSSP_SIGN_VERSION ) ;
memcpy ( sig - > data + 4 , digest , 8 ) ;
memcpy ( sig - > data + 12 , seq_num , 4 ) ;
2006-07-21 05:37:38 +04:00
DEBUG ( 10 , ( " NTLM2: created signature over %llu bytes of input: \n " , ( unsigned long long ) pdu_length ) ) ;
dump_data ( 11 , sig - > data , sig - > length ) ;
2003-11-26 04:16:41 +03:00
} else {
2004-05-25 20:24:13 +04:00
uint32_t crc ;
2004-11-25 21:02:35 +03:00
crc = crc32_calc_buffer ( data , length ) ;
2008-01-04 02:22:04 +03:00
if ( ! msrpc_gen ( sig_mem_ctx ,
sig , " dddd " , NTLMSSP_SIGN_VERSION , 0 , crc , gensec_ntlmssp_state - > crypt . ntlm . seq_num ) ) {
2004-06-28 10:46:27 +04:00
return NT_STATUS_NO_MEMORY ;
2003-11-26 04:16:41 +03:00
}
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm . seq_num + + ;
2004-09-11 19:11:36 +04:00
2005-05-11 23:22:22 +04:00
arcfour_crypt_sbox ( gensec_ntlmssp_state - > crypt . ntlm . arcfour_state , sig - > data + 4 , sig - > length - 4 ) ;
2006-07-21 05:37:38 +04:00
DEBUG ( 10 , ( " NTLM1: created signature over %llu bytes of input: \n " , ( unsigned long long ) length ) ) ;
dump_data ( 11 , sig - > data , sig - > length ) ;
2003-11-26 04:16:41 +03:00
}
return NT_STATUS_OK ;
}
2009-12-30 17:58:05 +03:00
NTSTATUS ntlmssp_sign_packet ( struct gensec_ntlmssp_state * ntlmssp_state ,
TALLOC_CTX * sig_mem_ctx ,
const uint8_t * data , size_t length ,
const uint8_t * whole_pdu , size_t pdu_length ,
DATA_BLOB * sig )
2003-11-26 04:16:41 +03:00
{
2009-12-30 17:58:05 +03:00
return ntlmssp_make_packet_signature ( ntlmssp_state ,
sig_mem_ctx ,
2009-12-29 19:29:47 +03:00
data , length ,
whole_pdu , pdu_length ,
2007-10-07 02:16:19 +04:00
NTLMSSP_SEND , sig , true ) ;
2003-11-26 04:16:41 +03:00
}
/**
* Check the signature of an incoming packet
*
*/
2009-12-30 18:01:28 +03:00
NTSTATUS ntlmssp_check_packet ( struct gensec_ntlmssp_state * ntlmssp_state ,
TALLOC_CTX * sig_mem_ctx ,
const uint8_t * data , size_t length ,
const uint8_t * whole_pdu , size_t pdu_length ,
const DATA_BLOB * sig )
2003-11-26 04:16:41 +03:00
{
DATA_BLOB local_sig ;
NTSTATUS nt_status ;
2009-12-30 18:01:28 +03:00
if ( ! ntlmssp_state - > session_key . length ) {
2004-05-02 12:45:00 +04:00
DEBUG ( 3 , ( " NO session key, cannot check packet signature \n " ) ) ;
return NT_STATUS_NO_USER_SESSION_KEY ;
}
2009-12-30 18:01:28 +03:00
nt_status = ntlmssp_make_packet_signature ( ntlmssp_state , sig_mem_ctx ,
2009-12-29 19:29:47 +03:00
data , length ,
whole_pdu , pdu_length ,
2007-10-07 02:16:19 +04:00
NTLMSSP_RECEIVE , & local_sig , true ) ;
2003-11-26 04:16:41 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2009-12-08 08:50:18 +03:00
DEBUG ( 0 , ( " NTLMSSP packet sig creation failed with %s \n " , nt_errstr ( nt_status ) ) ) ;
2003-11-26 04:16:41 +03:00
return nt_status ;
}
2003-11-26 05:08:41 +03:00
2009-12-30 18:01:28 +03:00
if ( ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_NTLM2 ) {
2004-05-25 18:06:28 +04:00
if ( local_sig . length ! = sig - > length | |
memcmp ( local_sig . data ,
sig - > data , sig - > length ) ! = 0 ) {
2009-12-08 08:50:18 +03:00
DEBUG ( 10 , ( " BAD SIG NTLM2: wanted signature over %llu bytes of input: \n " , ( unsigned long long ) pdu_length ) ) ;
dump_data ( 10 , local_sig . data , local_sig . length ) ;
2004-05-25 18:06:28 +04:00
2009-12-08 08:50:18 +03:00
DEBUG ( 10 , ( " BAD SIG: got signature over %llu bytes of input: \n " , ( unsigned long long ) pdu_length ) ) ;
dump_data ( 10 , sig - > data , sig - > length ) ;
2004-05-25 18:06:28 +04:00
2009-12-30 18:01:28 +03:00
data_blob_free ( & local_sig ) ;
2004-06-18 15:59:52 +04:00
return NT_STATUS_ACCESS_DENIED ;
2004-05-25 18:06:28 +04:00
}
} else {
if ( local_sig . length ! = sig - > length | |
memcmp ( local_sig . data + 8 ,
sig - > data + 8 , sig - > length - 8 ) ! = 0 ) {
2009-12-08 08:50:18 +03:00
DEBUG ( 10 , ( " BAD SIG NTLM1: wanted signature of %llu bytes of input: \n " , ( unsigned long long ) length ) ) ;
2004-11-25 21:02:35 +03:00
dump_data ( 5 , local_sig . data , local_sig . length ) ;
2004-05-25 18:06:28 +04:00
2009-12-08 08:50:18 +03:00
DEBUG ( 10 , ( " BAD SIG: got signature of %llu bytes of input: \n " , ( unsigned long long ) length ) ) ;
dump_data ( 10 , sig - > data , sig - > length ) ;
2004-05-25 18:06:28 +04:00
2009-12-30 18:01:28 +03:00
data_blob_free ( & local_sig ) ;
2004-05-25 18:06:28 +04:00
return NT_STATUS_ACCESS_DENIED ;
}
2003-11-26 04:16:41 +03:00
}
2004-06-16 17:53:40 +04:00
dump_data_pw ( " checked ntlmssp signature \n " , sig - > data , sig - > length ) ;
2003-11-26 04:16:41 +03:00
2009-12-30 18:01:28 +03:00
data_blob_free ( & local_sig ) ;
2003-11-26 04:16:41 +03:00
return NT_STATUS_OK ;
}
/**
* Seal data with the NTLMSSP algorithm
*
*/
2009-12-30 18:02:37 +03:00
NTSTATUS ntlmssp_seal_packet ( struct gensec_ntlmssp_state * ntlmssp_state ,
TALLOC_CTX * sig_mem_ctx ,
uint8_t * data , size_t length ,
const uint8_t * whole_pdu , size_t pdu_length ,
DATA_BLOB * sig )
2005-04-25 07:37:37 +04:00
{
2004-09-11 19:11:36 +04:00
NTSTATUS nt_status ;
2009-12-30 18:02:37 +03:00
if ( ! ntlmssp_state - > session_key . length ) {
2004-05-02 12:45:00 +04:00
DEBUG ( 3 , ( " NO session key, cannot seal packet \n " ) ) ;
return NT_STATUS_NO_USER_SESSION_KEY ;
}
2003-11-26 04:16:41 +03:00
DEBUG ( 10 , ( " ntlmssp_seal_data: seal \n " ) ) ;
dump_data_pw ( " ntlmssp clear data \n " , data , length ) ;
2009-12-30 18:02:37 +03:00
if ( ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_NTLM2 ) {
2004-05-25 18:06:28 +04:00
/* The order of these two operations matters - we must first seal the packet,
2010-03-03 18:03:13 +03:00
then seal the sequence number - this is because the send_seal_hash is not
2004-05-25 18:06:28 +04:00
constant , but is is rather updated with each iteration */
2009-12-30 18:02:37 +03:00
nt_status = ntlmssp_make_packet_signature ( ntlmssp_state , sig_mem_ctx ,
2009-12-29 19:29:47 +03:00
data , length ,
whole_pdu , pdu_length ,
2007-10-07 02:16:19 +04:00
NTLMSSP_SEND , sig , false ) ;
2009-12-30 18:02:37 +03:00
arcfour_crypt_sbox ( ntlmssp_state - > crypt . ntlm2 . send_seal_arcfour_state , data , length ) ;
if ( ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH ) {
arcfour_crypt_sbox ( ntlmssp_state - > crypt . ntlm2 . send_seal_arcfour_state , sig - > data + 4 , 8 ) ;
2004-09-12 10:38:00 +04:00
}
2003-11-26 04:16:41 +03:00
} else {
2004-05-25 20:24:13 +04:00
uint32_t crc ;
2004-11-25 21:02:35 +03:00
crc = crc32_calc_buffer ( data , length ) ;
2009-12-29 19:29:47 +03:00
if ( ! msrpc_gen ( sig_mem_ctx ,
2009-12-30 18:02:37 +03:00
sig , " dddd " , NTLMSSP_SIGN_VERSION , 0 ,
crc , ntlmssp_state - > crypt . ntlm . seq_num ) ) {
2004-06-28 10:46:27 +04:00
return NT_STATUS_NO_MEMORY ;
2003-11-26 04:16:41 +03:00
}
2004-09-12 10:38:00 +04:00
/* The order of these two operations matters - we must
first seal the packet , then seal the sequence
2010-03-03 18:03:13 +03:00
number - this is because the ntlmssp_hash is not
2004-09-12 10:38:00 +04:00
constant , but is is rather updated with each
iteration */
2003-11-26 04:16:41 +03:00
2009-12-30 18:02:37 +03:00
arcfour_crypt_sbox ( ntlmssp_state - > crypt . ntlm . arcfour_state , data , length ) ;
arcfour_crypt_sbox ( ntlmssp_state - > crypt . ntlm . arcfour_state , sig - > data + 4 , sig - > length - 4 ) ;
2004-09-11 19:11:36 +04:00
/* increment counter on send */
2009-12-30 18:02:37 +03:00
ntlmssp_state - > crypt . ntlm . seq_num + + ;
2004-09-11 19:11:36 +04:00
nt_status = NT_STATUS_OK ;
2003-11-26 04:16:41 +03:00
}
2004-06-16 17:53:40 +04:00
dump_data_pw ( " ntlmssp signature \n " , sig - > data , sig - > length ) ;
2003-11-26 04:16:41 +03:00
dump_data_pw ( " ntlmssp sealed data \n " , data , length ) ;
2004-09-11 19:11:36 +04:00
return nt_status ;
2003-11-26 04:16:41 +03:00
}
/**
* Unseal data with the NTLMSSP algorithm
*
*/
2005-04-25 07:37:37 +04:00
/*
wrappers for the ntlmssp_ * ( ) functions
*/
2009-12-29 19:29:47 +03:00
NTSTATUS gensec_ntlmssp_unseal_packet ( struct gensec_security * gensec_security ,
TALLOC_CTX * sig_mem_ctx ,
uint8_t * data , size_t length ,
const uint8_t * whole_pdu , size_t pdu_length ,
2005-04-25 07:37:37 +04:00
const DATA_BLOB * sig )
2003-11-26 04:16:41 +03:00
{
2009-12-08 08:50:18 +03:00
NTSTATUS status ;
2009-12-30 10:23:13 +03:00
struct gensec_ntlmssp_context * gensec_ntlmssp =
talloc_get_type_abort ( gensec_security - > private_data ,
struct gensec_ntlmssp_context ) ;
struct gensec_ntlmssp_state * gensec_ntlmssp_state = gensec_ntlmssp - > ntlmssp_state ;
2005-04-25 14:33:00 +04:00
if ( ! gensec_ntlmssp_state - > session_key . length ) {
2004-05-02 12:45:00 +04:00
DEBUG ( 3 , ( " NO session key, cannot unseal packet \n " ) ) ;
return NT_STATUS_NO_USER_SESSION_KEY ;
}
2003-11-26 04:16:41 +03:00
dump_data_pw ( " ntlmssp sealed data \n " , data , length ) ;
2005-04-25 14:33:00 +04:00
if ( gensec_ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_NTLM2 ) {
2005-05-11 23:22:22 +04:00
arcfour_crypt_sbox ( gensec_ntlmssp_state - > crypt . ntlm2 . recv_seal_arcfour_state , data , length ) ;
2003-11-26 04:16:41 +03:00
} else {
2005-05-11 23:22:22 +04:00
arcfour_crypt_sbox ( gensec_ntlmssp_state - > crypt . ntlm . arcfour_state , data , length ) ;
2003-11-26 04:16:41 +03:00
}
2005-08-20 10:14:14 +04:00
dump_data_pw ( " ntlmssp clear data \n " , data , length ) ;
2009-12-08 08:50:18 +03:00
status = gensec_ntlmssp_check_packet ( gensec_security , sig_mem_ctx , data , length , whole_pdu , pdu_length , sig ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " NTLMSSP packet check for unseal failed due to invalid signature on %llu bytes of input: \n " , ( unsigned long long ) length ) ) ;
}
return status ;
2003-11-26 04:16:41 +03:00
}
/**
Initialise the state for NTLMSSP signing .
*/
2006-03-09 16:42:13 +03:00
/* TODO: make this non-public */
2008-04-02 06:53:27 +04:00
NTSTATUS ntlmssp_sign_init ( struct gensec_ntlmssp_state * gensec_ntlmssp_state )
2003-11-26 04:16:41 +03:00
{
2006-02-12 15:42:37 +03:00
TALLOC_CTX * mem_ctx = talloc_new ( gensec_ntlmssp_state ) ;
if ( ! mem_ctx ) {
return NT_STATUS_NO_MEMORY ;
}
2003-11-26 04:16:41 +03:00
DEBUG ( 3 , ( " NTLMSSP Sign/Seal - Initialising with flags: \n " ) ) ;
2005-04-25 14:33:00 +04:00
debug_ntlmssp_flags ( gensec_ntlmssp_state - > neg_flags ) ;
2003-11-26 04:16:41 +03:00
2006-02-12 15:42:37 +03:00
if ( gensec_ntlmssp_state - > session_key . length < 8 ) {
talloc_free ( mem_ctx ) ;
2004-05-02 12:45:00 +04:00
DEBUG ( 3 , ( " NO session key, cannot intialise signing \n " ) ) ;
return NT_STATUS_NO_USER_SESSION_KEY ;
}
2005-04-25 14:33:00 +04:00
if ( gensec_ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_NTLM2 )
2003-11-26 04:16:41 +03:00
{
2005-04-25 14:33:00 +04:00
DATA_BLOB weak_session_key = gensec_ntlmssp_state - > session_key ;
2003-11-26 04:16:41 +03:00
const char * send_sign_const ;
const char * send_seal_const ;
const char * recv_sign_const ;
const char * recv_seal_const ;
2005-04-25 12:26:53 +04:00
DATA_BLOB send_seal_key ;
DATA_BLOB recv_seal_key ;
2005-04-25 14:33:00 +04:00
switch ( gensec_ntlmssp_state - > role ) {
2003-11-26 04:16:41 +03:00
case NTLMSSP_CLIENT :
send_sign_const = CLI_SIGN ;
send_seal_const = CLI_SEAL ;
recv_sign_const = SRV_SIGN ;
recv_seal_const = SRV_SEAL ;
break ;
case NTLMSSP_SERVER :
send_sign_const = SRV_SIGN ;
send_seal_const = SRV_SEAL ;
recv_sign_const = CLI_SIGN ;
recv_seal_const = CLI_SEAL ;
break ;
2004-12-02 07:51:56 +03:00
default :
2006-02-12 15:42:37 +03:00
talloc_free ( mem_ctx ) ;
2004-12-02 07:51:56 +03:00
return NT_STATUS_INTERNAL_ERROR ;
2003-11-26 04:16:41 +03:00
}
2004-06-16 17:53:40 +04:00
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm2 . send_seal_arcfour_state = talloc ( gensec_ntlmssp_state , struct arcfour_state ) ;
NT_STATUS_HAVE_NO_MEMORY ( gensec_ntlmssp_state - > crypt . ntlm2 . send_seal_arcfour_state ) ;
gensec_ntlmssp_state - > crypt . ntlm2 . recv_seal_arcfour_state = talloc ( gensec_ntlmssp_state , struct arcfour_state ) ;
NT_STATUS_HAVE_NO_MEMORY ( gensec_ntlmssp_state - > crypt . ntlm2 . send_seal_arcfour_state ) ;
2005-04-25 12:26:53 +04:00
2004-06-16 17:53:40 +04:00
/**
2005-08-20 10:14:14 +04:00
Weaken NTLMSSP keys to cope with down - level
clients , servers and export restrictions .
2004-06-16 17:53:40 +04:00
2005-08-20 10:14:14 +04:00
We probably should have some parameters to control
this , once we get NTLM2 working .
2004-06-16 17:53:40 +04:00
*/
2005-08-20 10:14:14 +04:00
/* Key weakening was not performed on the master key
* for NTLM2 ( in ntlmssp_weaken_keys ( ) ) , but must be
* done on the encryption subkeys only . That is why
* we don ' t have this code for the ntlmv1 case .
*/
2004-06-16 17:53:40 +04:00
2005-04-25 14:33:00 +04:00
if ( gensec_ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_128 ) {
2004-06-16 17:53:40 +04:00
2005-04-25 14:33:00 +04:00
} else if ( gensec_ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_56 ) {
2006-02-12 16:53:42 +03:00
weak_session_key . length = 7 ;
2004-06-16 17:53:40 +04:00
} else { /* forty bits */
weak_session_key . length = 5 ;
}
dump_data_pw ( " NTLMSSP weakend master key: \n " ,
weak_session_key . data ,
weak_session_key . length ) ;
2003-11-26 04:16:41 +03:00
2006-02-12 15:42:37 +03:00
/* SEND: sign key */
2005-04-25 14:33:00 +04:00
calc_ntlmv2_key ( gensec_ntlmssp_state ,
2005-05-11 23:22:22 +04:00
& gensec_ntlmssp_state - > crypt . ntlm2 . send_sign_key ,
2005-04-25 14:33:00 +04:00
gensec_ntlmssp_state - > session_key , send_sign_const ) ;
2004-05-25 18:06:28 +04:00
dump_data_pw ( " NTLMSSP send sign key: \n " ,
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm2 . send_sign_key . data ,
gensec_ntlmssp_state - > crypt . ntlm2 . send_sign_key . length ) ;
2004-05-25 18:06:28 +04:00
2006-02-12 15:42:37 +03:00
/* SEND: seal ARCFOUR pad */
calc_ntlmv2_key ( mem_ctx ,
2005-04-25 12:26:53 +04:00
& send_seal_key ,
2004-06-16 17:53:40 +04:00
weak_session_key , send_seal_const ) ;
2004-05-25 18:06:28 +04:00
dump_data_pw ( " NTLMSSP send seal key: \n " ,
2005-04-25 12:26:53 +04:00
send_seal_key . data ,
send_seal_key . length ) ;
2005-05-11 23:22:22 +04:00
arcfour_init ( gensec_ntlmssp_state - > crypt . ntlm2 . send_seal_arcfour_state ,
2005-04-25 12:26:53 +04:00
& send_seal_key ) ;
2003-11-26 04:16:41 +03:00
dump_data_pw ( " NTLMSSP send sesl hash: \n " ,
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm2 . send_seal_arcfour_state - > sbox ,
sizeof ( gensec_ntlmssp_state - > crypt . ntlm2 . send_seal_arcfour_state - > sbox ) ) ;
2003-11-26 04:16:41 +03:00
2006-02-12 15:42:37 +03:00
/* RECV: sign key */
2005-04-25 14:33:00 +04:00
calc_ntlmv2_key ( gensec_ntlmssp_state ,
2005-05-11 23:22:22 +04:00
& gensec_ntlmssp_state - > crypt . ntlm2 . recv_sign_key ,
2005-04-25 14:33:00 +04:00
gensec_ntlmssp_state - > session_key , recv_sign_const ) ;
2004-05-25 18:06:28 +04:00
dump_data_pw ( " NTLMSSP recv sign key: \n " ,
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm2 . recv_sign_key . data ,
gensec_ntlmssp_state - > crypt . ntlm2 . recv_sign_key . length ) ;
2003-11-26 04:16:41 +03:00
2006-02-12 15:42:37 +03:00
/* RECV: seal ARCFOUR pad */
calc_ntlmv2_key ( mem_ctx ,
2005-04-25 12:26:53 +04:00
& recv_seal_key ,
2004-06-16 17:53:40 +04:00
weak_session_key , recv_seal_const ) ;
2004-05-25 18:06:28 +04:00
dump_data_pw ( " NTLMSSP recv seal key: \n " ,
2005-04-25 12:26:53 +04:00
recv_seal_key . data ,
recv_seal_key . length ) ;
2005-05-11 23:22:22 +04:00
arcfour_init ( gensec_ntlmssp_state - > crypt . ntlm2 . recv_seal_arcfour_state ,
2005-04-25 12:26:53 +04:00
& recv_seal_key ) ;
2004-06-16 17:53:40 +04:00
dump_data_pw ( " NTLMSSP receive seal hash: \n " ,
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm2 . recv_seal_arcfour_state - > sbox ,
sizeof ( gensec_ntlmssp_state - > crypt . ntlm2 . recv_seal_arcfour_state - > sbox ) ) ;
2005-04-25 13:23:56 +04:00
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm2 . send_seq_num = 0 ;
gensec_ntlmssp_state - > crypt . ntlm2 . recv_seq_num = 0 ;
2005-04-25 13:23:56 +04:00
2003-11-26 04:16:41 +03:00
} else {
2006-02-12 15:42:37 +03:00
DATA_BLOB weak_session_key = ntlmssp_weakend_key ( gensec_ntlmssp_state , mem_ctx ) ;
2004-06-16 17:53:40 +04:00
DEBUG ( 5 , ( " NTLMSSP Sign/Seal - using NTLM1 \n " ) ) ;
2003-11-26 04:16:41 +03:00
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm . arcfour_state = talloc ( gensec_ntlmssp_state , struct arcfour_state ) ;
NT_STATUS_HAVE_NO_MEMORY ( gensec_ntlmssp_state - > crypt . ntlm . arcfour_state ) ;
2005-04-25 12:26:53 +04:00
2005-05-11 23:22:22 +04:00
arcfour_init ( gensec_ntlmssp_state - > crypt . ntlm . arcfour_state ,
2006-02-12 15:42:37 +03:00
& weak_session_key ) ;
2005-05-11 23:22:22 +04:00
dump_data_pw ( " NTLMSSP hash: \n " , gensec_ntlmssp_state - > crypt . ntlm . arcfour_state - > sbox ,
sizeof ( gensec_ntlmssp_state - > crypt . ntlm . arcfour_state - > sbox ) ) ;
2003-11-26 04:16:41 +03:00
2005-05-11 23:22:22 +04:00
gensec_ntlmssp_state - > crypt . ntlm . seq_num = 0 ;
2005-04-25 13:23:56 +04:00
}
2003-11-26 04:16:41 +03:00
2006-02-12 15:42:37 +03:00
talloc_free ( mem_ctx ) ;
2003-11-26 04:16:41 +03:00
return NT_STATUS_OK ;
}
2005-04-25 07:37:37 +04:00
2009-12-30 17:58:05 +03:00
NTSTATUS gensec_ntlmssp_sign_packet ( struct gensec_security * gensec_security ,
TALLOC_CTX * sig_mem_ctx ,
const uint8_t * data , size_t length ,
const uint8_t * whole_pdu , size_t pdu_length ,
DATA_BLOB * sig )
{
struct gensec_ntlmssp_context * gensec_ntlmssp =
talloc_get_type_abort ( gensec_security - > private_data ,
struct gensec_ntlmssp_context ) ;
NTSTATUS nt_status ;
nt_status = ntlmssp_sign_packet ( gensec_ntlmssp - > ntlmssp_state ,
sig_mem_ctx ,
data , length ,
whole_pdu , pdu_length ,
sig ) ;
return nt_status ;
}
2009-12-30 18:01:28 +03:00
NTSTATUS gensec_ntlmssp_check_packet ( struct gensec_security * gensec_security ,
TALLOC_CTX * sig_mem_ctx ,
const uint8_t * data , size_t length ,
const uint8_t * whole_pdu , size_t pdu_length ,
const DATA_BLOB * sig )
{
struct gensec_ntlmssp_context * gensec_ntlmssp =
talloc_get_type_abort ( gensec_security - > private_data ,
struct gensec_ntlmssp_context ) ;
NTSTATUS nt_status ;
nt_status = ntlmssp_check_packet ( gensec_ntlmssp - > ntlmssp_state ,
sig_mem_ctx ,
data , length ,
whole_pdu , pdu_length ,
sig ) ;
return nt_status ;
}
2009-12-30 18:02:37 +03:00
NTSTATUS gensec_ntlmssp_seal_packet ( struct gensec_security * gensec_security ,
TALLOC_CTX * sig_mem_ctx ,
uint8_t * data , size_t length ,
const uint8_t * whole_pdu , size_t pdu_length ,
DATA_BLOB * sig )
{
struct gensec_ntlmssp_context * gensec_ntlmssp =
talloc_get_type_abort ( gensec_security - > private_data ,
struct gensec_ntlmssp_context ) ;
NTSTATUS nt_status ;
nt_status = ntlmssp_seal_packet ( gensec_ntlmssp - > ntlmssp_state ,
sig_mem_ctx ,
data , length ,
whole_pdu , pdu_length ,
sig ) ;
return nt_status ;
}
2005-09-11 15:19:02 +04:00
size_t gensec_ntlmssp_sig_size ( struct gensec_security * gensec_security , size_t data_size )
2005-04-25 07:37:37 +04:00
{
return NTLMSSP_SIG_SIZE ;
}
NTSTATUS gensec_ntlmssp_wrap ( struct gensec_security * gensec_security ,
TALLOC_CTX * sig_mem_ctx ,
const DATA_BLOB * in ,
DATA_BLOB * out )
{
DATA_BLOB sig ;
NTSTATUS nt_status ;
2005-08-20 10:14:14 +04:00
if ( gensec_have_feature ( gensec_security , GENSEC_FEATURE_SEAL ) ) {
2005-04-25 07:37:37 +04:00
* out = data_blob_talloc ( sig_mem_ctx , NULL , in - > length + NTLMSSP_SIG_SIZE ) ;
2006-07-21 05:37:38 +04:00
if ( ! out - > data ) {
return NT_STATUS_NO_MEMORY ;
}
2005-04-25 07:37:37 +04:00
memcpy ( out - > data + NTLMSSP_SIG_SIZE , in - > data , in - > length ) ;
2005-08-20 10:14:14 +04:00
2005-04-25 07:37:37 +04:00
nt_status = gensec_ntlmssp_seal_packet ( gensec_security , sig_mem_ctx ,
out - > data + NTLMSSP_SIG_SIZE ,
out - > length - NTLMSSP_SIG_SIZE ,
out - > data + NTLMSSP_SIG_SIZE ,
out - > length - NTLMSSP_SIG_SIZE ,
& sig ) ;
2005-08-20 10:14:14 +04:00
2005-04-25 07:37:37 +04:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
memcpy ( out - > data , sig . data , NTLMSSP_SIG_SIZE ) ;
}
return nt_status ;
2005-08-20 10:14:14 +04:00
} else if ( gensec_have_feature ( gensec_security , GENSEC_FEATURE_SIGN ) ) {
2005-04-25 07:37:37 +04:00
* out = data_blob_talloc ( sig_mem_ctx , NULL , in - > length + NTLMSSP_SIG_SIZE ) ;
2006-07-21 05:37:38 +04:00
if ( ! out - > data ) {
return NT_STATUS_NO_MEMORY ;
}
2005-04-25 07:37:37 +04:00
memcpy ( out - > data + NTLMSSP_SIG_SIZE , in - > data , in - > length ) ;
nt_status = gensec_ntlmssp_sign_packet ( gensec_security , sig_mem_ctx ,
2005-08-20 10:14:14 +04:00
out - > data + NTLMSSP_SIG_SIZE ,
out - > length - NTLMSSP_SIG_SIZE ,
out - > data + NTLMSSP_SIG_SIZE ,
out - > length - NTLMSSP_SIG_SIZE ,
& sig ) ;
2005-04-25 07:37:37 +04:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
memcpy ( out - > data , sig . data , NTLMSSP_SIG_SIZE ) ;
}
return nt_status ;
} else {
* out = * in ;
return NT_STATUS_OK ;
}
}
NTSTATUS gensec_ntlmssp_unwrap ( struct gensec_security * gensec_security ,
TALLOC_CTX * sig_mem_ctx ,
const DATA_BLOB * in ,
DATA_BLOB * out )
{
2009-12-30 10:23:13 +03:00
struct gensec_ntlmssp_context * gensec_ntlmssp =
talloc_get_type_abort ( gensec_security - > private_data ,
struct gensec_ntlmssp_context ) ;
struct gensec_ntlmssp_state * gensec_ntlmssp_state = gensec_ntlmssp - > ntlmssp_state ;
2005-04-25 07:37:37 +04:00
DATA_BLOB sig ;
2005-08-20 10:14:14 +04:00
if ( gensec_have_feature ( gensec_security , GENSEC_FEATURE_SEAL ) ) {
2005-04-25 07:37:37 +04:00
if ( in - > length < NTLMSSP_SIG_SIZE ) {
return NT_STATUS_INVALID_PARAMETER ;
}
sig . data = in - > data ;
sig . length = NTLMSSP_SIG_SIZE ;
* out = data_blob_talloc ( sig_mem_ctx , in - > data + NTLMSSP_SIG_SIZE , in - > length - NTLMSSP_SIG_SIZE ) ;
return gensec_ntlmssp_unseal_packet ( gensec_security , sig_mem_ctx ,
out - > data , out - > length ,
out - > data , out - > length ,
& sig ) ;
2005-08-20 10:14:14 +04:00
} else if ( gensec_have_feature ( gensec_security , GENSEC_FEATURE_SIGN ) ) {
2009-07-08 11:22:39 +04:00
NTSTATUS status ;
uint32_t ntlm_seqnum ;
struct arcfour_state ntlm_state ;
uint32_t ntlm2_seqnum_r ;
uint8_t ntlm2_key_r [ 16 ] ;
struct arcfour_state ntlm2_state_r ;
2005-04-25 07:37:37 +04:00
if ( in - > length < NTLMSSP_SIG_SIZE ) {
return NT_STATUS_INVALID_PARAMETER ;
}
sig . data = in - > data ;
sig . length = NTLMSSP_SIG_SIZE ;
* out = data_blob_talloc ( sig_mem_ctx , in - > data + NTLMSSP_SIG_SIZE , in - > length - NTLMSSP_SIG_SIZE ) ;
2009-07-08 11:22:39 +04:00
if ( gensec_ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_NTLM2 ) {
ntlm2_seqnum_r = gensec_ntlmssp_state - > crypt . ntlm2 . recv_seq_num ;
ntlm2_state_r = * gensec_ntlmssp_state - > crypt . ntlm2 . recv_seal_arcfour_state ;
memcpy ( ntlm2_key_r ,
gensec_ntlmssp_state - > crypt . ntlm2 . recv_sign_key . data ,
16 ) ;
} else {
ntlm_seqnum = gensec_ntlmssp_state - > crypt . ntlm . seq_num ;
ntlm_state = * gensec_ntlmssp_state - > crypt . ntlm . arcfour_state ;
}
status = gensec_ntlmssp_check_packet ( gensec_security , sig_mem_ctx ,
out - > data , out - > length ,
out - > data , out - > length ,
& sig ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
NTSTATUS check_status = status ;
/*
* The Windows LDAP libraries seems to have a bug
* and always use sealing even if only signing was
* negotiated . So we need to fallback .
*/
if ( gensec_ntlmssp_state - > neg_flags & NTLMSSP_NEGOTIATE_NTLM2 ) {
gensec_ntlmssp_state - > crypt . ntlm2 . recv_seq_num = ntlm2_seqnum_r ;
* gensec_ntlmssp_state - > crypt . ntlm2 . recv_seal_arcfour_state = ntlm2_state_r ;
memcpy ( gensec_ntlmssp_state - > crypt . ntlm2 . recv_sign_key . data ,
ntlm2_key_r , 16 ) ;
} else {
gensec_ntlmssp_state - > crypt . ntlm . seq_num = ntlm_seqnum ;
* gensec_ntlmssp_state - > crypt . ntlm . arcfour_state = ntlm_state ;
}
status = gensec_ntlmssp_unseal_packet ( gensec_security ,
sig_mem_ctx ,
out - > data ,
out - > length ,
out - > data ,
out - > length ,
& sig ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
gensec_ntlmssp_state - > neg_flags | = NTLMSSP_NEGOTIATE_SEAL ;
} else {
status = check_status ;
}
}
2009-12-08 08:50:18 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " NTLMSSP packet check for unwrap failed due to invalid signature \n " ) ) ;
}
2009-07-08 11:22:39 +04:00
return status ;
2005-04-25 07:37:37 +04:00
} else {
* out = * in ;
return NT_STATUS_OK ;
}
}