2001-10-12 08:49:42 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-10-12 08:49:42 +04:00
simple kerberos5 / SPNEGO routines
Copyright ( C ) Andrew Tridgell 2001
2003-08-01 19:21:20 +04:00
Copyright ( C ) Jim McDonough < jmcd @ us . ibm . com > 2002
2003-03-18 01:45:16 +03:00
Copyright ( C ) Luke Howard 2003
2010-07-20 20:51:48 +04:00
Copyright ( C ) Jeremy Allison 2010
2001-10-12 08:49:42 +04: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 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2001-10-12 08:49:42 +04: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 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2001-10-12 08:49:42 +04:00
*/
# include "includes.h"
2009-09-17 02:21:01 +04:00
# include "../libcli/auth/spnego.h"
2009-11-27 17:52:57 +03:00
# include "smb_krb5.h"
2011-02-24 14:27:29 +03:00
# include "../lib/util/asn1.h"
2001-10-12 08:49:42 +04:00
/*
parse a negTokenInit packet giving a GUID , a list of supported
2001-10-22 00:51:27 +04:00
OIDs ( the mechanisms ) and a principal name string
2001-10-12 08:49:42 +04:00
*/
2010-07-21 00:35:43 +04:00
bool spnego_parse_negTokenInit ( TALLOC_CTX * ctx ,
DATA_BLOB blob ,
2008-10-22 16:06:08 +04:00
char * OIDs [ ASN1_MAX_OIDS ] ,
2010-07-20 02:41:45 +04:00
char * * principal ,
DATA_BLOB * secblob )
2001-10-12 08:49:42 +04:00
{
int i ;
2014-09-20 01:27:58 +04:00
bool ret = false ;
2008-10-22 21:23:49 +04:00
ASN1_DATA * data ;
2012-09-26 03:35:09 +04:00
for ( i = 0 ; i < ASN1_MAX_OIDS ; i + + ) {
OIDs [ i ] = NULL ;
}
2014-09-20 01:27:58 +04:00
if ( principal ) {
* principal = NULL ;
}
if ( secblob ) {
* secblob = data_blob_null ;
}
2020-04-03 02:18:03 +03:00
data = asn1_init ( talloc_tos ( ) , ASN1_MAX_TREE_DEPTH ) ;
2008-10-22 21:23:49 +04:00
if ( data = = NULL ) {
return false ;
}
2014-09-20 01:27:58 +04:00
if ( ! asn1_load ( data , blob ) ) goto err ;
2001-10-12 08:49:42 +04:00
2014-09-20 01:27:58 +04:00
if ( ! asn1_start_tag ( data , ASN1_APPLICATION ( 0 ) ) ) goto err ;
2001-10-12 08:49:42 +04:00
2014-09-20 01:27:58 +04:00
if ( ! asn1_check_OID ( data , OID_SPNEGO ) ) goto err ;
2010-07-20 01:21:01 +04:00
/* negTokenInit [0] NegTokenInit */
2014-09-20 01:27:58 +04:00
if ( ! asn1_start_tag ( data , ASN1_CONTEXT ( 0 ) ) ) goto err ;
if ( ! asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ) goto err ;
2001-10-12 08:49:42 +04:00
2010-07-20 01:21:01 +04:00
/* mechTypes [0] MechTypeList OPTIONAL */
/* Not really optional, we depend on this to decide
* what mechanisms we have to work with . */
2014-09-20 01:27:58 +04:00
if ( ! asn1_start_tag ( data , ASN1_CONTEXT ( 0 ) ) ) goto err ;
if ( ! asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ) goto err ;
2008-10-22 21:23:49 +04:00
for ( i = 0 ; asn1_tag_remaining ( data ) > 0 & & i < ASN1_MAX_OIDS - 1 ; i + + ) {
2011-09-21 05:50:00 +04:00
if ( ! asn1_read_OID ( data , ctx , & OIDs [ i ] ) ) {
2014-09-20 01:27:58 +04:00
goto err ;
2011-09-21 05:50:00 +04:00
}
2016-01-02 20:11:00 +03:00
if ( asn1_has_error ( data ) ) {
2014-09-20 01:27:58 +04:00
goto err ;
2011-09-21 05:50:00 +04:00
}
2001-10-12 08:49:42 +04:00
}
OIDs [ i ] = NULL ;
2014-09-20 01:27:58 +04:00
if ( ! asn1_end_tag ( data ) ) goto err ;
if ( ! asn1_end_tag ( data ) ) goto err ;
2010-07-20 01:21:01 +04: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 20:51:48 +04:00
if ( asn1_peek_tag ( data , ASN1_CONTEXT ( 1 ) ) ) {
2015-04-25 05:22:21 +03:00
uint8_t flags ;
2010-07-20 20:51:48 +04:00
/* reqFlags [1] ContextFlags OPTIONAL */
2014-09-20 01:27:58 +04:00
if ( ! asn1_start_tag ( data , ASN1_CONTEXT ( 1 ) ) ) goto err ;
if ( ! asn1_start_tag ( data , ASN1_BIT_STRING ) ) goto err ;
2010-07-20 20:51:48 +04:00
while ( asn1_tag_remaining ( data ) > 0 ) {
2014-09-20 01:27:58 +04:00
if ( ! asn1_read_uint8 ( data , & flags ) ) goto err ;
2010-07-20 01:21:01 +04:00
}
2014-09-20 01:27:58 +04:00
if ( ! asn1_end_tag ( data ) ) goto err ;
if ( ! asn1_end_tag ( data ) ) goto err ;
2010-07-20 01:21:01 +04:00
}
2010-07-20 20:51:48 +04:00
if ( asn1_peek_tag ( data , ASN1_CONTEXT ( 2 ) ) ) {
DATA_BLOB sblob = data_blob_null ;
/* mechToken [2] OCTET STRING OPTIONAL */
2014-09-20 01:27:58 +04:00
if ( ! asn1_start_tag ( data , ASN1_CONTEXT ( 2 ) ) ) goto err ;
if ( ! asn1_read_OctetString ( data , ctx , & sblob ) ) goto err ;
if ( ! asn1_end_tag ( data ) ) {
data_blob_free ( & sblob ) ;
goto err ;
}
2010-07-20 20:51:48 +04:00
if ( secblob ) {
* secblob = sblob ;
} else {
data_blob_free ( & sblob ) ;
2010-07-20 01:21:01 +04:00
}
}
2010-07-20 20:51:48 +04:00
if ( asn1_peek_tag ( data , ASN1_CONTEXT ( 3 ) ) ) {
char * princ = NULL ;
/* mechListMIC [3] OCTET STRING OPTIONAL */
2014-09-20 01:27:58 +04:00
if ( ! asn1_start_tag ( data , ASN1_CONTEXT ( 3 ) ) ) goto err ;
if ( ! asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ) goto err ;
if ( ! asn1_start_tag ( data , ASN1_CONTEXT ( 0 ) ) ) goto err ;
if ( ! asn1_read_GeneralString ( data , ctx , & princ ) ) goto err ;
if ( ! asn1_end_tag ( data ) ) goto err ;
if ( ! asn1_end_tag ( data ) ) goto err ;
if ( ! asn1_end_tag ( data ) ) goto err ;
2010-07-20 20:51:48 +04:00
if ( principal ) {
* principal = princ ;
} else {
TALLOC_FREE ( princ ) ;
2010-07-20 01:21:01 +04:00
}
2006-10-02 16:54:49 +04:00
}
2001-10-12 08:49:42 +04:00
2014-09-20 01:27:58 +04:00
if ( ! asn1_end_tag ( data ) ) goto err ;
if ( ! asn1_end_tag ( data ) ) goto err ;
2001-10-12 08:49:42 +04:00
2014-09-20 01:27:58 +04:00
if ( ! asn1_end_tag ( data ) ) goto err ;
2001-10-12 08:49:42 +04:00
2016-01-02 20:11:00 +03:00
ret = ! asn1_has_error ( data ) ;
2014-09-20 01:27:58 +04:00
err :
2016-01-02 20:11:00 +03:00
if ( asn1_has_error ( data ) ) {
2006-06-17 02:25:17 +04:00
int j ;
2010-07-20 02:41:45 +04:00
if ( principal ) {
TALLOC_FREE ( * principal ) ;
}
if ( secblob ) {
data_blob_free ( secblob ) ;
}
2006-06-17 02:25:17 +04:00
for ( j = 0 ; j < i & & j < ASN1_MAX_OIDS - 1 ; j + + ) {
2008-10-22 16:06:08 +04:00
TALLOC_FREE ( OIDs [ j ] ) ;
2006-06-17 02:25:17 +04:00
}
}
2008-10-22 21:23:49 +04:00
asn1_free ( data ) ;
2001-10-12 08:49:42 +04:00
return ret ;
}
/*
generate a krb5 GSS - API wrapper packet given a ticket
*/
2015-04-25 05:22:21 +03:00
DATA_BLOB spnego_gen_krb5_wrap ( TALLOC_CTX * ctx , const DATA_BLOB ticket , const uint8_t tok_id [ 2 ] )
2001-10-12 08:49:42 +04:00
{
2008-10-22 21:23:49 +04:00
ASN1_DATA * data ;
2014-09-20 01:27:58 +04:00
DATA_BLOB ret = data_blob_null ;
2001-10-12 08:49:42 +04:00
2020-04-03 02:18:03 +03:00
data = asn1_init ( talloc_tos ( ) , ASN1_MAX_TREE_DEPTH ) ;
2008-10-22 21:23:49 +04:00
if ( data = = NULL ) {
return data_blob_null ;
}
2001-10-12 08:49:42 +04:00
2014-09-20 01:27:58 +04:00
if ( ! asn1_push_tag ( data , ASN1_APPLICATION ( 0 ) ) ) goto err ;
if ( ! asn1_write_OID ( data , OID_KERBEROS5 ) ) goto err ;
2003-03-18 01:45:16 +03:00
2014-09-20 01:27:58 +04:00
if ( ! asn1_write ( data , tok_id , 2 ) ) goto err ;
if ( ! asn1_write ( data , ticket . data , ticket . length ) ) goto err ;
if ( ! asn1_pop_tag ( data ) ) goto err ;
2016-01-02 22:10:53 +03:00
if ( ! asn1_extract_blob ( data , ctx , & ret ) ) {
goto err ;
}
2014-09-20 01:27:58 +04:00
2016-01-28 17:50:06 +03:00
asn1_free ( data ) ;
data = NULL ;
2014-09-20 01:27:58 +04:00
err :
2001-10-12 08:49:42 +04:00
2016-01-28 17:50:06 +03:00
if ( data ! = NULL ) {
if ( asn1_has_error ( data ) ) {
DEBUG ( 1 , ( " Failed to build krb5 wrapper at offset %d \n " ,
( int ) asn1_current_ofs ( data ) ) ) ;
}
2001-10-12 08:49:42 +04:00
2016-01-28 17:50:06 +03:00
asn1_free ( data ) ;
}
2001-10-12 08:49:42 +04:00
return ret ;
}