]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/gssapi/test_context.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / lib / gssapi / test_context.c
1 /*
2  * Copyright (c) 2006 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of KTH nor the names of its contributors may be
18  *    used to endorse or promote products derived from this software without
19  *    specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include "krb5/gsskrb5_locl.h"
35 #include <err.h>
36 #include <getarg.h>
37 #include "test_common.h"
38
39 RCSID("$Id: test_context.c 20075 2007-01-31 06:05:19Z lha $");
40
41 static char *type_string;
42 static char *mech_string;
43 static char *ret_mech_string;
44 static int dns_canon_flag = -1;
45 static int mutual_auth_flag = 0;
46 static int dce_style_flag = 0;
47 static int wrapunwrap_flag = 0;
48 static int getverifymic_flag = 0;
49 static int deleg_flag = 0;
50 static int version_flag = 0;
51 static int verbose_flag = 0;
52 static int help_flag    = 0;
53
54 static struct {
55     const char *name;
56     gss_OID *oid;
57 } o2n[] = {
58     { "krb5", &GSS_KRB5_MECHANISM },
59     { "spnego", &GSS_SPNEGO_MECHANISM },
60     { "ntlm", &GSS_NTLM_MECHANISM },
61     { "sasl-digest-md5", &GSS_SASL_DIGEST_MD5_MECHANISM }
62 };
63
64 static gss_OID
65 string_to_oid(const char *name)
66 {
67     int i;
68     for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
69         if (strcasecmp(name, o2n[i].name) == 0)
70             return *o2n[i].oid;
71     errx(1, "name %s not unknown", name);
72 }
73
74 static const char *
75 oid_to_string(const gss_OID oid)
76 {
77     int i;
78     for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
79         if (gss_oid_equal(oid, *o2n[i].oid))
80             return o2n[i].name;
81     return "unknown oid";
82 }
83
84 static void
85 loop(gss_OID mechoid,
86      gss_OID nameoid, const char *target,
87      gss_cred_id_t init_cred,
88      gss_ctx_id_t *sctx, gss_ctx_id_t *cctx,
89      gss_OID *actual_mech, 
90      gss_cred_id_t *deleg_cred)
91 {
92     int server_done = 0, client_done = 0;
93     OM_uint32 maj_stat, min_stat;
94     gss_name_t gss_target_name;
95     gss_buffer_desc input_token, output_token;
96     OM_uint32 flags = 0, ret_cflags, ret_sflags;
97     gss_OID actual_mech_client; 
98     gss_OID actual_mech_server; 
99
100     *actual_mech = GSS_C_NO_OID;
101
102     flags |= GSS_C_INTEG_FLAG;
103     flags |= GSS_C_CONF_FLAG;
104
105     if (mutual_auth_flag)
106         flags |= GSS_C_MUTUAL_FLAG;
107     if (dce_style_flag)
108         flags |= GSS_C_DCE_STYLE;
109     if (deleg_flag)
110         flags |= GSS_C_DELEG_FLAG;
111
112     input_token.value = rk_UNCONST(target);
113     input_token.length = strlen(target);
114
115     maj_stat = gss_import_name(&min_stat,
116                                &input_token,
117                                nameoid,
118                                &gss_target_name);
119     if (GSS_ERROR(maj_stat))
120         err(1, "import name creds failed with: %d", maj_stat);
121
122     input_token.length = 0;
123     input_token.value = NULL;
124
125     while (!server_done || !client_done) {
126
127         maj_stat = gss_init_sec_context(&min_stat,
128                                         init_cred,
129                                         cctx,
130                                         gss_target_name,
131                                         mechoid, 
132                                         flags,
133                                         0, 
134                                         NULL,
135                                         &input_token,
136                                         &actual_mech_client,
137                                         &output_token,
138                                         &ret_cflags,
139                                         NULL);
140         if (GSS_ERROR(maj_stat))
141             errx(1, "init_sec_context: %s",
142                  gssapi_err(maj_stat, min_stat, mechoid));
143         if (maj_stat & GSS_S_CONTINUE_NEEDED)
144             ;
145         else
146             client_done = 1;
147
148         if (client_done && server_done)
149             break;
150
151         if (input_token.length != 0)
152             gss_release_buffer(&min_stat, &input_token);
153
154         maj_stat = gss_accept_sec_context(&min_stat,
155                                           sctx,
156                                           GSS_C_NO_CREDENTIAL,
157                                           &output_token,
158                                           GSS_C_NO_CHANNEL_BINDINGS,
159                                           NULL,
160                                           &actual_mech_server,
161                                           &input_token,
162                                           &ret_sflags,
163                                           NULL,
164                                           deleg_cred);
165         if (GSS_ERROR(maj_stat))
166                 errx(1, "accept_sec_context: %s",
167                      gssapi_err(maj_stat, min_stat, actual_mech_server));
168
169         if (verbose_flag)
170             printf("%.*s", (int)input_token.length, (char *)input_token.value);
171
172         if (output_token.length != 0)
173             gss_release_buffer(&min_stat, &output_token);
174
175         if (maj_stat & GSS_S_CONTINUE_NEEDED)
176             ;
177         else
178             server_done = 1;
179     }   
180     if (output_token.length != 0)
181         gss_release_buffer(&min_stat, &output_token);
182     if (input_token.length != 0)
183         gss_release_buffer(&min_stat, &input_token);
184     gss_release_name(&min_stat, &gss_target_name);
185
186     if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)
187         errx(1, "mech mismatch");
188     *actual_mech = actual_mech_server;
189 }
190
191 static void
192 wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
193 {
194     gss_buffer_desc input_token, output_token, output_token2;
195     OM_uint32 min_stat, maj_stat;
196     int32_t flags = 0;
197     gss_qop_t qop_state;
198     int conf_state;
199
200     input_token.value = "foo";
201     input_token.length = 3;
202
203     maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token,
204                         &conf_state, &output_token);
205     if (maj_stat != GSS_S_COMPLETE)
206         errx(1, "gss_wrap failed: %s",
207              gssapi_err(maj_stat, min_stat, mechoid));
208
209     maj_stat = gss_unwrap(&min_stat, sctx, &output_token,
210                           &output_token2, &conf_state, &qop_state);
211     if (maj_stat != GSS_S_COMPLETE)
212         errx(1, "gss_unwrap failed: %s",
213              gssapi_err(maj_stat, min_stat, mechoid));
214 }
215
216 static void
217 getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
218 {
219     gss_buffer_desc input_token, output_token;
220     OM_uint32 min_stat, maj_stat;
221     gss_qop_t qop_state;
222
223     input_token.value = "bar";
224     input_token.length = 3;
225
226     maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
227                            &output_token);
228     if (maj_stat != GSS_S_COMPLETE)
229         errx(1, "gss_get_mic failed: %s",
230              gssapi_err(maj_stat, min_stat, mechoid));
231
232     maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
233                               &output_token, &qop_state);
234     if (maj_stat != GSS_S_COMPLETE)
235         errx(1, "gss_verify_mic failed: %s",
236              gssapi_err(maj_stat, min_stat, mechoid));
237 }
238
239
240 /*
241  *
242  */
243
244 static struct getargs args[] = {
245     {"name-type",0,     arg_string, &type_string,  "type of name", NULL },
246     {"mech-type",0,     arg_string, &mech_string,  "type of mech", NULL },
247     {"ret-mech-type",0, arg_string, &ret_mech_string,
248      "type of return mech", NULL },
249     {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag, 
250      "use dns to canonicalize", NULL },
251     {"mutual-auth",0,   arg_flag,       &mutual_auth_flag,"mutual auth", NULL },
252     {"dce-style",0,     arg_flag,       &dce_style_flag, "dce-style", NULL },
253     {"wrapunwrap",0,    arg_flag,       &wrapunwrap_flag, "wrap/unwrap", NULL },
254     {"getverifymic",0,  arg_flag,       &getverifymic_flag, 
255      "get and verify mic", NULL },
256     {"delegate",0,      arg_flag,       &deleg_flag, "delegate credential", NULL },
257     {"version", 0,      arg_flag,       &version_flag, "print version", NULL },
258     {"verbose", 'v',    arg_flag,       &verbose_flag, "verbose", NULL },
259     {"help",    0,      arg_flag,       &help_flag,  NULL, NULL }
260 };
261
262 static void
263 usage (int ret)
264 {
265     arg_printusage (args, sizeof(args)/sizeof(*args),
266                     NULL, "service@host");
267     exit (ret);
268 }
269
270 int
271 main(int argc, char **argv)
272 {
273     int optind = 0;
274     OM_uint32 min_stat, maj_stat;
275     gss_ctx_id_t cctx, sctx;
276     void *ctx;
277     gss_OID nameoid, mechoid, actual_mech;
278     gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
279
280     setprogname(argv[0]);
281
282     cctx = sctx = GSS_C_NO_CONTEXT;
283
284     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
285         usage(1);
286     
287     if (help_flag)
288         usage (0);
289
290     if(version_flag){
291         print_version(NULL);
292         exit(0);
293     }
294
295     argc -= optind;
296     argv += optind;
297
298     if (argc != 1)
299         usage(1);
300
301     if (dns_canon_flag != -1)
302         gsskrb5_set_dns_canonicalize(dns_canon_flag);
303
304     if (type_string == NULL)
305         nameoid = GSS_C_NT_HOSTBASED_SERVICE;
306     else if (strcmp(type_string, "hostbased-service") == 0)
307         nameoid = GSS_C_NT_HOSTBASED_SERVICE;
308     else if (strcmp(type_string, "krb5-principal-name") == 0)
309         nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
310     else
311         errx(1, "%s not suppported", type_string);
312
313     if (mech_string == NULL)
314         mechoid = GSS_KRB5_MECHANISM;
315     else 
316         mechoid = string_to_oid(mech_string);
317
318     loop(mechoid, nameoid, argv[0], GSS_C_NO_CREDENTIAL,
319          &sctx, &cctx, &actual_mech, &deleg_cred);
320     
321     if (verbose_flag)
322         printf("resulting mech: %s\n", oid_to_string(actual_mech));
323
324     if (ret_mech_string) {
325         gss_OID retoid;
326
327         retoid = string_to_oid(ret_mech_string);
328
329         if (gss_oid_equal(retoid, actual_mech) == 0)
330             errx(1, "actual_mech mech is not the expected type %s", 
331                  ret_mech_string);
332     }
333
334     /* XXX should be actual_mech */
335     if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) { 
336         krb5_context context;
337         time_t time, skew;
338         gss_buffer_desc authz_data;
339         gss_buffer_desc in, out1, out2;
340         krb5_keyblock *keyblock, *keyblock2;
341         krb5_timestamp now;
342         krb5_error_code ret;
343
344         ret = krb5_init_context(&context);
345         if (ret)
346             errx(1, "krb5_init_context");
347
348         ret = krb5_timeofday(context, &now);
349         if (ret) 
350                 errx(1, "krb5_timeofday failed");
351         
352         /* client */
353         maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
354                                                      &cctx,
355                                                      1, /* version */
356                                                      &ctx);
357         if (maj_stat != GSS_S_COMPLETE)
358                 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
359                      gssapi_err(maj_stat, min_stat, actual_mech));
360         
361         
362         maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
363         if (maj_stat != GSS_S_COMPLETE)
364             errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
365                      gssapi_err(maj_stat, min_stat, actual_mech));
366         
367         /* server */
368         maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
369                                                      &sctx,
370                                                      1, /* version */
371                                                      &ctx);
372         if (maj_stat != GSS_S_COMPLETE)
373             errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
374                      gssapi_err(maj_stat, min_stat, actual_mech));
375         maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
376         if (maj_stat != GSS_S_COMPLETE)
377             errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
378                      gssapi_err(maj_stat, min_stat, actual_mech));
379
380         maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
381                                                              sctx,
382                                                              &time);
383         if (maj_stat != GSS_S_COMPLETE)
384             errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
385                      gssapi_err(maj_stat, min_stat, actual_mech));
386
387         skew = abs(time - now);
388         if (skew > krb5_get_max_time_skew(context)) {
389             errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
390                  "time skew too great %llu > %llu", 
391                  (unsigned long long)skew, 
392                  (unsigned long long)krb5_get_max_time_skew(context));
393         }
394
395         maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
396                                                     sctx,
397                                                     &keyblock);
398         if (maj_stat != GSS_S_COMPLETE)
399             errx(1, "gsskrb5_export_service_keyblock failed: %s",
400                      gssapi_err(maj_stat, min_stat, actual_mech));
401
402         krb5_free_keyblock(context, keyblock);
403
404         maj_stat = gsskrb5_get_subkey(&min_stat,
405                                       sctx,
406                                       &keyblock);
407         if (maj_stat != GSS_S_COMPLETE 
408             && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
409             errx(1, "gsskrb5_get_subkey server failed: %s",
410                      gssapi_err(maj_stat, min_stat, actual_mech));
411
412         if (maj_stat != GSS_S_COMPLETE)
413             keyblock = NULL;
414         
415         maj_stat = gsskrb5_get_subkey(&min_stat,
416                                       cctx,
417                                       &keyblock2);
418         if (maj_stat != GSS_S_COMPLETE 
419             && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
420             errx(1, "gsskrb5_get_subkey client failed: %s",
421                      gssapi_err(maj_stat, min_stat, actual_mech));
422
423         if (maj_stat != GSS_S_COMPLETE)
424             keyblock2 = NULL;
425
426         if (keyblock || keyblock2) {
427             if (keyblock == NULL)
428                 errx(1, "server missing token keyblock");
429             if (keyblock2 == NULL)
430                 errx(1, "client missing token keyblock");
431
432             if (keyblock->keytype != keyblock2->keytype)
433                 errx(1, "enctype mismatch");
434             if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
435                 errx(1, "key length mismatch");
436             if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data, 
437                        keyblock2->keyvalue.length) != 0)
438                 errx(1, "key data mismatch");
439         }
440
441         if (keyblock)
442             krb5_free_keyblock(context, keyblock);
443         if (keyblock2)
444             krb5_free_keyblock(context, keyblock2);
445
446         maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
447                                                 sctx,
448                                                 &keyblock);
449         if (maj_stat != GSS_S_COMPLETE 
450             && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
451             errx(1, "gsskrb5_get_initiator_subkey failed: %s",
452                      gssapi_err(maj_stat, min_stat, actual_mech));
453
454         if (maj_stat == GSS_S_COMPLETE)
455             krb5_free_keyblock(context, keyblock);
456
457         maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
458                                                                sctx,
459                                                                128,
460                                                                &authz_data);
461         if (maj_stat == GSS_S_COMPLETE)
462             gss_release_buffer(&min_stat, &authz_data);
463
464         krb5_free_context(context);
465
466
467         memset(&out1, 0, sizeof(out1));
468         memset(&out2, 0, sizeof(out2));
469
470         in.value = "foo";
471         in.length = 3;
472
473         gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in, 
474                           100, &out1);
475         gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in, 
476                           100, &out2);
477
478         if (out1.length != out2.length)
479             errx(1, "prf len mismatch");
480         if (memcmp(out1.value, out2.value, out1.length) != 0)
481             errx(1, "prf data mismatch");
482         
483         gss_release_buffer(&min_stat, &out1);
484
485         gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in, 
486                           100, &out1);
487
488         if (out1.length != out2.length)
489             errx(1, "prf len mismatch");
490         if (memcmp(out1.value, out2.value, out1.length) != 0)
491             errx(1, "prf data mismatch");
492
493         gss_release_buffer(&min_stat, &out1);
494         gss_release_buffer(&min_stat, &out2);
495
496         in.value = "bar";
497         in.length = 3;
498
499         gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in, 
500                           100, &out1);
501         gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in, 
502                           100, &out2);
503
504         if (out1.length != out2.length)
505             errx(1, "prf len mismatch");
506         if (memcmp(out1.value, out2.value, out1.length) != 0)
507             errx(1, "prf data mismatch");
508
509         gss_release_buffer(&min_stat, &out1);
510         gss_release_buffer(&min_stat, &out2);
511
512         wrapunwrap_flag = 1;
513         getverifymic_flag = 1;
514     }
515
516     if (wrapunwrap_flag) {
517         wrapunwrap(cctx, sctx, actual_mech);
518         wrapunwrap(cctx, sctx, actual_mech);
519         wrapunwrap(sctx, cctx, actual_mech);
520         wrapunwrap(sctx, cctx, actual_mech);
521     }
522     if (getverifymic_flag) {
523         getverifymic(cctx, sctx, actual_mech);
524         getverifymic(cctx, sctx, actual_mech);
525         getverifymic(sctx, cctx, actual_mech);
526         getverifymic(sctx, cctx, actual_mech);
527     }
528
529     gss_delete_sec_context(&min_stat, &cctx, NULL);
530     gss_delete_sec_context(&min_stat, &sctx, NULL);
531
532     if (deleg_cred != GSS_C_NO_CREDENTIAL) {
533
534         loop(mechoid, nameoid, argv[0], deleg_cred, &cctx, &sctx, &actual_mech, NULL);
535
536         gss_delete_sec_context(&min_stat, &cctx, NULL);
537         gss_delete_sec_context(&min_stat, &sctx, NULL);
538
539     }
540
541     return 0;
542 }