LCOV - code coverage report
Current view: top level - libcli/auth - spnego_parse.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 191 257 74.3 %
Date: 2024-02-14 10:14:15 Functions: 7 8 87.5 %

          Line data    Source code
       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             : #include "../libcli/auth/spnego.h"
      25             : #include "../lib/util/asn1.h"
      26             : 
      27       43435 : static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
      28             :                               struct spnego_negTokenInit *token)
      29             : {
      30       43435 :         ZERO_STRUCTP(token);
      31             : 
      32       43435 :         if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
      33       43435 :         if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
      34             : 
      35      130304 :         while (asn1_tag_remaining(asn1) > 0) {
      36             :                 int i;
      37             :                 uint8_t context;
      38             : 
      39       86869 :                 if (!asn1_peek_uint8(asn1, &context)) {
      40           0 :                         asn1_set_error(asn1);
      41           0 :                         break;
      42             :                 }
      43             : 
      44       86869 :                 switch (context) {
      45             :                 /* Read mechTypes */
      46       43435 :                 case ASN1_CONTEXT(0): {
      47             :                         const char **mechTypes;
      48             : 
      49       43435 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
      50       43435 :                         if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
      51             : 
      52       43435 :                         mechTypes = talloc(mem_ctx, const char *);
      53       43435 :                         if (mechTypes == NULL) {
      54           0 :                                 asn1_set_error(asn1);
      55           0 :                                 return false;
      56             :                         }
      57      142784 :                         for (i = 0; asn1_tag_remaining(asn1) > 0; i++) {
      58             :                                 char *oid;
      59             :                                 const char **p;
      60       99349 :                                 p = talloc_realloc(mem_ctx,
      61             :                                                    mechTypes,
      62             :                                                    const char *, i+2);
      63       99349 :                                 if (p == NULL) {
      64           0 :                                         talloc_free(mechTypes);
      65           0 :                                         asn1_set_error(asn1);
      66           0 :                                         return false;
      67             :                                 }
      68       99349 :                                 mechTypes = p;
      69             : 
      70       99349 :                                 if (!asn1_read_OID(asn1, mechTypes, &oid)) return false;
      71       99349 :                                 mechTypes[i] = oid;
      72             :                         }
      73       43435 :                         mechTypes[i] = NULL;
      74       43435 :                         token->mechTypes = mechTypes;
      75             : 
      76       43435 :                         asn1_end_tag(asn1);
      77       43435 :                         asn1_end_tag(asn1);
      78       43435 :                         break;
      79             :                 }
      80             :                 /* Read reqFlags */
      81           0 :                 case ASN1_CONTEXT(1):
      82           0 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
      83           0 :                         if (!asn1_read_BitString(asn1, mem_ctx, &token->reqFlags,
      84           0 :                                             &token->reqFlagsPadding)) return false;
      85           0 :                         if (!asn1_end_tag(asn1)) return false;
      86           0 :                         break;
      87             :                 /* Read mechToken */
      88       35104 :                 case ASN1_CONTEXT(2):
      89       35104 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(2))) return false;
      90       35104 :                         if (!asn1_read_OctetString(asn1, mem_ctx, &token->mechToken)) return false;
      91       35104 :                         if (!asn1_end_tag(asn1)) return false;
      92       35104 :                         break;
      93             :                 /* Read mecListMIC */
      94        8330 :                 case ASN1_CONTEXT(3):
      95             :                 {
      96             :                         uint8_t type_peek;
      97        8330 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
      98        8330 :                         if (!asn1_peek_uint8(asn1, &type_peek)) {
      99           0 :                                 asn1_set_error(asn1);
     100        8330 :                                 break;
     101             :                         }
     102        8330 :                         if (type_peek == ASN1_OCTET_STRING) {
     103           0 :                                 if (!asn1_read_OctetString(asn1, mem_ctx,
     104           0 :                                                       &token->mechListMIC)) return false;
     105             :                         } else {
     106             :                                 /* RFC 2478 says we have an Octet String here,
     107             :                                    but W2k sends something different... */
     108             :                                 char *mechListMIC;
     109        8330 :                                 if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
     110        8330 :                                 if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
     111        8330 :                                 if (!asn1_read_GeneralString(asn1, mem_ctx, &mechListMIC)) return false;
     112        8330 :                                 if (!asn1_end_tag(asn1)) return false;
     113        8330 :                                 if (!asn1_end_tag(asn1)) return false;
     114             : 
     115        8330 :                                 token->targetPrincipal = mechListMIC;
     116             :                         }
     117        8330 :                         if (!asn1_end_tag(asn1)) return false;
     118        8330 :                         break;
     119             :                 }
     120           0 :                 default:
     121           0 :                         asn1_set_error(asn1);
     122           0 :                         break;
     123             :                 }
     124             :         }
     125             : 
     126       43435 :         if (!asn1_end_tag(asn1)) return false;
     127       43435 :         if (!asn1_end_tag(asn1)) return false;
     128             : 
     129       43435 :         return !asn1_has_error(asn1);
     130             : }
     131             : 
     132       46426 : static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenInit *token)
     133             : {
     134       46426 :         if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
     135       46426 :         if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
     136             : 
     137             :         /* Write mechTypes */
     138       46426 :         if (token->mechTypes && *token->mechTypes) {
     139             :                 int i;
     140             : 
     141       46426 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
     142       46426 :                 if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
     143      154529 :                 for (i = 0; token->mechTypes[i]; i++) {
     144      108103 :                         if (!asn1_write_OID(asn1, token->mechTypes[i])) return false;
     145             :                 }
     146       46426 :                 if (!asn1_pop_tag(asn1)) return false;
     147       46426 :                 if (!asn1_pop_tag(asn1)) return false;
     148             :         }
     149             : 
     150             :         /* write reqFlags */
     151       46426 :         if (token->reqFlags.length > 0) {
     152           0 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
     153           0 :                 if (!asn1_write_BitString(asn1, token->reqFlags.data,
     154             :                                      token->reqFlags.length,
     155           0 :                                      token->reqFlagsPadding)) return false;
     156           0 :                 if (!asn1_pop_tag(asn1)) return false;
     157             :         }
     158             : 
     159             :         /* write mechToken */
     160       46426 :         if (token->mechToken.data) {
     161       35282 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(2))) return false;
     162       35282 :                 if (!asn1_write_OctetString(asn1, token->mechToken.data,
     163           0 :                                        token->mechToken.length)) return false;
     164       35282 :                 if (!asn1_pop_tag(asn1)) return false;
     165             :         }
     166             : 
     167             :         /* write mechListMIC */
     168       46426 :         if (token->mechListMIC.data) {
     169       11143 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(3))) return false;
     170             : #if 0
     171             :                 /* This is what RFC 2478 says ... */
     172             :                 asn1_write_OctetString(asn1, token->mechListMIC.data,
     173             :                                        token->mechListMIC.length);
     174             : #else
     175             :                 /* ... but unfortunately this is what Windows
     176             :                    sends/expects */
     177       11143 :                 if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
     178       11143 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
     179       11143 :                 if (!asn1_push_tag(asn1, ASN1_GENERAL_STRING)) return false;
     180       11143 :                 if (!asn1_write(asn1, token->mechListMIC.data,
     181       11143 :                            token->mechListMIC.length)) return false;
     182       11143 :                 if (!asn1_pop_tag(asn1)) return false;
     183       11143 :                 if (!asn1_pop_tag(asn1)) return false;
     184       11143 :                 if (!asn1_pop_tag(asn1)) return false;
     185             : #endif
     186       11143 :                 if (!asn1_pop_tag(asn1)) return false;
     187             :         }
     188             : 
     189       46426 :         if (!asn1_pop_tag(asn1)) return false;
     190       46426 :         if (!asn1_pop_tag(asn1)) return false;
     191             : 
     192       46426 :         return !asn1_has_error(asn1);
     193             : }
     194             : 
     195       66349 : static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
     196             :                               struct spnego_negTokenTarg *token)
     197             : {
     198       66349 :         ZERO_STRUCTP(token);
     199             : 
     200       66349 :         if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
     201       66349 :         if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
     202             : 
     203      232402 :         while (asn1_tag_remaining(asn1) > 0) {
     204             :                 uint8_t context;
     205             :                 uint8_t neg_result;
     206             :                 char *oid;
     207             : 
     208      166053 :                 if (!asn1_peek_uint8(asn1, &context)) {
     209           0 :                         asn1_set_error(asn1);
     210           0 :                         break;
     211             :                 }
     212             : 
     213      166053 :                 switch (context) {
     214       50134 :                 case ASN1_CONTEXT(0):
     215       50134 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
     216       50134 :                         if (!asn1_start_tag(asn1, ASN1_ENUMERATED)) return false;
     217       50134 :                         if (!asn1_read_uint8(asn1, &neg_result)) return false;
     218       50134 :                         token->negResult = neg_result;
     219       50134 :                         if (!asn1_end_tag(asn1)) return false;
     220       50134 :                         if (!asn1_end_tag(asn1)) return false;
     221       50134 :                         break;
     222       34647 :                 case ASN1_CONTEXT(1):
     223       34647 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
     224       34647 :                         if (!asn1_read_OID(asn1, mem_ctx, &oid)) return false;
     225       34647 :                         token->supportedMech = oid;
     226       34647 :                         if (!asn1_end_tag(asn1)) return false;
     227       34647 :                         break;
     228       50859 :                 case ASN1_CONTEXT(2):
     229       50859 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(2))) return false;
     230       50859 :                         if (!asn1_read_OctetString(asn1, mem_ctx, &token->responseToken)) return false;
     231       50859 :                         if (!asn1_end_tag(asn1)) return false;
     232       50859 :                         break;
     233       30413 :                 case ASN1_CONTEXT(3):
     234       30413 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
     235       30413 :                         if (!asn1_read_OctetString(asn1, mem_ctx, &token->mechListMIC)) return false;
     236       30413 :                         if (!asn1_end_tag(asn1)) return false;
     237       30413 :                         break;
     238           0 :                 default:
     239           0 :                         asn1_set_error(asn1);
     240           0 :                         break;
     241             :                 }
     242             :         }
     243             : 
     244       66349 :         if (!asn1_end_tag(asn1)) return false;
     245       66349 :         if (!asn1_end_tag(asn1)) return false;
     246             : 
     247       66349 :         return !asn1_has_error(asn1);
     248             : }
     249             : 
     250       66686 : static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTarg *token)
     251             : {
     252       66686 :         if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
     253       66686 :         if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
     254             : 
     255       66686 :         if (token->negResult != SPNEGO_NONE_RESULT) {
     256       50515 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
     257       50515 :                 if (!asn1_write_enumerated(asn1, token->negResult)) return false;
     258       50515 :                 if (!asn1_pop_tag(asn1)) return false;
     259             :         }
     260             : 
     261       66686 :         if (token->supportedMech) {
     262       34908 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
     263       34908 :                 if (!asn1_write_OID(asn1, token->supportedMech)) return false;
     264       34908 :                 if (!asn1_pop_tag(asn1)) return false;
     265             :         }
     266             : 
     267       66686 :         if (token->responseToken.data) {
     268       51076 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(2))) return false;
     269       51076 :                 if (!asn1_write_OctetString(asn1, token->responseToken.data,
     270           0 :                                        token->responseToken.length)) return false;
     271       51076 :                 if (!asn1_pop_tag(asn1)) return false;
     272             :         }
     273             : 
     274       66686 :         if (token->mechListMIC.data) {
     275       30415 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(3))) return false;
     276       30415 :                 if (!asn1_write_OctetString(asn1, token->mechListMIC.data,
     277           0 :                                       token->mechListMIC.length)) return false;
     278       30415 :                 if (!asn1_pop_tag(asn1)) return false;
     279             :         }
     280             : 
     281       66686 :         if (!asn1_pop_tag(asn1)) return false;
     282       66686 :         if (!asn1_pop_tag(asn1)) return false;
     283             : 
     284       66686 :         return !asn1_has_error(asn1);
     285             : }
     286             : 
     287      109853 : ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token)
     288             : {
     289             :         struct asn1_data *asn1;
     290      109853 :         ssize_t ret = -1;
     291             :         uint8_t context;
     292             : 
     293      109853 :         ZERO_STRUCTP(token);
     294             : 
     295      109853 :         if (data.length == 0) {
     296           0 :                 return ret;
     297             :         }
     298             : 
     299      109853 :         asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
     300      109853 :         if (asn1 == NULL) {
     301           0 :                 return -1;
     302             :         }
     303             : 
     304      109853 :         if (!asn1_load(asn1, data)) goto err;
     305             : 
     306      109853 :         if (!asn1_peek_uint8(asn1, &context)) {
     307           0 :                 asn1_set_error(asn1);
     308             :         } else {
     309      109853 :                 switch (context) {
     310       43471 :                 case ASN1_APPLICATION(0):
     311       43471 :                         if (!asn1_start_tag(asn1, ASN1_APPLICATION(0))) goto err;
     312       43471 :                         if (!asn1_check_OID(asn1, OID_SPNEGO)) goto err;
     313       43435 :                         if (read_negTokenInit(asn1, mem_ctx, &token->negTokenInit)) {
     314       43435 :                                 token->type = SPNEGO_NEG_TOKEN_INIT;
     315             :                         }
     316       43435 :                         if (!asn1_end_tag(asn1)) goto err;
     317       43435 :                         break;
     318       66349 :                 case ASN1_CONTEXT(1):
     319       66349 :                         if (read_negTokenTarg(asn1, mem_ctx, &token->negTokenTarg)) {
     320       66349 :                                 token->type = SPNEGO_NEG_TOKEN_TARG;
     321             :                         }
     322       66349 :                         break;
     323          33 :                 default:
     324          33 :                         asn1_set_error(asn1);
     325          33 :                         break;
     326             :                 }
     327             :         }
     328             : 
     329      109817 :         if (!asn1_has_error(asn1)) {
     330      109784 :                 ret = asn1_current_ofs(asn1);
     331             :         }
     332             : 
     333          33 :   err:
     334             : 
     335      109853 :         asn1_free(asn1);
     336             : 
     337      109853 :         return ret;
     338             : }
     339             : 
     340      113112 : ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego)
     341             : {
     342      113112 :         struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
     343      113112 :         ssize_t ret = -1;
     344             : 
     345      113112 :         if (asn1 == NULL) {
     346           0 :                 return -1;
     347             :         }
     348             : 
     349      113112 :         switch (spnego->type) {
     350       46426 :         case SPNEGO_NEG_TOKEN_INIT:
     351       46426 :                 if (!asn1_push_tag(asn1, ASN1_APPLICATION(0))) goto err;
     352       46426 :                 if (!asn1_write_OID(asn1, OID_SPNEGO)) goto err;
     353       46426 :                 if (!write_negTokenInit(asn1, &spnego->negTokenInit)) goto err;
     354       46426 :                 if (!asn1_pop_tag(asn1)) goto err;
     355       46426 :                 break;
     356       66686 :         case SPNEGO_NEG_TOKEN_TARG:
     357       66686 :                 write_negTokenTarg(asn1, &spnego->negTokenTarg);
     358       66686 :                 break;
     359           0 :         default:
     360           0 :                 asn1_set_error(asn1);
     361           0 :                 break;
     362             :         }
     363             : 
     364      113112 :         if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
     365           0 :                 goto err;
     366             :         }
     367             : 
     368      113112 :         ret = asn1_current_ofs(asn1);
     369             : 
     370      113112 :   err:
     371             : 
     372      113112 :         asn1_free(asn1);
     373             : 
     374      113112 :         return ret;
     375             : }
     376             : 
     377           0 : bool spnego_free_data(struct spnego_data *spnego)
     378             : {
     379           0 :         bool ret = true;
     380             : 
     381           0 :         if (!spnego) goto out;
     382             : 
     383           0 :         switch(spnego->type) {
     384           0 :         case SPNEGO_NEG_TOKEN_INIT:
     385           0 :                 if (spnego->negTokenInit.mechTypes) {
     386           0 :                         talloc_free(discard_const(spnego->negTokenInit.mechTypes));
     387             :                 }
     388           0 :                 data_blob_free(&spnego->negTokenInit.reqFlags);
     389           0 :                 data_blob_free(&spnego->negTokenInit.mechToken);
     390           0 :                 data_blob_free(&spnego->negTokenInit.mechListMIC);
     391           0 :                 talloc_free(spnego->negTokenInit.targetPrincipal);
     392           0 :                 break;
     393           0 :         case SPNEGO_NEG_TOKEN_TARG:
     394           0 :                 if (spnego->negTokenTarg.supportedMech) {
     395           0 :                         talloc_free(discard_const(spnego->negTokenTarg.supportedMech));
     396             :                 }
     397           0 :                 data_blob_free(&spnego->negTokenTarg.responseToken);
     398           0 :                 data_blob_free(&spnego->negTokenTarg.mechListMIC);
     399           0 :                 break;
     400           0 :         default:
     401           0 :                 ret = false;
     402           0 :                 break;
     403             :         }
     404           0 :         ZERO_STRUCTP(spnego);
     405           0 : out:
     406           0 :         return ret;
     407             : }
     408             : 
     409       81531 : bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
     410             :                              const char * const *mech_types,
     411             :                              DATA_BLOB *blob)
     412             : {
     413       81531 :         bool ret = false;
     414       81531 :         struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
     415             : 
     416       81531 :         if (asn1 == NULL) {
     417           0 :                 return false;
     418             :         }
     419             : 
     420             :         /* Write mechTypes */
     421       81531 :         if (mech_types && *mech_types) {
     422             :                 int i;
     423             : 
     424       81531 :                 if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) goto err;
     425      264153 :                 for (i = 0; mech_types[i]; i++) {
     426      182622 :                         if (!asn1_write_OID(asn1, mech_types[i])) goto err;
     427             :                 }
     428       81531 :                 if (!asn1_pop_tag(asn1)) goto err;
     429             :         }
     430             : 
     431       81531 :         if (asn1_has_error(asn1)) {
     432           0 :                 goto err;
     433             :         }
     434             : 
     435       81531 :         if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
     436           0 :                 goto err;
     437             :         }
     438             : 
     439       81531 :         ret = true;
     440             : 
     441       81531 :   err:
     442             : 
     443       81531 :         asn1_free(asn1);
     444             : 
     445       81531 :         return ret;
     446             : }

Generated by: LCOV version 1.14