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

Generated by: LCOV version 1.13