2001-10-12 04:49:42 +00:00
/*
2002-01-30 06:08:46 +00:00
Unix SMB / CIFS implementation .
2001-10-12 04:49:42 +00:00
simple kerberos5 / SPNEGO routines
Copyright ( C ) Andrew Tridgell 2001
2003-08-01 15:21:20 +00:00
Copyright ( C ) Jim McDonough < jmcd @ us . ibm . com > 2002
2003-03-17 22:45:16 +00:00
Copyright ( C ) Luke Howard 2003
2010-07-20 09:51:48 -07:00
Copyright ( C ) Jeremy Allison 2010
2001-10-12 04:49:42 +00: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-09 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
2001-10-12 04:49:42 +00: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 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2001-10-12 04:49:42 +00:00
*/
# include "includes.h"
2009-09-17 00:21:01 +02:00
# include "../libcli/auth/spnego.h"
2009-11-27 15:52:57 +01:00
# include "smb_krb5.h"
2011-02-24 12:27:29 +01:00
# include "../lib/util/asn1.h"
2001-10-12 04:49:42 +00:00
/*
2010-07-19 16:45:16 -07:00
generate a negTokenInit packet given a list of supported
2010-07-19 17:14:26 -07:00
OIDs ( the mechanisms ) a blob , and a principal name string
2001-10-12 04:49:42 +00:00
*/
2010-07-19 17:14:26 -07:00
2010-07-20 14:59:31 -07:00
DATA_BLOB spnego_gen_negTokenInit ( TALLOC_CTX * ctx ,
const char * OIDs [ ] ,
2010-07-19 17:14:26 -07:00
DATA_BLOB * psecblob ,
2001-10-21 20:51:27 +00:00
const char * principal )
2001-10-12 04:49:42 +00:00
{
int i ;
2008-10-22 19:23:49 +02:00
ASN1_DATA * data ;
2001-10-17 08:54:19 +00:00
DATA_BLOB ret ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
return data_blob_null ;
}
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_push_tag ( data , ASN1_APPLICATION ( 0 ) ) ;
asn1_write_OID ( data , OID_SPNEGO ) ;
asn1_push_tag ( data , ASN1_CONTEXT ( 0 ) ) ;
asn1_push_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_push_tag ( data , ASN1_CONTEXT ( 0 ) ) ;
asn1_push_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
2001-10-12 04:49:42 +00:00
for ( i = 0 ; OIDs [ i ] ; i + + ) {
2008-10-22 19:23:49 +02:00
asn1_write_OID ( data , OIDs [ i ] ) ;
2001-10-12 04:49:42 +00:00
}
2008-10-22 19:23:49 +02:00
asn1_pop_tag ( data ) ;
asn1_pop_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2010-07-19 17:14:26 -07:00
if ( psecblob & & psecblob - > length & & psecblob - > data ) {
asn1_push_tag ( data , ASN1_CONTEXT ( 2 ) ) ;
asn1_write_OctetString ( data , psecblob - > data ,
psecblob - > length ) ;
asn1_pop_tag ( data ) ;
2001-10-12 04:49:42 +00:00
}
2010-07-19 17:14:26 -07:00
if ( principal ) {
asn1_push_tag ( data , ASN1_CONTEXT ( 3 ) ) ;
asn1_push_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_push_tag ( data , ASN1_CONTEXT ( 0 ) ) ;
asn1_write_GeneralString ( data , principal ) ;
asn1_pop_tag ( data ) ;
asn1_pop_tag ( data ) ;
asn1_pop_tag ( data ) ;
2008-10-22 19:23:49 +02:00
}
2002-09-25 15:19:00 +00:00
2008-10-22 19:23:49 +02:00
asn1_pop_tag ( data ) ;
asn1_pop_tag ( data ) ;
2002-09-25 15:19:00 +00:00
2008-10-22 19:23:49 +02:00
asn1_pop_tag ( data ) ;
2002-09-25 15:19:00 +00:00
2008-10-22 19:23:49 +02:00
if ( data - > has_error ) {
DEBUG ( 1 , ( " Failed to build negTokenInit at offset %d \n " , ( int ) data - > ofs ) ) ;
2002-09-25 15:19:00 +00:00
}
2010-07-20 14:59:31 -07:00
ret = data_blob_talloc ( ctx , data - > data , data - > length ) ;
2008-10-22 19:23:49 +02:00
asn1_free ( data ) ;
2002-09-25 15:19:00 +00:00
return ret ;
}
2001-10-12 04:49:42 +00:00
/*
parse a negTokenInit packet giving a GUID , a list of supported
2001-10-21 20:51:27 +00:00
OIDs ( the mechanisms ) and a principal name string
2001-10-12 04:49:42 +00:00
*/
2010-07-20 13:35:43 -07:00
bool spnego_parse_negTokenInit ( TALLOC_CTX * ctx ,
DATA_BLOB blob ,
2008-10-22 14:06:08 +02:00
char * OIDs [ ASN1_MAX_OIDS ] ,
2010-07-19 15:41:45 -07:00
char * * principal ,
DATA_BLOB * secblob )
2001-10-12 04:49:42 +00:00
{
int i ;
2007-10-18 17:40:25 -07:00
bool ret ;
2008-10-22 19:23:49 +02:00
ASN1_DATA * data ;
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
return false ;
}
asn1_load ( data , blob ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_start_tag ( data , ASN1_APPLICATION ( 0 ) ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_check_OID ( data , OID_SPNEGO ) ;
2010-07-19 14:21:01 -07:00
/* negTokenInit [0] NegTokenInit */
2008-10-22 19:23:49 +02:00
asn1_start_tag ( data , ASN1_CONTEXT ( 0 ) ) ;
asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
2001-10-12 04:49:42 +00:00
2010-07-19 14:21:01 -07:00
/* mechTypes [0] MechTypeList OPTIONAL */
/* Not really optional, we depend on this to decide
* what mechanisms we have to work with . */
2008-10-22 19:23:49 +02:00
asn1_start_tag ( data , ASN1_CONTEXT ( 0 ) ) ;
asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
for ( i = 0 ; asn1_tag_remaining ( data ) > 0 & & i < ASN1_MAX_OIDS - 1 ; i + + ) {
2011-09-20 18:50:00 -07:00
if ( ! asn1_read_OID ( data , ctx , & OIDs [ i ] ) ) {
break ;
}
if ( data - > has_error ) {
break ;
}
2001-10-12 04:49:42 +00:00
}
OIDs [ i ] = NULL ;
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
asn1_end_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2010-07-19 15:41:45 -07:00
if ( principal ) {
* principal = NULL ;
}
if ( secblob ) {
* secblob = data_blob_null ;
}
2010-07-19 14:21:01 -07:00
/*
Win7 + Live Sign - in Assistant attaches a mechToken
ASN1_CONTEXT ( 2 ) to the negTokenInit packet
which breaks our negotiation if we just assume
the next tag is ASN1_CONTEXT ( 3 ) .
*/
2010-07-20 09:51:48 -07:00
if ( asn1_peek_tag ( data , ASN1_CONTEXT ( 1 ) ) ) {
uint8 flags ;
/* reqFlags [1] ContextFlags OPTIONAL */
asn1_start_tag ( data , ASN1_CONTEXT ( 1 ) ) ;
asn1_start_tag ( data , ASN1_BIT_STRING ) ;
while ( asn1_tag_remaining ( data ) > 0 ) {
asn1_read_uint8 ( data , & flags ) ;
2010-07-19 14:21:01 -07:00
}
2010-07-20 09:51:48 -07:00
asn1_end_tag ( data ) ;
asn1_end_tag ( data ) ;
2010-07-19 14:21:01 -07:00
}
2010-07-20 09:51:48 -07:00
if ( asn1_peek_tag ( data , ASN1_CONTEXT ( 2 ) ) ) {
DATA_BLOB sblob = data_blob_null ;
/* mechToken [2] OCTET STRING OPTIONAL */
asn1_start_tag ( data , ASN1_CONTEXT ( 2 ) ) ;
2010-07-20 13:35:43 -07:00
asn1_read_OctetString ( data , ctx , & sblob ) ;
2010-07-20 09:51:48 -07:00
asn1_end_tag ( data ) ;
if ( secblob ) {
* secblob = sblob ;
} else {
data_blob_free ( & sblob ) ;
2010-07-19 14:21:01 -07:00
}
}
2010-07-20 09:51:48 -07:00
if ( asn1_peek_tag ( data , ASN1_CONTEXT ( 3 ) ) ) {
char * princ = NULL ;
/* mechListMIC [3] OCTET STRING OPTIONAL */
asn1_start_tag ( data , ASN1_CONTEXT ( 3 ) ) ;
asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_start_tag ( data , ASN1_CONTEXT ( 0 ) ) ;
2010-07-20 13:35:43 -07:00
asn1_read_GeneralString ( data , ctx , & princ ) ;
2010-07-20 09:51:48 -07:00
asn1_end_tag ( data ) ;
asn1_end_tag ( data ) ;
asn1_end_tag ( data ) ;
if ( principal ) {
* principal = princ ;
} else {
TALLOC_FREE ( princ ) ;
2010-07-19 14:21:01 -07:00
}
2006-10-02 12:54:49 +00:00
}
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
asn1_end_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
ret = ! data - > has_error ;
if ( data - > has_error ) {
2006-06-16 22:25:17 +00:00
int j ;
2010-07-19 15:41:45 -07:00
if ( principal ) {
TALLOC_FREE ( * principal ) ;
}
if ( secblob ) {
data_blob_free ( secblob ) ;
}
2006-06-16 22:25:17 +00:00
for ( j = 0 ; j < i & & j < ASN1_MAX_OIDS - 1 ; j + + ) {
2008-10-22 14:06:08 +02:00
TALLOC_FREE ( OIDs [ j ] ) ;
2006-06-16 22:25:17 +00:00
}
}
2008-10-22 19:23:49 +02:00
asn1_free ( data ) ;
2001-10-12 04:49:42 +00:00
return ret ;
}
/*
generate a krb5 GSS - API wrapper packet given a ticket
*/
2010-07-20 16:17:58 -07:00
DATA_BLOB spnego_gen_krb5_wrap ( TALLOC_CTX * ctx , const DATA_BLOB ticket , const uint8 tok_id [ 2 ] )
2001-10-12 04:49:42 +00:00
{
2008-10-22 19:23:49 +02:00
ASN1_DATA * data ;
2001-10-12 04:49:42 +00:00
DATA_BLOB ret ;
2008-10-22 19:23:49 +02:00
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
return data_blob_null ;
}
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_push_tag ( data , ASN1_APPLICATION ( 0 ) ) ;
asn1_write_OID ( data , OID_KERBEROS5 ) ;
2003-03-17 22:45:16 +00:00
2008-10-22 19:23:49 +02:00
asn1_write ( data , tok_id , 2 ) ;
asn1_write ( data , ticket . data , ticket . length ) ;
asn1_pop_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
if ( data - > has_error ) {
DEBUG ( 1 , ( " Failed to build krb5 wrapper at offset %d \n " , ( int ) data - > ofs ) ) ;
2001-10-12 04:49:42 +00:00
}
2010-07-20 16:17:58 -07:00
ret = data_blob_talloc ( ctx , data - > data , data - > length ) ;
2008-10-22 19:23:49 +02:00
asn1_free ( data ) ;
2001-10-12 04:49:42 +00:00
return ret ;
}
2001-10-18 10:26:06 +00:00
/*
parse a krb5 GSS - API wrapper packet giving a ticket
*/
2010-07-20 16:17:58 -07:00
bool spnego_parse_krb5_wrap ( TALLOC_CTX * ctx , DATA_BLOB blob , DATA_BLOB * ticket , uint8 tok_id [ 2 ] )
2001-10-18 10:26:06 +00:00
{
2007-10-18 17:40:25 -07:00
bool ret ;
2008-10-22 19:23:49 +02:00
ASN1_DATA * data ;
2002-02-15 23:11:13 +00:00
int data_remaining ;
2001-10-18 10:26:06 +00:00
2008-10-22 19:23:49 +02:00
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
return false ;
}
asn1_load ( data , blob ) ;
asn1_start_tag ( data , ASN1_APPLICATION ( 0 ) ) ;
asn1_check_OID ( data , OID_KERBEROS5 ) ;
2002-02-15 23:11:13 +00:00
2008-10-22 19:23:49 +02:00
data_remaining = asn1_tag_remaining ( data ) ;
2002-02-15 23:11:13 +00:00
2003-03-17 22:45:16 +00:00
if ( data_remaining < 3 ) {
2008-10-22 19:23:49 +02:00
data - > has_error = True ;
2002-02-15 23:11:13 +00:00
} else {
2008-10-22 19:23:49 +02:00
asn1_read ( data , tok_id , 2 ) ;
2003-03-17 22:45:16 +00:00
data_remaining - = 2 ;
2010-07-20 16:17:58 -07:00
* ticket = data_blob_talloc ( ctx , NULL , data_remaining ) ;
2008-10-22 19:23:49 +02:00
asn1_read ( data , ticket - > data , ticket - > length ) ;
2002-02-15 23:11:13 +00:00
}
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
2001-10-18 10:26:06 +00:00
2008-10-22 19:23:49 +02:00
ret = ! data - > has_error ;
2001-10-18 10:26:06 +00:00
2008-10-22 19:23:49 +02:00
if ( data - > has_error ) {
2006-06-16 22:25:17 +00:00
data_blob_free ( ticket ) ;
}
2008-10-22 19:23:49 +02:00
asn1_free ( data ) ;
2001-10-18 10:26:06 +00:00
return ret ;
}
2001-10-12 04:49:42 +00:00
/*
2010-07-20 11:14:49 -07:00
generate a SPNEGO krb5 negTokenInit packet , ready for a EXTENDED_SECURITY
kerberos session setup
2001-10-12 04:49:42 +00:00
*/
2010-07-20 14:59:31 -07:00
int spnego_gen_krb5_negTokenInit ( TALLOC_CTX * ctx ,
const char * principal , int time_offset ,
DATA_BLOB * targ ,
2007-02-08 17:02:39 +00:00
DATA_BLOB * session_key_krb5 , uint32 extra_ap_opts ,
time_t * expire_time )
2001-10-12 04:49:42 +00:00
{
2004-01-08 08:19:18 +00:00
int retval ;
DATA_BLOB tkt , tkt_wrapped ;
2007-04-05 12:36:10 +00:00
const char * krb_mechs [ ] = { OID_KERBEROS5_OLD , OID_KERBEROS5 , OID_NTLMSSP , NULL } ;
2001-10-12 04:49:42 +00:00
2003-07-25 23:15:30 +00:00
/* get a kerberos ticket for the service and extract the session key */
2010-07-20 20:00:12 -04:00
retval = cli_krb5_get_ticket ( ctx , principal , time_offset ,
& tkt , session_key_krb5 ,
extra_ap_opts , NULL ,
expire_time , NULL ) ;
if ( retval ) {
2004-01-08 08:19:18 +00:00
return retval ;
2010-07-20 20:00:12 -04:00
}
2003-08-13 20:27:18 +00:00
2001-10-12 04:49:42 +00:00
/* wrap that up in a nice GSS-API wrapping */
2010-07-20 16:17:58 -07:00
tkt_wrapped = spnego_gen_krb5_wrap ( ctx , tkt , TOK_ID_KRB_AP_REQ ) ;
2001-10-12 04:49:42 +00:00
/* and wrap that in a shiny SPNEGO wrapper */
2010-07-20 14:59:31 -07:00
* targ = spnego_gen_negTokenInit ( ctx , krb_mechs , & tkt_wrapped , NULL ) ;
2001-10-12 04:49:42 +00:00
2001-10-17 08:54:19 +00:00
data_blob_free ( & tkt_wrapped ) ;
data_blob_free ( & tkt ) ;
2001-10-12 04:49:42 +00:00
2004-01-08 08:19:18 +00:00
return retval ;
2001-10-12 04:49:42 +00:00
}
/*
parse a spnego NTLMSSP challenge packet giving two security blobs
*/
2010-07-20 16:17:58 -07:00
bool spnego_parse_challenge ( TALLOC_CTX * ctx , const DATA_BLOB blob ,
2001-10-12 04:49:42 +00:00
DATA_BLOB * chal1 , DATA_BLOB * chal2 )
{
2007-10-18 17:40:25 -07:00
bool ret ;
2008-10-22 19:23:49 +02:00
ASN1_DATA * data ;
2001-10-12 04:49:42 +00:00
2001-10-14 06:14:11 +00:00
ZERO_STRUCTP ( chal1 ) ;
ZERO_STRUCTP ( chal2 ) ;
2008-10-22 19:23:49 +02:00
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
return false ;
}
asn1_load ( data , blob ) ;
asn1_start_tag ( data , ASN1_CONTEXT ( 1 ) ) ;
asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_start_tag ( data , ASN1_CONTEXT ( 0 ) ) ;
asn1_check_enumerated ( data , 1 ) ;
asn1_end_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_start_tag ( data , ASN1_CONTEXT ( 1 ) ) ;
asn1_check_OID ( data , OID_NTLMSSP ) ;
asn1_end_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_start_tag ( data , ASN1_CONTEXT ( 2 ) ) ;
2010-07-20 16:17:58 -07:00
asn1_read_OctetString ( data , ctx , chal1 ) ;
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2001-10-14 06:14:11 +00:00
/* the second challenge is optional (XP doesn't send it) */
2008-10-22 19:23:49 +02:00
if ( asn1_tag_remaining ( data ) ) {
asn1_start_tag ( data , ASN1_CONTEXT ( 3 ) ) ;
2010-07-20 16:17:58 -07:00
asn1_read_OctetString ( data , ctx , chal2 ) ;
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
2001-10-14 06:14:11 +00:00
}
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
asn1_end_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
ret = ! data - > has_error ;
2006-06-16 22:25:17 +00:00
2008-10-22 19:23:49 +02:00
if ( data - > has_error ) {
2006-06-16 22:25:17 +00:00
data_blob_free ( chal1 ) ;
data_blob_free ( chal2 ) ;
}
2008-10-22 19:23:49 +02:00
asn1_free ( data ) ;
2001-10-12 04:49:42 +00:00
return ret ;
}
2001-10-17 08:54:19 +00:00
2001-10-12 04:49:42 +00:00
/*
2003-02-19 12:31:16 +00:00
generate a SPNEGO auth packet . This will contain the encrypted passwords
2001-10-12 04:49:42 +00:00
*/
2010-07-20 16:17:58 -07:00
DATA_BLOB spnego_gen_auth ( TALLOC_CTX * ctx , DATA_BLOB blob )
2001-10-12 04:49:42 +00:00
{
2008-10-22 19:23:49 +02:00
ASN1_DATA * data ;
2001-10-12 04:49:42 +00:00
DATA_BLOB ret ;
2008-10-22 19:23:49 +02:00
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
return data_blob_null ;
}
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_push_tag ( data , ASN1_CONTEXT ( 1 ) ) ;
asn1_push_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_push_tag ( data , ASN1_CONTEXT ( 2 ) ) ;
asn1_write_OctetString ( data , blob . data , blob . length ) ;
asn1_pop_tag ( data ) ;
asn1_pop_tag ( data ) ;
asn1_pop_tag ( data ) ;
2001-10-12 04:49:42 +00:00
2010-07-20 16:17:58 -07:00
ret = data_blob_talloc ( ctx , data - > data , data - > length ) ;
2001-10-12 04:49:42 +00:00
2008-10-22 19:23:49 +02:00
asn1_free ( data ) ;
2001-10-12 04:49:42 +00:00
return ret ;
2001-10-17 08:54:19 +00:00
}
/*
2003-02-19 12:31:16 +00:00
parse a SPNEGO auth packet . This contains the encrypted passwords
2001-10-17 08:54:19 +00:00
*/
2010-08-31 15:08:31 -04:00
bool spnego_parse_auth_and_mic ( TALLOC_CTX * ctx , DATA_BLOB blob ,
DATA_BLOB * auth , DATA_BLOB * signature )
2001-10-17 08:54:19 +00:00
{
2009-10-15 14:13:26 +02:00
ssize_t len ;
struct spnego_data token ;
2008-10-22 19:23:49 +02:00
2009-10-15 14:13:26 +02:00
len = spnego_read_data ( talloc_tos ( ) , blob , & token ) ;
if ( len = = - 1 ) {
DEBUG ( 3 , ( " spnego_parse_auth: spnego_read_data failed \n " ) ) ;
2008-10-22 19:23:49 +02:00
return false ;
}
2009-10-15 14:13:26 +02:00
if ( token . type ! = SPNEGO_NEG_TOKEN_TARG ) {
DEBUG ( 3 , ( " spnego_parse_auth: wrong token type: %d \n " ,
token . type ) ) ;
2009-10-15 15:45:20 +02:00
spnego_free_data ( & token ) ;
2009-10-15 14:13:26 +02:00
return false ;
2001-10-17 08:54:19 +00:00
}
2010-07-20 16:17:58 -07:00
* auth = data_blob_talloc ( ctx ,
2009-10-15 15:45:20 +02:00
token . negTokenTarg . responseToken . data ,
token . negTokenTarg . responseToken . length ) ;
2010-08-31 15:08:31 -04:00
if ( ! signature ) {
goto done ;
}
* signature = data_blob_talloc ( ctx ,
token . negTokenTarg . mechListMIC . data ,
token . negTokenTarg . mechListMIC . length ) ;
done :
2009-10-15 15:45:20 +02:00
spnego_free_data ( & token ) ;
2009-10-15 14:13:26 +02:00
return true ;
2001-10-12 04:49:42 +00:00
}
2010-08-31 15:08:31 -04:00
bool spnego_parse_auth ( TALLOC_CTX * ctx , DATA_BLOB blob , DATA_BLOB * auth )
{
return spnego_parse_auth_and_mic ( ctx , blob , auth , NULL ) ;
}
2002-08-17 17:00:51 +00:00
/*
2003-03-17 22:45:16 +00:00
generate a minimal SPNEGO response packet . Doesn ' t contain much .
2002-08-17 17:00:51 +00:00
*/
2010-08-31 15:08:31 -04:00
DATA_BLOB spnego_gen_auth_response_and_mic ( TALLOC_CTX * ctx ,
NTSTATUS nt_status ,
const char * mechOID ,
DATA_BLOB * reply ,
DATA_BLOB * mechlistMIC )
2002-08-17 17:00:51 +00:00
{
2008-10-22 19:23:49 +02:00
ASN1_DATA * data ;
2002-08-17 17:00:51 +00:00
DATA_BLOB ret ;
2003-01-28 12:07:02 +00:00
uint8 negResult ;
2002-08-17 17:00:51 +00:00
2003-01-28 12:07:02 +00:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
2009-09-17 00:21:01 +02:00
negResult = SPNEGO_ACCEPT_COMPLETED ;
2003-01-28 12:07:02 +00:00
} else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
2009-09-17 00:21:01 +02:00
negResult = SPNEGO_ACCEPT_INCOMPLETE ;
2003-01-28 12:07:02 +00:00
} else {
2009-09-17 00:21:01 +02:00
negResult = SPNEGO_REJECT ;
2003-01-28 12:07:02 +00:00
}
2008-10-22 19:23:49 +02:00
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
return data_blob_null ;
}
2002-08-17 17:00:51 +00:00
2008-10-22 19:23:49 +02:00
asn1_push_tag ( data , ASN1_CONTEXT ( 1 ) ) ;
asn1_push_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_push_tag ( data , ASN1_CONTEXT ( 0 ) ) ;
asn1_write_enumerated ( data , negResult ) ;
asn1_pop_tag ( data ) ;
2003-02-19 12:31:16 +00:00
2008-02-14 11:29:54 -08:00
if ( mechOID ) {
2008-10-22 19:23:49 +02:00
asn1_push_tag ( data , ASN1_CONTEXT ( 1 ) ) ;
asn1_write_OID ( data , mechOID ) ;
asn1_pop_tag ( data ) ;
2008-02-14 11:29:54 -08:00
}
if ( reply & & reply - > data ! = NULL ) {
2008-10-22 19:23:49 +02:00
asn1_push_tag ( data , ASN1_CONTEXT ( 2 ) ) ;
asn1_write_OctetString ( data , reply - > data , reply - > length ) ;
asn1_pop_tag ( data ) ;
2003-01-28 12:07:02 +00:00
}
2010-08-31 15:08:31 -04:00
if ( mechlistMIC & & mechlistMIC - > data ! = NULL ) {
asn1_push_tag ( data , ASN1_CONTEXT ( 3 ) ) ;
asn1_write_OctetString ( data ,
mechlistMIC - > data ,
mechlistMIC - > length ) ;
asn1_pop_tag ( data ) ;
}
2008-10-22 19:23:49 +02:00
asn1_pop_tag ( data ) ;
asn1_pop_tag ( data ) ;
2002-08-17 17:00:51 +00:00
2010-07-20 16:17:58 -07:00
ret = data_blob_talloc ( ctx , data - > data , data - > length ) ;
2008-10-22 19:23:49 +02:00
asn1_free ( data ) ;
2002-08-17 17:00:51 +00:00
return ret ;
}
2001-10-12 04:49:42 +00:00
2010-08-31 15:08:31 -04:00
DATA_BLOB spnego_gen_auth_response ( TALLOC_CTX * ctx , DATA_BLOB * reply ,
NTSTATUS nt_status , const char * mechOID )
{
return spnego_gen_auth_response_and_mic ( ctx , nt_status ,
mechOID , reply , NULL ) ;
}
2001-10-12 04:49:42 +00:00
/*
2007-04-05 12:30:23 +00:00
parse a SPNEGO auth packet . This contains the encrypted passwords
2003-02-24 02:55:00 +00:00
*/
2010-07-20 16:17:58 -07:00
bool spnego_parse_auth_response ( TALLOC_CTX * ctx ,
DATA_BLOB blob , NTSTATUS nt_status ,
2007-04-05 12:30:23 +00:00
const char * mechOID ,
2003-02-24 02:55:00 +00:00
DATA_BLOB * auth )
2001-10-12 04:49:42 +00:00
{
2008-10-22 19:23:49 +02:00
ASN1_DATA * data ;
2003-02-24 02:55:00 +00:00
uint8 negResult ;
2001-10-12 04:49:42 +00:00
2003-02-24 02:55:00 +00:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
2009-09-17 00:21:01 +02:00
negResult = SPNEGO_ACCEPT_COMPLETED ;
2003-02-24 02:55:00 +00:00
} else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
2009-09-17 00:21:01 +02:00
negResult = SPNEGO_ACCEPT_INCOMPLETE ;
2003-02-24 02:55:00 +00:00
} else {
2009-09-17 00:21:01 +02:00
negResult = SPNEGO_REJECT ;
2003-02-24 02:55:00 +00:00
}
2001-10-17 08:54:19 +00:00
2008-10-22 19:23:49 +02:00
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
return false ;
}
asn1_load ( data , blob ) ;
asn1_start_tag ( data , ASN1_CONTEXT ( 1 ) ) ;
asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
asn1_start_tag ( data , ASN1_CONTEXT ( 0 ) ) ;
asn1_check_enumerated ( data , negResult ) ;
asn1_end_tag ( data ) ;
2001-10-17 08:54:19 +00:00
2007-05-14 12:16:20 +00:00
* auth = data_blob_null ;
2007-04-05 12:30:23 +00:00
2008-10-22 19:23:49 +02:00
if ( asn1_tag_remaining ( data ) ) {
asn1_start_tag ( data , ASN1_CONTEXT ( 1 ) ) ;
asn1_check_OID ( data , mechOID ) ;
asn1_end_tag ( data ) ;
2007-04-05 12:30:23 +00:00
2008-10-22 19:23:49 +02:00
if ( asn1_tag_remaining ( data ) ) {
asn1_start_tag ( data , ASN1_CONTEXT ( 2 ) ) ;
2010-07-20 16:17:58 -07:00
asn1_read_OctetString ( data , ctx , auth ) ;
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
2007-04-05 12:30:23 +00:00
}
2009-09-17 00:21:01 +02:00
} else if ( negResult = = SPNEGO_ACCEPT_INCOMPLETE ) {
2008-10-22 19:23:49 +02:00
data - > has_error = 1 ;
2001-10-17 08:54:19 +00:00
}
2007-09-19 14:33:32 +00:00
/* Binding against Win2K DC returns a duplicate of the responseToken in
* the optional mechListMIC field . This is a bug in Win2K . We ignore
* this field if it exists . Win2K8 may return a proper mechListMIC at
* which point we need to implement the integrity checking . */
2008-10-22 19:23:49 +02:00
if ( asn1_tag_remaining ( data ) ) {
2007-09-19 14:33:32 +00:00
DATA_BLOB mechList = data_blob_null ;
2008-10-22 19:23:49 +02:00
asn1_start_tag ( data , ASN1_CONTEXT ( 3 ) ) ;
2010-07-20 16:17:58 -07:00
asn1_read_OctetString ( data , ctx , & mechList ) ;
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
2007-09-19 14:33:32 +00:00
data_blob_free ( & mechList ) ;
DEBUG ( 5 , ( " spnego_parse_auth_response received mechListMIC, "
" ignoring. \n " ) ) ;
}
2008-10-22 19:23:49 +02:00
asn1_end_tag ( data ) ;
asn1_end_tag ( data ) ;
2002-07-15 10:35:28 +00:00
2008-10-22 19:23:49 +02:00
if ( data - > has_error ) {
DEBUG ( 3 , ( " spnego_parse_auth_response failed at %d \n " , ( int ) data - > ofs ) ) ;
asn1_free ( data ) ;
2003-02-24 02:55:00 +00:00
data_blob_free ( auth ) ;
return False ;
}
2002-07-15 10:35:28 +00:00
2008-10-22 19:23:49 +02:00
asn1_free ( data ) ;
2003-02-24 02:55:00 +00:00
return True ;
2002-07-15 10:35:28 +00:00
}
2010-08-31 15:08:31 -04:00
bool spnego_mech_list_blob ( TALLOC_CTX * mem_ctx ,
char * * oid_list , DATA_BLOB * raw_data )
{
ASN1_DATA * data ;
unsigned int idx ;
if ( ! oid_list | | ! oid_list [ 0 ] | | ! raw_data ) {
return false ;
}
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
return false ;
}
asn1_push_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
for ( idx = 0 ; oid_list [ idx ] ; idx + + ) {
asn1_write_OID ( data , oid_list [ idx ] ) ;
}
asn1_pop_tag ( data ) ;
if ( data - > has_error ) {
DEBUG ( 3 , ( __location__ " failed at %d \n " , ( int ) data - > ofs ) ) ;
asn1_free ( data ) ;
return false ;
}
* raw_data = data_blob_talloc ( mem_ctx , data - > data , data - > length ) ;
if ( ! raw_data - > data ) {
DEBUG ( 3 , ( __location__ " : data_blob_talloc() failed! \n " ) ) ;
asn1_free ( data ) ;
return false ;
}
asn1_free ( data ) ;
return true ;
}