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

Generated by: LCOV version 1.14