LCOV - code coverage report
Current view: top level - libcli/auth - spnego_parse.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 205 271 75.6 %
Date: 2024-04-21 15:09:00 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      107377 : static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
      28             :                               struct spnego_negTokenInit *token)
      29             : {
      30      107377 :         ZERO_STRUCTP(token);
      31             : 
      32      107377 :         if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
      33      107377 :         if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
      34             : 
      35      322125 :         while (asn1_tag_remaining(asn1) > 0) {
      36        4272 :                 int i;
      37        4272 :                 uint8_t context;
      38             : 
      39      214748 :                 if (!asn1_peek_uint8(asn1, &context)) {
      40           0 :                         asn1_set_error(asn1);
      41           0 :                         break;
      42             :                 }
      43             : 
      44      214748 :                 switch (context) {
      45             :                 /* Read mechTypes */
      46      107377 :                 case ASN1_CONTEXT(0): {
      47        2136 :                         const char **mechTypes;
      48             : 
      49      107377 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
      50      107377 :                         if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
      51             : 
      52      107377 :                         mechTypes = talloc(mem_ctx, const char *);
      53      107377 :                         if (mechTypes == NULL) {
      54           0 :                                 asn1_set_error(asn1);
      55           0 :                                 return false;
      56             :                         }
      57      303230 :                         for (i = 0; asn1_tag_remaining(asn1) > 0; i++) {
      58        5971 :                                 char *oid;
      59        5971 :                                 const char **p;
      60      195853 :                                 p = talloc_realloc(mem_ctx,
      61             :                                                    mechTypes,
      62             :                                                    const char *, i+2);
      63      195853 :                                 if (p == NULL) {
      64           0 :                                         talloc_free(mechTypes);
      65           0 :                                         asn1_set_error(asn1);
      66           0 :                                         return false;
      67             :                                 }
      68      195853 :                                 mechTypes = p;
      69             : 
      70      195853 :                                 if (!asn1_read_OID(asn1, mechTypes, &oid)) return false;
      71      195853 :                                 mechTypes[i] = oid;
      72             :                         }
      73      107377 :                         mechTypes[i] = NULL;
      74      107377 :                         token->mechTypes = mechTypes;
      75             : 
      76      107377 :                         asn1_end_tag(asn1);
      77      107377 :                         asn1_end_tag(asn1);
      78      107377 :                         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       69045 :                 case ASN1_CONTEXT(2):
      89       69045 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(2))) return false;
      90       69045 :                         if (!asn1_read_OctetString(asn1, mem_ctx, &token->mechToken)) return false;
      91       69045 :                         if (!asn1_end_tag(asn1)) return false;
      92       68016 :                         break;
      93             :                 /* Read mecListMIC */
      94       38326 :                 case ASN1_CONTEXT(3):
      95             :                 {
      96        1107 :                         uint8_t type_peek;
      97       38326 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
      98       38326 :                         if (!asn1_peek_uint8(asn1, &type_peek)) {
      99           0 :                                 asn1_set_error(asn1);
     100       38326 :                                 break;
     101             :                         }
     102       38326 :                         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        1107 :                                 char *mechListMIC;
     109       38326 :                                 if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
     110       38326 :                                 if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
     111       38326 :                                 if (!asn1_read_GeneralString(asn1, mem_ctx, &mechListMIC)) return false;
     112       38326 :                                 if (!asn1_end_tag(asn1)) return false;
     113       38326 :                                 if (!asn1_end_tag(asn1)) return false;
     114             : 
     115       38326 :                                 token->targetPrincipal = mechListMIC;
     116             :                         }
     117       38326 :                         if (!asn1_end_tag(asn1)) return false;
     118       37219 :                         break;
     119             :                 }
     120           0 :                 default:
     121           0 :                         asn1_set_error(asn1);
     122           0 :                         break;
     123             :                 }
     124             :         }
     125             : 
     126      107377 :         if (!asn1_end_tag(asn1)) return false;
     127      107377 :         if (!asn1_end_tag(asn1)) return false;
     128             : 
     129      107377 :         return !asn1_has_error(asn1);
     130             : }
     131             : 
     132      122118 : static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenInit *token)
     133             : {
     134      122118 :         if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
     135      122118 :         if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
     136             : 
     137             :         /* Write mechTypes */
     138      122118 :         if (token->mechTypes && *token->mechTypes) {
     139        2607 :                 int i;
     140             : 
     141      122118 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
     142      122118 :                 if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
     143      341774 :                 for (i = 0; token->mechTypes[i]; i++) {
     144      219656 :                         if (!asn1_write_OID(asn1, token->mechTypes[i])) return false;
     145             :                 }
     146      122118 :                 if (!asn1_pop_tag(asn1)) return false;
     147      122118 :                 if (!asn1_pop_tag(asn1)) return false;
     148             :         }
     149             : 
     150             :         /* write reqFlags */
     151      122118 :         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      122118 :         if (token->mechToken.data) {
     161       70755 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(2))) return false;
     162       70755 :                 if (!asn1_write_OctetString(asn1, token->mechToken.data,
     163           0 :                                        token->mechToken.length)) return false;
     164       70755 :                 if (!asn1_pop_tag(asn1)) return false;
     165             :         }
     166             : 
     167             :         /* write mechListMIC */
     168      122118 :         if (token->mechListMIC.data) {
     169       51357 :                 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       51357 :                 if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
     178       51357 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
     179       51357 :                 if (!asn1_push_tag(asn1, ASN1_GENERAL_STRING)) return false;
     180       51357 :                 if (!asn1_write(asn1, token->mechListMIC.data,
     181       51357 :                            token->mechListMIC.length)) return false;
     182       51357 :                 if (!asn1_pop_tag(asn1)) return false;
     183       51357 :                 if (!asn1_pop_tag(asn1)) return false;
     184       51357 :                 if (!asn1_pop_tag(asn1)) return false;
     185             : #endif
     186       51357 :                 if (!asn1_pop_tag(asn1)) return false;
     187             :         }
     188             : 
     189      122118 :         if (!asn1_pop_tag(asn1)) return false;
     190      122118 :         if (!asn1_pop_tag(asn1)) return false;
     191             : 
     192      122118 :         return !asn1_has_error(asn1);
     193             : }
     194             : 
     195      147289 : static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
     196             :                               struct spnego_negTokenTarg *token)
     197             : {
     198      147289 :         ZERO_STRUCTP(token);
     199             : 
     200      147289 :         if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
     201      147289 :         if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
     202             : 
     203      508074 :         while (asn1_tag_remaining(asn1) > 0) {
     204        4020 :                 uint8_t context;
     205        4020 :                 uint8_t neg_result;
     206        4020 :                 char *oid;
     207             : 
     208      360785 :                 if (!asn1_peek_uint8(asn1, &context)) {
     209           0 :                         asn1_set_error(asn1);
     210           0 :                         break;
     211             :                 }
     212             : 
     213      360785 :                 switch (context) {
     214      106227 :                 case ASN1_CONTEXT(0):
     215      106227 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
     216      106227 :                         if (!asn1_start_tag(asn1, ASN1_ENUMERATED)) return false;
     217      106227 :                         if (!asn1_read_uint8(asn1, &neg_result)) return false;
     218      106227 :                         token->negResult = neg_result;
     219      106227 :                         if (!asn1_end_tag(asn1)) return false;
     220      106227 :                         if (!asn1_end_tag(asn1)) return false;
     221      104965 :                         break;
     222       68702 :                 case ASN1_CONTEXT(1):
     223       68702 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
     224       68702 :                         if (!asn1_read_OID(asn1, mem_ctx, &oid)) return false;
     225       68702 :                         token->supportedMech = oid;
     226       68702 :                         if (!asn1_end_tag(asn1)) return false;
     227       67674 :                         break;
     228      109752 :                 case ASN1_CONTEXT(2):
     229      109752 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(2))) return false;
     230      109752 :                         if (!asn1_read_OctetString(asn1, mem_ctx, &token->responseToken)) return false;
     231      109752 :                         if (!asn1_end_tag(asn1)) return false;
     232      108480 :                         break;
     233       76104 :                 case ASN1_CONTEXT(3):
     234       76104 :                         if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
     235       76104 :                         if (!asn1_read_OctetString(asn1, mem_ctx, &token->mechListMIC)) return false;
     236       76104 :                         if (!asn1_end_tag(asn1)) return false;
     237       75646 :                         break;
     238           0 :                 default:
     239           0 :                         asn1_set_error(asn1);
     240           0 :                         break;
     241             :                 }
     242             :         }
     243             : 
     244      147289 :         if (!asn1_end_tag(asn1)) return false;
     245      147289 :         if (!asn1_end_tag(asn1)) return false;
     246             : 
     247      147289 :         return !asn1_has_error(asn1);
     248             : }
     249             : 
     250      147522 : static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTarg *token)
     251             : {
     252      147522 :         if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
     253      147522 :         if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
     254             : 
     255      147522 :         if (token->negResult != SPNEGO_NONE_RESULT) {
     256      106315 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
     257      106315 :                 if (!asn1_write_enumerated(asn1, token->negResult)) return false;
     258      106315 :                 if (!asn1_pop_tag(asn1)) return false;
     259             :         }
     260             : 
     261      147522 :         if (token->supportedMech) {
     262       68858 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
     263       68858 :                 if (!asn1_write_OID(asn1, token->supportedMech)) return false;
     264       68858 :                 if (!asn1_pop_tag(asn1)) return false;
     265             :         }
     266             : 
     267      147522 :         if (token->responseToken.data) {
     268      110053 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(2))) return false;
     269      110053 :                 if (!asn1_write_OctetString(asn1, token->responseToken.data,
     270           0 :                                        token->responseToken.length)) return false;
     271      110053 :                 if (!asn1_pop_tag(asn1)) return false;
     272             :         }
     273             : 
     274      147522 :         if (token->mechListMIC.data) {
     275       76091 :                 if (!asn1_push_tag(asn1, ASN1_CONTEXT(3))) return false;
     276       76091 :                 if (!asn1_write_OctetString(asn1, token->mechListMIC.data,
     277           0 :                                       token->mechListMIC.length)) return false;
     278       76091 :                 if (!asn1_pop_tag(asn1)) return false;
     279             :         }
     280             : 
     281      147522 :         if (!asn1_pop_tag(asn1)) return false;
     282      147522 :         if (!asn1_pop_tag(asn1)) return false;
     283             : 
     284      147522 :         return !asn1_has_error(asn1);
     285             : }
     286             : 
     287      254813 : ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token)
     288             : {
     289        3642 :         struct asn1_data *asn1;
     290      254813 :         ssize_t ret = -1;
     291        3642 :         uint8_t context;
     292             : 
     293      254813 :         ZERO_STRUCTP(token);
     294             : 
     295      254813 :         if (data.length == 0) {
     296           0 :                 return ret;
     297             :         }
     298             : 
     299      254813 :         asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
     300      254813 :         if (asn1 == NULL) {
     301           0 :                 return -1;
     302             :         }
     303             : 
     304      254813 :         if (!asn1_load(asn1, data)) goto err;
     305             : 
     306      254813 :         if (!asn1_peek_uint8(asn1, &context)) {
     307           0 :                 asn1_set_error(asn1);
     308             :         } else {
     309      254813 :                 switch (context) {
     310      107422 :                 case ASN1_APPLICATION(0):
     311      107422 :                         if (!asn1_start_tag(asn1, ASN1_APPLICATION(0))) goto err;
     312      107422 :                         if (!asn1_check_OID(asn1, OID_SPNEGO)) goto err;
     313      107377 :                         if (read_negTokenInit(asn1, mem_ctx, &token->negTokenInit)) {
     314      107377 :                                 token->type = SPNEGO_NEG_TOKEN_INIT;
     315             :                         }
     316      107377 :                         if (!asn1_end_tag(asn1)) goto err;
     317      105241 :                         break;
     318      147289 :                 case ASN1_CONTEXT(1):
     319      147289 :                         if (read_negTokenTarg(asn1, mem_ctx, &token->negTokenTarg)) {
     320      147289 :                                 token->type = SPNEGO_NEG_TOKEN_TARG;
     321             :                         }
     322      145783 :                         break;
     323         102 :                 default:
     324         102 :                         asn1_set_error(asn1);
     325         102 :                         break;
     326             :                 }
     327             :         }
     328             : 
     329      254768 :         if (!asn1_has_error(asn1)) {
     330      254666 :                 ret = asn1_current_ofs(asn1);
     331             :         }
     332             : 
     333         102 :   err:
     334             : 
     335      254813 :         asn1_free(asn1);
     336             : 
     337      254813 :         return ret;
     338             : }
     339             : 
     340      269640 : ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego)
     341             : {
     342      269640 :         struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
     343      269640 :         ssize_t ret = -1;
     344             : 
     345      269640 :         if (asn1 == NULL) {
     346           0 :                 return -1;
     347             :         }
     348             : 
     349      269640 :         switch (spnego->type) {
     350      122118 :         case SPNEGO_NEG_TOKEN_INIT:
     351      122118 :                 if (!asn1_push_tag(asn1, ASN1_APPLICATION(0))) goto err;
     352      122118 :                 if (!asn1_write_OID(asn1, OID_SPNEGO)) goto err;
     353      122118 :                 if (!write_negTokenInit(asn1, &spnego->negTokenInit)) goto err;
     354      122118 :                 if (!asn1_pop_tag(asn1)) goto err;
     355      119511 :                 break;
     356      147522 :         case SPNEGO_NEG_TOKEN_TARG:
     357      147522 :                 write_negTokenTarg(asn1, &spnego->negTokenTarg);
     358      147522 :                 break;
     359           0 :         default:
     360           0 :                 asn1_set_error(asn1);
     361           0 :                 break;
     362             :         }
     363             : 
     364      269640 :         if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
     365           0 :                 goto err;
     366             :         }
     367             : 
     368      269640 :         ret = asn1_current_ofs(asn1);
     369             : 
     370      269640 :   err:
     371             : 
     372      269640 :         asn1_free(asn1);
     373             : 
     374      269640 :         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      191169 : bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
     410             :                              const char * const *mech_types,
     411             :                              DATA_BLOB *blob)
     412             : {
     413      191169 :         bool ret = false;
     414      191169 :         struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
     415             : 
     416      191169 :         if (asn1 == NULL) {
     417           0 :                 return false;
     418             :         }
     419             : 
     420             :         /* Write mechTypes */
     421      191169 :         if (mech_types && *mech_types) {
     422        3636 :                 int i;
     423             : 
     424      191169 :                 if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) goto err;
     425      536920 :                 for (i = 0; mech_types[i]; i++) {
     426      345751 :                         if (!asn1_write_OID(asn1, mech_types[i])) goto err;
     427             :                 }
     428      191169 :                 if (!asn1_pop_tag(asn1)) goto err;
     429             :         }
     430             : 
     431      191169 :         if (asn1_has_error(asn1)) {
     432           0 :                 goto err;
     433             :         }
     434             : 
     435      191169 :         if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
     436           0 :                 goto err;
     437             :         }
     438             : 
     439      187533 :         ret = true;
     440             : 
     441      191169 :   err:
     442             : 
     443      191169 :         asn1_free(asn1);
     444             : 
     445      191169 :         return ret;
     446             : }

Generated by: LCOV version 1.14