root/source3/libsmb/spnego.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_negTokenInit
  2. write_negTokenInit
  3. read_negTokenTarg
  4. write_negTokenTarg
  5. read_spnego_data
  6. write_spnego_data
  7. free_spnego_data

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    RFC2478 Compliant SPNEGO implementation
   5 
   6    Copyright (C) Jim McDonough <jmcd@us.ibm.com>   2003
   7 
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12    
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17 
  18    
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 
  25 #undef DBGC_CLASS
  26 #define DBGC_CLASS DBGC_AUTH
  27 
  28 static bool read_negTokenInit(TALLOC_CTX *mem_ctx, ASN1_DATA *asn1, negTokenInit_t *token)
     /* [<][>][^][v][top][bottom][index][help] */
  29 {
  30         ZERO_STRUCTP(token);
  31 
  32         asn1_start_tag(asn1, ASN1_CONTEXT(0));
  33         asn1_start_tag(asn1, ASN1_SEQUENCE(0));
  34 
  35         while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
  36                 int i;
  37 
  38                 switch (asn1->data[asn1->ofs]) {
  39                 /* Read mechTypes */
  40                 case ASN1_CONTEXT(0):
  41                         asn1_start_tag(asn1, ASN1_CONTEXT(0));
  42                         asn1_start_tag(asn1, ASN1_SEQUENCE(0));
  43 
  44                         token->mechTypes = TALLOC_P(mem_ctx, const char *);
  45                         for (i = 0; !asn1->has_error &&
  46                                      0 < asn1_tag_remaining(asn1); i++) {
  47                                 const char *p_oid = NULL;
  48                                 token->mechTypes = 
  49                                         TALLOC_REALLOC_ARRAY(mem_ctx, token->mechTypes, const char *, i + 2);
  50                                 if (!token->mechTypes) {
  51                                         asn1->has_error = True;
  52                                         return False;
  53                                 }
  54                                 asn1_read_OID(asn1, mem_ctx, &p_oid);
  55                                 token->mechTypes[i] = p_oid;
  56                         }
  57                         token->mechTypes[i] = NULL;
  58                         
  59                         asn1_end_tag(asn1);
  60                         asn1_end_tag(asn1);
  61                         break;
  62                 /* Read reqFlags */
  63                 case ASN1_CONTEXT(1):
  64                         asn1_start_tag(asn1, ASN1_CONTEXT(1));
  65                         asn1_read_Integer(asn1, &token->reqFlags);
  66                         token->reqFlags |= SPNEGO_REQ_FLAG;
  67                         asn1_end_tag(asn1);
  68                         break;
  69                 /* Read mechToken */
  70                 case ASN1_CONTEXT(2):
  71                         asn1_start_tag(asn1, ASN1_CONTEXT(2));
  72                         asn1_read_OctetString(asn1, mem_ctx, &token->mechToken);
  73                         asn1_end_tag(asn1);
  74                         break;
  75                 /* Read mecListMIC */
  76                 case ASN1_CONTEXT(3):
  77                         asn1_start_tag(asn1, ASN1_CONTEXT(3));
  78                         if (asn1->data[asn1->ofs] == ASN1_OCTET_STRING) {
  79                                 asn1_read_OctetString(asn1, mem_ctx,
  80                                                       &token->mechListMIC);
  81                         } else {
  82                                 /* RFC 2478 says we have an Octet String here,
  83                                    but W2k sends something different... */
  84                                 char *mechListMIC;
  85                                 asn1_push_tag(asn1, ASN1_SEQUENCE(0));
  86                                 asn1_push_tag(asn1, ASN1_CONTEXT(0));
  87                                 asn1_read_GeneralString(asn1, mem_ctx, &mechListMIC);
  88                                 asn1_pop_tag(asn1);
  89                                 asn1_pop_tag(asn1);
  90 
  91                                 token->mechListMIC =
  92                                         data_blob(mechListMIC, strlen(mechListMIC));
  93                                 TALLOC_FREE(mechListMIC);
  94                         }
  95                         asn1_end_tag(asn1);
  96                         break;
  97                 default:
  98                         asn1->has_error = True;
  99                         break;
 100                 }
 101         }
 102 
 103         asn1_end_tag(asn1);
 104         asn1_end_tag(asn1);
 105 
 106         return !asn1->has_error;
 107 }
 108 
 109 static bool write_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
     /* [<][>][^][v][top][bottom][index][help] */
 110 {
 111         asn1_push_tag(asn1, ASN1_CONTEXT(0));
 112         asn1_push_tag(asn1, ASN1_SEQUENCE(0));
 113 
 114         /* Write mechTypes */
 115         if (token->mechTypes && *token->mechTypes) {
 116                 int i;
 117 
 118                 asn1_push_tag(asn1, ASN1_CONTEXT(0));
 119                 asn1_push_tag(asn1, ASN1_SEQUENCE(0));
 120                 for (i = 0; token->mechTypes[i]; i++) {
 121                         asn1_write_OID(asn1, token->mechTypes[i]);
 122                 }
 123                 asn1_pop_tag(asn1);
 124                 asn1_pop_tag(asn1);
 125         }
 126 
 127         /* write reqFlags */
 128         if (token->reqFlags & SPNEGO_REQ_FLAG) {
 129                 int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
 130 
 131                 asn1_push_tag(asn1, ASN1_CONTEXT(1));
 132                 asn1_write_Integer(asn1, flags);
 133                 asn1_pop_tag(asn1);
 134         }
 135 
 136         /* write mechToken */
 137         if (token->mechToken.data) {
 138                 asn1_push_tag(asn1, ASN1_CONTEXT(2));
 139                 asn1_write_OctetString(asn1, token->mechToken.data,
 140                                        token->mechToken.length);
 141                 asn1_pop_tag(asn1);
 142         }
 143 
 144         /* write mechListMIC */
 145         if (token->mechListMIC.data) {
 146                 asn1_push_tag(asn1, ASN1_CONTEXT(3));
 147 #if 0
 148                 /* This is what RFC 2478 says ... */
 149                 asn1_write_OctetString(asn1, token->mechListMIC.data,
 150                                        token->mechListMIC.length);
 151 #else
 152                 /* ... but unfortunately this is what Windows
 153                    sends/expects */
 154                 asn1_push_tag(asn1, ASN1_SEQUENCE(0));
 155                 asn1_push_tag(asn1, ASN1_CONTEXT(0));
 156                 asn1_push_tag(asn1, ASN1_GENERAL_STRING);
 157                 asn1_write(asn1, token->mechListMIC.data,
 158                            token->mechListMIC.length);
 159                 asn1_pop_tag(asn1);
 160                 asn1_pop_tag(asn1);
 161                 asn1_pop_tag(asn1);
 162 #endif          
 163                 asn1_pop_tag(asn1);
 164         }
 165 
 166         asn1_pop_tag(asn1);
 167         asn1_pop_tag(asn1);
 168 
 169         return !asn1->has_error;
 170 }
 171 
 172 static bool read_negTokenTarg(TALLOC_CTX *mem_ctx, ASN1_DATA *asn1, negTokenTarg_t *token)
     /* [<][>][^][v][top][bottom][index][help] */
 173 {
 174         ZERO_STRUCTP(token);
 175 
 176         asn1_start_tag(asn1, ASN1_CONTEXT(1));
 177         asn1_start_tag(asn1, ASN1_SEQUENCE(0));
 178 
 179         while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
 180                 switch (asn1->data[asn1->ofs]) {
 181                 case ASN1_CONTEXT(0):
 182                         asn1_start_tag(asn1, ASN1_CONTEXT(0));
 183                         asn1_start_tag(asn1, ASN1_ENUMERATED);
 184                         asn1_read_uint8(asn1, &token->negResult);
 185                         asn1_end_tag(asn1);
 186                         asn1_end_tag(asn1);
 187                         break;
 188                 case ASN1_CONTEXT(1): {
 189                         const char *mech = NULL;
 190                         asn1_start_tag(asn1, ASN1_CONTEXT(1));
 191                         asn1_read_OID(asn1, mem_ctx, &mech);
 192                         asn1_end_tag(asn1);
 193                         token->supportedMech = CONST_DISCARD(char *, mech);
 194                         }
 195                         break;
 196                 case ASN1_CONTEXT(2):
 197                         asn1_start_tag(asn1, ASN1_CONTEXT(2));
 198                         asn1_read_OctetString(asn1, mem_ctx, &token->responseToken);
 199                         asn1_end_tag(asn1);
 200                         break;
 201                 case ASN1_CONTEXT(3):
 202                         asn1_start_tag(asn1, ASN1_CONTEXT(3));
 203                         asn1_read_OctetString(asn1, mem_ctx, &token->mechListMIC);
 204                         asn1_end_tag(asn1);
 205                         break;
 206                 default:
 207                         asn1->has_error = True;
 208                         break;
 209                 }
 210         }
 211 
 212         asn1_end_tag(asn1);
 213         asn1_end_tag(asn1);
 214 
 215         return !asn1->has_error;
 216 }
 217 
 218 static bool write_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
     /* [<][>][^][v][top][bottom][index][help] */
 219 {
 220         asn1_push_tag(asn1, ASN1_CONTEXT(1));
 221         asn1_push_tag(asn1, ASN1_SEQUENCE(0));
 222 
 223         asn1_push_tag(asn1, ASN1_CONTEXT(0));
 224         asn1_write_enumerated(asn1, token->negResult);
 225         asn1_pop_tag(asn1);
 226 
 227         if (token->supportedMech) {
 228                 asn1_push_tag(asn1, ASN1_CONTEXT(1));
 229                 asn1_write_OID(asn1, token->supportedMech);
 230                 asn1_pop_tag(asn1);
 231         }
 232 
 233         if (token->responseToken.data) {
 234                 asn1_push_tag(asn1, ASN1_CONTEXT(2));
 235                 asn1_write_OctetString(asn1, token->responseToken.data,
 236                                        token->responseToken.length);
 237                 asn1_pop_tag(asn1);
 238         }
 239 
 240         if (token->mechListMIC.data) {
 241                 asn1_push_tag(asn1, ASN1_CONTEXT(3));
 242                 asn1_write_OctetString(asn1, token->mechListMIC.data,
 243                                       token->mechListMIC.length);
 244                 asn1_pop_tag(asn1);
 245         }
 246 
 247         asn1_pop_tag(asn1);
 248         asn1_pop_tag(asn1);
 249 
 250         return !asn1->has_error;
 251 }
 252 
 253 ssize_t read_spnego_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, SPNEGO_DATA *token)
     /* [<][>][^][v][top][bottom][index][help] */
 254 {
 255         ASN1_DATA *asn1;
 256         ssize_t ret = -1;
 257 
 258         ZERO_STRUCTP(token);
 259 
 260         asn1 = asn1_init(mem_ctx);
 261         if (asn1 == NULL) {
 262                 return -1;
 263         }
 264 
 265         asn1_load(asn1, data);
 266 
 267         switch (asn1->data[asn1->ofs]) {
 268         case ASN1_APPLICATION(0):
 269                 asn1_start_tag(asn1, ASN1_APPLICATION(0));
 270                 asn1_check_OID(asn1, OID_SPNEGO);
 271                 if (read_negTokenInit(mem_ctx, asn1, &token->negTokenInit)) {
 272                         token->type = SPNEGO_NEG_TOKEN_INIT;
 273                 }
 274                 asn1_end_tag(asn1);
 275                 break;
 276         case ASN1_CONTEXT(1):
 277                 if (read_negTokenTarg(mem_ctx, asn1, &token->negTokenTarg)) {
 278                         token->type = SPNEGO_NEG_TOKEN_TARG;
 279                 }
 280                 break;
 281         default:
 282                 break;
 283         }
 284 
 285         if (!asn1->has_error) ret = asn1->ofs;
 286         asn1_free(asn1);
 287 
 288         return ret;
 289 }
 290 
 291 ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego)
     /* [<][>][^][v][top][bottom][index][help] */
 292 {
 293         ASN1_DATA *asn1;
 294         ssize_t ret = -1;
 295 
 296         asn1 = asn1_init(talloc_tos());
 297         if (asn1 == NULL) {
 298                 return -1;
 299         }
 300 
 301         switch (spnego->type) {
 302         case SPNEGO_NEG_TOKEN_INIT:
 303                 asn1_push_tag(asn1, ASN1_APPLICATION(0));
 304                 asn1_write_OID(asn1, OID_SPNEGO);
 305                 write_negTokenInit(asn1, &spnego->negTokenInit);
 306                 asn1_pop_tag(asn1);
 307                 break;
 308         case SPNEGO_NEG_TOKEN_TARG:
 309                 write_negTokenTarg(asn1, &spnego->negTokenTarg);
 310                 break;
 311         default:
 312                 asn1->has_error = True;
 313                 break;
 314         }
 315 
 316         if (!asn1->has_error) {
 317                 *blob = data_blob(asn1->data, asn1->length);
 318                 ret = asn1->ofs;
 319         }
 320         asn1_free(asn1);
 321 
 322         return ret;
 323 }
 324 
 325 bool free_spnego_data(SPNEGO_DATA *spnego)
     /* [<][>][^][v][top][bottom][index][help] */
 326 {
 327         bool ret = True;
 328 
 329         if (!spnego) goto out;
 330 
 331         switch(spnego->type) {
 332         case SPNEGO_NEG_TOKEN_INIT:
 333                 if (spnego->negTokenInit.mechTypes) {
 334                         int i;
 335                         for (i = 0; spnego->negTokenInit.mechTypes[i]; i++) {
 336                                 talloc_free(CONST_DISCARD(char *,spnego->negTokenInit.mechTypes[i]));
 337                         }
 338                         talloc_free(spnego->negTokenInit.mechTypes);
 339                 }
 340                 data_blob_free(&spnego->negTokenInit.mechToken);
 341                 data_blob_free(&spnego->negTokenInit.mechListMIC);
 342                 break;
 343         case SPNEGO_NEG_TOKEN_TARG:
 344                 if (spnego->negTokenTarg.supportedMech) {
 345                         talloc_free(spnego->negTokenTarg.supportedMech);
 346                 }
 347                 data_blob_free(&spnego->negTokenTarg.responseToken);
 348                 data_blob_free(&spnego->negTokenTarg.mechListMIC);
 349                 break;
 350         default:
 351                 ret = False;
 352                 break;
 353         }
 354         ZERO_STRUCTP(spnego);
 355 out:
 356         return ret;
 357 }

/* [<][>][^][v][top][bottom][index][help] */