2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "krb5/gsskrb5_locl.h"
37 #include "test_common.h"
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 char *gsskrb5_acceptor_identity
;
51 static int version_flag
= 0;
52 static int verbose_flag
= 0;
53 static int help_flag
= 0;
59 { "krb5", &GSS_KRB5_MECHANISM
},
60 { "spnego", &GSS_SPNEGO_MECHANISM
},
61 { "ntlm", &GSS_NTLM_MECHANISM
},
62 { "sasl-digest-md5", &GSS_SASL_DIGEST_MD5_MECHANISM
}
66 string_to_oid(const char *name
)
69 for (i
= 0; i
< sizeof(o2n
)/sizeof(o2n
[0]); i
++)
70 if (strcasecmp(name
, o2n
[i
].name
) == 0)
72 errx(1, "name %s not unknown", name
);
76 oid_to_string(const gss_OID oid
)
79 for (i
= 0; i
< sizeof(o2n
)/sizeof(o2n
[0]); i
++)
80 if (gss_oid_equal(oid
, *o2n
[i
].oid
))
87 gss_OID nameoid
, const char *target
,
88 gss_cred_id_t init_cred
,
89 gss_ctx_id_t
*sctx
, gss_ctx_id_t
*cctx
,
91 gss_cred_id_t
*deleg_cred
)
93 int server_done
= 0, client_done
= 0;
94 OM_uint32 maj_stat
, min_stat
;
95 gss_name_t gss_target_name
;
96 gss_buffer_desc input_token
, output_token
;
97 OM_uint32 flags
= 0, ret_cflags
, ret_sflags
;
98 gss_OID actual_mech_client
;
99 gss_OID actual_mech_server
;
101 *actual_mech
= GSS_C_NO_OID
;
103 flags
|= GSS_C_INTEG_FLAG
;
104 flags
|= GSS_C_CONF_FLAG
;
106 if (mutual_auth_flag
)
107 flags
|= GSS_C_MUTUAL_FLAG
;
109 flags
|= GSS_C_DCE_STYLE
;
111 flags
|= GSS_C_DELEG_FLAG
;
113 input_token
.value
= rk_UNCONST(target
);
114 input_token
.length
= strlen(target
);
116 maj_stat
= gss_import_name(&min_stat
,
120 if (GSS_ERROR(maj_stat
))
121 err(1, "import name creds failed with: %d", maj_stat
);
123 input_token
.length
= 0;
124 input_token
.value
= NULL
;
126 while (!server_done
|| !client_done
) {
128 maj_stat
= gss_init_sec_context(&min_stat
,
141 if (GSS_ERROR(maj_stat
))
142 errx(1, "init_sec_context: %s",
143 gssapi_err(maj_stat
, min_stat
, mechoid
));
144 if (maj_stat
& GSS_S_CONTINUE_NEEDED
)
149 if (client_done
&& server_done
)
152 if (input_token
.length
!= 0)
153 gss_release_buffer(&min_stat
, &input_token
);
155 maj_stat
= gss_accept_sec_context(&min_stat
,
159 GSS_C_NO_CHANNEL_BINDINGS
,
166 if (GSS_ERROR(maj_stat
))
167 errx(1, "accept_sec_context: %s",
168 gssapi_err(maj_stat
, min_stat
, actual_mech_server
));
171 printf("%.*s", (int)input_token
.length
, (char *)input_token
.value
);
173 if (output_token
.length
!= 0)
174 gss_release_buffer(&min_stat
, &output_token
);
176 if (maj_stat
& GSS_S_CONTINUE_NEEDED
)
181 if (output_token
.length
!= 0)
182 gss_release_buffer(&min_stat
, &output_token
);
183 if (input_token
.length
!= 0)
184 gss_release_buffer(&min_stat
, &input_token
);
185 gss_release_name(&min_stat
, &gss_target_name
);
187 if (gss_oid_equal(actual_mech_server
, actual_mech_client
) == 0)
188 errx(1, "mech mismatch");
189 *actual_mech
= actual_mech_server
;
193 wrapunwrap(gss_ctx_id_t cctx
, gss_ctx_id_t sctx
, gss_OID mechoid
)
195 gss_buffer_desc input_token
, output_token
, output_token2
;
196 OM_uint32 min_stat
, maj_stat
;
201 input_token
.value
= "foo";
202 input_token
.length
= 3;
204 maj_stat
= gss_wrap(&min_stat
, cctx
, flags
, 0, &input_token
,
205 &conf_state
, &output_token
);
206 if (maj_stat
!= GSS_S_COMPLETE
)
207 errx(1, "gss_wrap failed: %s",
208 gssapi_err(maj_stat
, min_stat
, mechoid
));
210 maj_stat
= gss_unwrap(&min_stat
, sctx
, &output_token
,
211 &output_token2
, &conf_state
, &qop_state
);
212 if (maj_stat
!= GSS_S_COMPLETE
)
213 errx(1, "gss_unwrap failed: %s",
214 gssapi_err(maj_stat
, min_stat
, mechoid
));
218 getverifymic(gss_ctx_id_t cctx
, gss_ctx_id_t sctx
, gss_OID mechoid
)
220 gss_buffer_desc input_token
, output_token
;
221 OM_uint32 min_stat
, maj_stat
;
224 input_token
.value
= "bar";
225 input_token
.length
= 3;
227 maj_stat
= gss_get_mic(&min_stat
, cctx
, 0, &input_token
,
229 if (maj_stat
!= GSS_S_COMPLETE
)
230 errx(1, "gss_get_mic failed: %s",
231 gssapi_err(maj_stat
, min_stat
, mechoid
));
233 maj_stat
= gss_verify_mic(&min_stat
, sctx
, &input_token
,
234 &output_token
, &qop_state
);
235 if (maj_stat
!= GSS_S_COMPLETE
)
236 errx(1, "gss_verify_mic failed: %s",
237 gssapi_err(maj_stat
, min_stat
, mechoid
));
245 static struct getargs args
[] = {
246 {"name-type",0, arg_string
, &type_string
, "type of name", NULL
},
247 {"mech-type",0, arg_string
, &mech_string
, "type of mech", NULL
},
248 {"ret-mech-type",0, arg_string
, &ret_mech_string
,
249 "type of return mech", NULL
},
250 {"dns-canonicalize",0,arg_negative_flag
, &dns_canon_flag
,
251 "use dns to canonicalize", NULL
},
252 {"mutual-auth",0, arg_flag
, &mutual_auth_flag
,"mutual auth", NULL
},
253 {"dce-style",0, arg_flag
, &dce_style_flag
, "dce-style", NULL
},
254 {"wrapunwrap",0, arg_flag
, &wrapunwrap_flag
, "wrap/unwrap", NULL
},
255 {"getverifymic",0, arg_flag
, &getverifymic_flag
,
256 "get and verify mic", NULL
},
257 {"delegate",0, arg_flag
, &deleg_flag
, "delegate credential", NULL
},
258 {"gsskrb5-acceptor-identity", 0, arg_string
, &gsskrb5_acceptor_identity
, "keytab", NULL
},
259 {"version", 0, arg_flag
, &version_flag
, "print version", NULL
},
260 {"verbose", 'v', arg_flag
, &verbose_flag
, "verbose", NULL
},
261 {"help", 0, arg_flag
, &help_flag
, NULL
, NULL
}
267 arg_printusage (args
, sizeof(args
)/sizeof(*args
),
268 NULL
, "service@host");
273 main(int argc
, char **argv
)
276 OM_uint32 min_stat
, maj_stat
;
277 gss_ctx_id_t cctx
, sctx
;
279 gss_OID nameoid
, mechoid
, actual_mech
;
280 gss_cred_id_t deleg_cred
= GSS_C_NO_CREDENTIAL
;
282 setprogname(argv
[0]);
284 cctx
= sctx
= GSS_C_NO_CONTEXT
;
286 if(getarg(args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optind
))
303 if (dns_canon_flag
!= -1)
304 gsskrb5_set_dns_canonicalize(dns_canon_flag
);
306 if (type_string
== NULL
)
307 nameoid
= GSS_C_NT_HOSTBASED_SERVICE
;
308 else if (strcmp(type_string
, "hostbased-service") == 0)
309 nameoid
= GSS_C_NT_HOSTBASED_SERVICE
;
310 else if (strcmp(type_string
, "krb5-principal-name") == 0)
311 nameoid
= GSS_KRB5_NT_PRINCIPAL_NAME
;
313 errx(1, "%s not suppported", type_string
);
315 if (mech_string
== NULL
)
316 mechoid
= GSS_KRB5_MECHANISM
;
318 mechoid
= string_to_oid(mech_string
);
320 if (gsskrb5_acceptor_identity
)
321 gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity
);
323 loop(mechoid
, nameoid
, argv
[0], GSS_C_NO_CREDENTIAL
,
324 &sctx
, &cctx
, &actual_mech
, &deleg_cred
);
327 printf("resulting mech: %s\n", oid_to_string(actual_mech
));
329 if (ret_mech_string
) {
332 retoid
= string_to_oid(ret_mech_string
);
334 if (gss_oid_equal(retoid
, actual_mech
) == 0)
335 errx(1, "actual_mech mech is not the expected type %s",
339 /* XXX should be actual_mech */
340 if (gss_oid_equal(mechoid
, GSS_KRB5_MECHANISM
)) {
341 krb5_context context
;
343 gss_buffer_desc authz_data
;
344 gss_buffer_desc in
, out1
, out2
;
345 krb5_keyblock
*keyblock
, *keyblock2
;
349 ret
= krb5_init_context(&context
);
351 errx(1, "krb5_init_context");
353 ret
= krb5_timeofday(context
, &now
);
355 errx(1, "krb5_timeofday failed");
358 maj_stat
= gss_krb5_export_lucid_sec_context(&min_stat
,
362 if (maj_stat
!= GSS_S_COMPLETE
)
363 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
364 gssapi_err(maj_stat
, min_stat
, actual_mech
));
367 maj_stat
= gss_krb5_free_lucid_sec_context(&maj_stat
, ctx
);
368 if (maj_stat
!= GSS_S_COMPLETE
)
369 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
370 gssapi_err(maj_stat
, min_stat
, actual_mech
));
373 maj_stat
= gss_krb5_export_lucid_sec_context(&min_stat
,
377 if (maj_stat
!= GSS_S_COMPLETE
)
378 errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
379 gssapi_err(maj_stat
, min_stat
, actual_mech
));
380 maj_stat
= gss_krb5_free_lucid_sec_context(&min_stat
, ctx
);
381 if (maj_stat
!= GSS_S_COMPLETE
)
382 errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
383 gssapi_err(maj_stat
, min_stat
, actual_mech
));
385 maj_stat
= gsskrb5_extract_authtime_from_sec_context(&min_stat
,
388 if (maj_stat
!= GSS_S_COMPLETE
)
389 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
390 gssapi_err(maj_stat
, min_stat
, actual_mech
));
392 skew
= abs(time
- now
);
393 if (skew
> krb5_get_max_time_skew(context
)) {
394 errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
395 "time skew too great %llu > %llu",
396 (unsigned long long)skew
,
397 (unsigned long long)krb5_get_max_time_skew(context
));
400 maj_stat
= gsskrb5_extract_service_keyblock(&min_stat
,
403 if (maj_stat
!= GSS_S_COMPLETE
)
404 errx(1, "gsskrb5_export_service_keyblock failed: %s",
405 gssapi_err(maj_stat
, min_stat
, actual_mech
));
407 krb5_free_keyblock(context
, keyblock
);
409 maj_stat
= gsskrb5_get_subkey(&min_stat
,
412 if (maj_stat
!= GSS_S_COMPLETE
413 && (!(maj_stat
== GSS_S_FAILURE
&& min_stat
== GSS_KRB5_S_KG_NO_SUBKEY
)))
414 errx(1, "gsskrb5_get_subkey server failed: %s",
415 gssapi_err(maj_stat
, min_stat
, actual_mech
));
417 if (maj_stat
!= GSS_S_COMPLETE
)
420 maj_stat
= gsskrb5_get_subkey(&min_stat
,
423 if (maj_stat
!= GSS_S_COMPLETE
424 && (!(maj_stat
== GSS_S_FAILURE
&& min_stat
== GSS_KRB5_S_KG_NO_SUBKEY
)))
425 errx(1, "gsskrb5_get_subkey client failed: %s",
426 gssapi_err(maj_stat
, min_stat
, actual_mech
));
428 if (maj_stat
!= GSS_S_COMPLETE
)
431 if (keyblock
|| keyblock2
) {
432 if (keyblock
== NULL
)
433 errx(1, "server missing token keyblock");
434 if (keyblock2
== NULL
)
435 errx(1, "client missing token keyblock");
437 if (keyblock
->keytype
!= keyblock2
->keytype
)
438 errx(1, "enctype mismatch");
439 if (keyblock
->keyvalue
.length
!= keyblock2
->keyvalue
.length
)
440 errx(1, "key length mismatch");
441 if (memcmp(keyblock
->keyvalue
.data
, keyblock2
->keyvalue
.data
,
442 keyblock2
->keyvalue
.length
) != 0)
443 errx(1, "key data mismatch");
447 krb5_free_keyblock(context
, keyblock
);
449 krb5_free_keyblock(context
, keyblock2
);
451 maj_stat
= gsskrb5_get_initiator_subkey(&min_stat
,
454 if (maj_stat
!= GSS_S_COMPLETE
455 && (!(maj_stat
== GSS_S_FAILURE
&& min_stat
== GSS_KRB5_S_KG_NO_SUBKEY
)))
456 errx(1, "gsskrb5_get_initiator_subkey failed: %s",
457 gssapi_err(maj_stat
, min_stat
, actual_mech
));
459 if (maj_stat
== GSS_S_COMPLETE
)
460 krb5_free_keyblock(context
, keyblock
);
462 maj_stat
= gsskrb5_extract_authz_data_from_sec_context(&min_stat
,
466 if (maj_stat
== GSS_S_COMPLETE
)
467 gss_release_buffer(&min_stat
, &authz_data
);
469 krb5_free_context(context
);
472 memset(&out1
, 0, sizeof(out1
));
473 memset(&out2
, 0, sizeof(out2
));
478 gss_pseudo_random(&min_stat
, sctx
, GSS_C_PRF_KEY_FULL
, &in
,
480 gss_pseudo_random(&min_stat
, cctx
, GSS_C_PRF_KEY_FULL
, &in
,
483 if (out1
.length
!= out2
.length
)
484 errx(1, "prf len mismatch");
485 if (memcmp(out1
.value
, out2
.value
, out1
.length
) != 0)
486 errx(1, "prf data mismatch");
488 gss_release_buffer(&min_stat
, &out1
);
490 gss_pseudo_random(&min_stat
, sctx
, GSS_C_PRF_KEY_FULL
, &in
,
493 if (out1
.length
!= out2
.length
)
494 errx(1, "prf len mismatch");
495 if (memcmp(out1
.value
, out2
.value
, out1
.length
) != 0)
496 errx(1, "prf data mismatch");
498 gss_release_buffer(&min_stat
, &out1
);
499 gss_release_buffer(&min_stat
, &out2
);
504 gss_pseudo_random(&min_stat
, sctx
, GSS_C_PRF_KEY_PARTIAL
, &in
,
506 gss_pseudo_random(&min_stat
, cctx
, GSS_C_PRF_KEY_PARTIAL
, &in
,
509 if (out1
.length
!= out2
.length
)
510 errx(1, "prf len mismatch");
511 if (memcmp(out1
.value
, out2
.value
, out1
.length
) != 0)
512 errx(1, "prf data mismatch");
514 gss_release_buffer(&min_stat
, &out1
);
515 gss_release_buffer(&min_stat
, &out2
);
518 getverifymic_flag
= 1;
521 if (wrapunwrap_flag
) {
522 wrapunwrap(cctx
, sctx
, actual_mech
);
523 wrapunwrap(cctx
, sctx
, actual_mech
);
524 wrapunwrap(sctx
, cctx
, actual_mech
);
525 wrapunwrap(sctx
, cctx
, actual_mech
);
527 if (getverifymic_flag
) {
528 getverifymic(cctx
, sctx
, actual_mech
);
529 getverifymic(cctx
, sctx
, actual_mech
);
530 getverifymic(sctx
, cctx
, actual_mech
);
531 getverifymic(sctx
, cctx
, actual_mech
);
534 gss_delete_sec_context(&min_stat
, &cctx
, NULL
);
535 gss_delete_sec_context(&min_stat
, &sctx
, NULL
);
537 if (deleg_cred
!= GSS_C_NO_CREDENTIAL
) {
539 loop(mechoid
, nameoid
, argv
[0], deleg_cred
, &cctx
, &sctx
, &actual_mech
, NULL
);
541 gss_delete_sec_context(&min_stat
, &cctx
, NULL
);
542 gss_delete_sec_context(&min_stat
, &sctx
, NULL
);