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

Generated by: LCOV version 1.14