/crypto/heimdal/lib/gssapi/test_context.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 970 lines · 756 code · 172 blank · 42 comment · 213 complexity · 2704fa17d924722cc3f24736124de54e MD5 · raw file

  1. /*
  2. * Copyright (c) 2006 - 2008 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. #include "krb5/gsskrb5_locl.h"
  34. #include <err.h>
  35. #include <getarg.h>
  36. #include <gssapi.h>
  37. #include <gssapi_krb5.h>
  38. #include <gssapi_spnego.h>
  39. #include <gssapi_ntlm.h>
  40. #include "test_common.h"
  41. static char *type_string;
  42. static char *mech_string;
  43. static char *ret_mech_string;
  44. static char *client_name;
  45. static char *client_password;
  46. static int dns_canon_flag = -1;
  47. static int mutual_auth_flag = 0;
  48. static int dce_style_flag = 0;
  49. static int wrapunwrap_flag = 0;
  50. static int iov_flag = 0;
  51. static int getverifymic_flag = 0;
  52. static int deleg_flag = 0;
  53. static int policy_deleg_flag = 0;
  54. static int server_no_deleg_flag = 0;
  55. static int ei_flag = 0;
  56. static char *gsskrb5_acceptor_identity = NULL;
  57. static char *session_enctype_string = NULL;
  58. static int client_time_offset = 0;
  59. static int server_time_offset = 0;
  60. static int max_loops = 0;
  61. static char *limit_enctype_string = NULL;
  62. static int version_flag = 0;
  63. static int verbose_flag = 0;
  64. static int help_flag = 0;
  65. static krb5_context context;
  66. static krb5_enctype limit_enctype = 0;
  67. static struct {
  68. const char *name;
  69. gss_OID oid;
  70. } o2n[] = {
  71. { "krb5", NULL /* GSS_KRB5_MECHANISM */ },
  72. { "spnego", NULL /* GSS_SPNEGO_MECHANISM */ },
  73. { "ntlm", NULL /* GSS_NTLM_MECHANISM */ },
  74. { "sasl-digest-md5", NULL /* GSS_SASL_DIGEST_MD5_MECHANISM */ }
  75. };
  76. static void
  77. init_o2n(void)
  78. {
  79. o2n[0].oid = GSS_KRB5_MECHANISM;
  80. o2n[1].oid = GSS_SPNEGO_MECHANISM;
  81. o2n[2].oid = GSS_NTLM_MECHANISM;
  82. o2n[3].oid = GSS_SASL_DIGEST_MD5_MECHANISM;
  83. }
  84. static gss_OID
  85. string_to_oid(const char *name)
  86. {
  87. int i;
  88. for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
  89. if (strcasecmp(name, o2n[i].name) == 0)
  90. return o2n[i].oid;
  91. errx(1, "name '%s' not unknown", name);
  92. }
  93. static const char *
  94. oid_to_string(const gss_OID oid)
  95. {
  96. int i;
  97. for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
  98. if (gss_oid_equal(oid, o2n[i].oid))
  99. return o2n[i].name;
  100. return "unknown oid";
  101. }
  102. static void
  103. loop(gss_OID mechoid,
  104. gss_OID nameoid, const char *target,
  105. gss_cred_id_t init_cred,
  106. gss_ctx_id_t *sctx, gss_ctx_id_t *cctx,
  107. gss_OID *actual_mech,
  108. gss_cred_id_t *deleg_cred)
  109. {
  110. int server_done = 0, client_done = 0;
  111. int num_loops = 0;
  112. OM_uint32 maj_stat, min_stat;
  113. gss_name_t gss_target_name;
  114. gss_buffer_desc input_token, output_token;
  115. OM_uint32 flags = 0, ret_cflags, ret_sflags;
  116. gss_OID actual_mech_client;
  117. gss_OID actual_mech_server;
  118. *actual_mech = GSS_C_NO_OID;
  119. flags |= GSS_C_INTEG_FLAG;
  120. flags |= GSS_C_CONF_FLAG;
  121. if (mutual_auth_flag)
  122. flags |= GSS_C_MUTUAL_FLAG;
  123. if (dce_style_flag)
  124. flags |= GSS_C_DCE_STYLE;
  125. if (deleg_flag)
  126. flags |= GSS_C_DELEG_FLAG;
  127. if (policy_deleg_flag)
  128. flags |= GSS_C_DELEG_POLICY_FLAG;
  129. input_token.value = rk_UNCONST(target);
  130. input_token.length = strlen(target);
  131. maj_stat = gss_import_name(&min_stat,
  132. &input_token,
  133. nameoid,
  134. &gss_target_name);
  135. if (GSS_ERROR(maj_stat))
  136. err(1, "import name creds failed with: %d", maj_stat);
  137. input_token.length = 0;
  138. input_token.value = NULL;
  139. while (!server_done || !client_done) {
  140. num_loops++;
  141. gsskrb5_set_time_offset(client_time_offset);
  142. maj_stat = gss_init_sec_context(&min_stat,
  143. init_cred,
  144. cctx,
  145. gss_target_name,
  146. mechoid,
  147. flags,
  148. 0,
  149. NULL,
  150. &input_token,
  151. &actual_mech_client,
  152. &output_token,
  153. &ret_cflags,
  154. NULL);
  155. if (GSS_ERROR(maj_stat))
  156. errx(1, "init_sec_context: %s",
  157. gssapi_err(maj_stat, min_stat, mechoid));
  158. if (maj_stat & GSS_S_CONTINUE_NEEDED)
  159. ;
  160. else
  161. client_done = 1;
  162. gsskrb5_get_time_offset(&client_time_offset);
  163. if (client_done && server_done)
  164. break;
  165. if (input_token.length != 0)
  166. gss_release_buffer(&min_stat, &input_token);
  167. gsskrb5_set_time_offset(server_time_offset);
  168. maj_stat = gss_accept_sec_context(&min_stat,
  169. sctx,
  170. GSS_C_NO_CREDENTIAL,
  171. &output_token,
  172. GSS_C_NO_CHANNEL_BINDINGS,
  173. NULL,
  174. &actual_mech_server,
  175. &input_token,
  176. &ret_sflags,
  177. NULL,
  178. deleg_cred);
  179. if (GSS_ERROR(maj_stat))
  180. errx(1, "accept_sec_context: %s",
  181. gssapi_err(maj_stat, min_stat, actual_mech_server));
  182. gsskrb5_get_time_offset(&server_time_offset);
  183. if (output_token.length != 0)
  184. gss_release_buffer(&min_stat, &output_token);
  185. if (maj_stat & GSS_S_CONTINUE_NEEDED)
  186. ;
  187. else
  188. server_done = 1;
  189. }
  190. if (output_token.length != 0)
  191. gss_release_buffer(&min_stat, &output_token);
  192. if (input_token.length != 0)
  193. gss_release_buffer(&min_stat, &input_token);
  194. gss_release_name(&min_stat, &gss_target_name);
  195. if (deleg_flag || policy_deleg_flag) {
  196. if (server_no_deleg_flag) {
  197. if (*deleg_cred != GSS_C_NO_CREDENTIAL)
  198. errx(1, "got delegated cred but didn't expect one");
  199. } else if (*deleg_cred == GSS_C_NO_CREDENTIAL)
  200. errx(1, "asked for delegarated cred but did get one");
  201. } else if (*deleg_cred != GSS_C_NO_CREDENTIAL)
  202. errx(1, "got deleg_cred cred but didn't ask");
  203. if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)
  204. errx(1, "mech mismatch");
  205. *actual_mech = actual_mech_server;
  206. if (max_loops && num_loops > max_loops)
  207. errx(1, "num loops %d was lager then max loops %d",
  208. num_loops, max_loops);
  209. if (verbose_flag) {
  210. printf("server time offset: %d\n", server_time_offset);
  211. printf("client time offset: %d\n", client_time_offset);
  212. printf("num loops %d\n", num_loops);
  213. }
  214. }
  215. static void
  216. wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
  217. {
  218. gss_buffer_desc input_token, output_token, output_token2;
  219. OM_uint32 min_stat, maj_stat;
  220. gss_qop_t qop_state;
  221. int conf_state;
  222. input_token.value = "foo";
  223. input_token.length = 3;
  224. maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token,
  225. &conf_state, &output_token);
  226. if (maj_stat != GSS_S_COMPLETE)
  227. errx(1, "gss_wrap failed: %s",
  228. gssapi_err(maj_stat, min_stat, mechoid));
  229. maj_stat = gss_unwrap(&min_stat, sctx, &output_token,
  230. &output_token2, &conf_state, &qop_state);
  231. if (maj_stat != GSS_S_COMPLETE)
  232. errx(1, "gss_unwrap failed: %s",
  233. gssapi_err(maj_stat, min_stat, mechoid));
  234. gss_release_buffer(&min_stat, &output_token);
  235. gss_release_buffer(&min_stat, &output_token2);
  236. #if 0 /* doesn't work for NTLM yet */
  237. if (!!conf_state != !!flags)
  238. errx(1, "conf_state mismatch");
  239. #endif
  240. }
  241. #define USE_CONF 1
  242. #define USE_HEADER_ONLY 2
  243. #define USE_SIGN_ONLY 4
  244. #define FORCE_IOV 8
  245. static void
  246. wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
  247. {
  248. krb5_data token, header, trailer;
  249. OM_uint32 min_stat, maj_stat;
  250. gss_qop_t qop_state;
  251. int conf_state, conf_state2;
  252. gss_iov_buffer_desc iov[6];
  253. unsigned char *p;
  254. int iov_len;
  255. char header_data[9] = "ABCheader";
  256. char trailer_data[10] = "trailerXYZ";
  257. char token_data[16] = "0123456789abcdef";
  258. memset(&iov, 0, sizeof(iov));
  259. if (flags & USE_SIGN_ONLY) {
  260. header.data = header_data;
  261. header.length = 9;
  262. trailer.data = trailer_data;
  263. trailer.length = 10;
  264. } else {
  265. header.data = NULL;
  266. header.length = 0;
  267. trailer.data = NULL;
  268. trailer.length = 0;
  269. }
  270. token.data = token_data;
  271. token.length = 16;
  272. iov_len = sizeof(iov)/sizeof(iov[0]);
  273. memset(iov, 0, sizeof(iov));
  274. iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
  275. if (header.length != 0) {
  276. iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
  277. iov[1].buffer.length = header.length;
  278. iov[1].buffer.value = header.data;
  279. } else {
  280. iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
  281. iov[1].buffer.length = 0;
  282. iov[1].buffer.value = NULL;
  283. }
  284. iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
  285. iov[2].buffer.length = token.length;
  286. iov[2].buffer.value = token.data;
  287. if (trailer.length != 0) {
  288. iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
  289. iov[3].buffer.length = trailer.length;
  290. iov[3].buffer.value = trailer.data;
  291. } else {
  292. iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
  293. iov[3].buffer.length = 0;
  294. iov[3].buffer.value = NULL;
  295. }
  296. if (dce_style_flag) {
  297. iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY;
  298. } else {
  299. iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
  300. }
  301. iov[4].buffer.length = 0;
  302. iov[4].buffer.value = 0;
  303. if (dce_style_flag) {
  304. iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
  305. } else if (flags & USE_HEADER_ONLY) {
  306. iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
  307. } else {
  308. iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
  309. }
  310. iov[5].buffer.length = 0;
  311. iov[5].buffer.value = 0;
  312. maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state,
  313. iov, iov_len);
  314. if (maj_stat != GSS_S_COMPLETE)
  315. errx(1, "gss_wrap_iov failed");
  316. token.length =
  317. iov[0].buffer.length +
  318. iov[1].buffer.length +
  319. iov[2].buffer.length +
  320. iov[3].buffer.length +
  321. iov[4].buffer.length +
  322. iov[5].buffer.length;
  323. token.data = emalloc(token.length);
  324. p = token.data;
  325. memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
  326. p += iov[0].buffer.length;
  327. memcpy(p, iov[1].buffer.value, iov[1].buffer.length);
  328. p += iov[1].buffer.length;
  329. memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
  330. p += iov[2].buffer.length;
  331. memcpy(p, iov[3].buffer.value, iov[3].buffer.length);
  332. p += iov[3].buffer.length;
  333. memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
  334. p += iov[4].buffer.length;
  335. memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
  336. p += iov[5].buffer.length;
  337. assert(p - ((unsigned char *)token.data) == token.length);
  338. if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
  339. gss_buffer_desc input, output;
  340. input.value = token.data;
  341. input.length = token.length;
  342. maj_stat = gss_unwrap(&min_stat, sctx, &input,
  343. &output, &conf_state2, &qop_state);
  344. if (maj_stat != GSS_S_COMPLETE)
  345. errx(1, "gss_unwrap from gss_wrap_iov failed: %s",
  346. gssapi_err(maj_stat, min_stat, mechoid));
  347. gss_release_buffer(&min_stat, &output);
  348. } else {
  349. maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state,
  350. iov, iov_len);
  351. if (maj_stat != GSS_S_COMPLETE)
  352. errx(1, "gss_unwrap_iov failed: %x %s", flags,
  353. gssapi_err(maj_stat, min_stat, mechoid));
  354. }
  355. if (conf_state2 != conf_state)
  356. errx(1, "conf state wrong for iov: %x", flags);
  357. free(token.data);
  358. }
  359. static void
  360. getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
  361. {
  362. gss_buffer_desc input_token, output_token;
  363. OM_uint32 min_stat, maj_stat;
  364. gss_qop_t qop_state;
  365. input_token.value = "bar";
  366. input_token.length = 3;
  367. maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
  368. &output_token);
  369. if (maj_stat != GSS_S_COMPLETE)
  370. errx(1, "gss_get_mic failed: %s",
  371. gssapi_err(maj_stat, min_stat, mechoid));
  372. maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
  373. &output_token, &qop_state);
  374. if (maj_stat != GSS_S_COMPLETE)
  375. errx(1, "gss_verify_mic failed: %s",
  376. gssapi_err(maj_stat, min_stat, mechoid));
  377. gss_release_buffer(&min_stat, &output_token);
  378. }
  379. static void
  380. empty_release(void)
  381. {
  382. gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
  383. gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
  384. gss_name_t name = GSS_C_NO_NAME;
  385. gss_OID_set oidset = GSS_C_NO_OID_SET;
  386. OM_uint32 junk;
  387. gss_delete_sec_context(&junk, &ctx, NULL);
  388. gss_release_cred(&junk, &cred);
  389. gss_release_name(&junk, &name);
  390. gss_release_oid_set(&junk, &oidset);
  391. }
  392. /*
  393. *
  394. */
  395. static struct getargs args[] = {
  396. {"name-type",0, arg_string, &type_string, "type of name", NULL },
  397. {"mech-type",0, arg_string, &mech_string, "type of mech", NULL },
  398. {"ret-mech-type",0, arg_string, &ret_mech_string,
  399. "type of return mech", NULL },
  400. {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,
  401. "use dns to canonicalize", NULL },
  402. {"mutual-auth",0, arg_flag, &mutual_auth_flag,"mutual auth", NULL },
  403. {"client-name", 0, arg_string, &client_name, "client name", NULL },
  404. {"client-password", 0, arg_string, &client_password, "client password", NULL },
  405. {"limit-enctype",0, arg_string, &limit_enctype_string, "enctype", NULL },
  406. {"dce-style",0, arg_flag, &dce_style_flag, "dce-style", NULL },
  407. {"wrapunwrap",0, arg_flag, &wrapunwrap_flag, "wrap/unwrap", NULL },
  408. {"iov", 0, arg_flag, &iov_flag, "wrap/unwrap iov", NULL },
  409. {"getverifymic",0, arg_flag, &getverifymic_flag,
  410. "get and verify mic", NULL },
  411. {"delegate",0, arg_flag, &deleg_flag, "delegate credential", NULL },
  412. {"policy-delegate",0, arg_flag, &policy_deleg_flag, "policy delegate credential", NULL },
  413. {"server-no-delegate",0, arg_flag, &server_no_deleg_flag,
  414. "server should get a credential", NULL },
  415. {"export-import-cred",0, arg_flag, &ei_flag, "test export/import cred", NULL },
  416. {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL },
  417. {"session-enctype", 0, arg_string, &session_enctype_string, "enctype", NULL },
  418. {"client-time-offset", 0, arg_integer, &client_time_offset, "time", NULL },
  419. {"server-time-offset", 0, arg_integer, &server_time_offset, "time", NULL },
  420. {"max-loops", 0, arg_integer, &max_loops, "time", NULL },
  421. {"version", 0, arg_flag, &version_flag, "print version", NULL },
  422. {"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL },
  423. {"help", 0, arg_flag, &help_flag, NULL, NULL }
  424. };
  425. static void
  426. usage (int ret)
  427. {
  428. arg_printusage (args, sizeof(args)/sizeof(*args),
  429. NULL, "service@host");
  430. exit (ret);
  431. }
  432. int
  433. main(int argc, char **argv)
  434. {
  435. int optind = 0;
  436. OM_uint32 min_stat, maj_stat;
  437. gss_ctx_id_t cctx, sctx;
  438. void *ctx;
  439. gss_OID nameoid, mechoid, actual_mech, actual_mech2;
  440. gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL;
  441. gss_name_t cname = GSS_C_NO_NAME;
  442. gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;
  443. setprogname(argv[0]);
  444. init_o2n();
  445. if (krb5_init_context(&context))
  446. errx(1, "krb5_init_context");
  447. cctx = sctx = GSS_C_NO_CONTEXT;
  448. if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
  449. usage(1);
  450. if (help_flag)
  451. usage (0);
  452. if(version_flag){
  453. print_version(NULL);
  454. exit(0);
  455. }
  456. argc -= optind;
  457. argv += optind;
  458. if (argc != 1)
  459. usage(1);
  460. if (dns_canon_flag != -1)
  461. gsskrb5_set_dns_canonicalize(dns_canon_flag);
  462. if (type_string == NULL)
  463. nameoid = GSS_C_NT_HOSTBASED_SERVICE;
  464. else if (strcmp(type_string, "hostbased-service") == 0)
  465. nameoid = GSS_C_NT_HOSTBASED_SERVICE;
  466. else if (strcmp(type_string, "krb5-principal-name") == 0)
  467. nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
  468. else
  469. errx(1, "%s not suppported", type_string);
  470. if (mech_string == NULL)
  471. mechoid = GSS_KRB5_MECHANISM;
  472. else
  473. mechoid = string_to_oid(mech_string);
  474. if (gsskrb5_acceptor_identity) {
  475. maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity);
  476. if (maj_stat)
  477. errx(1, "gsskrb5_acceptor_identity: %s",
  478. gssapi_err(maj_stat, 0, GSS_C_NO_OID));
  479. }
  480. if (client_password) {
  481. credential_data.value = client_password;
  482. credential_data.length = strlen(client_password);
  483. }
  484. if (client_name) {
  485. gss_buffer_desc cn;
  486. cn.value = client_name;
  487. cn.length = strlen(client_name);
  488. maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
  489. if (maj_stat)
  490. errx(1, "gss_import_name: %s",
  491. gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
  492. }
  493. if (client_password) {
  494. maj_stat = gss_acquire_cred_with_password(&min_stat,
  495. cname,
  496. &credential_data,
  497. GSS_C_INDEFINITE,
  498. GSS_C_NO_OID_SET,
  499. GSS_C_INITIATE,
  500. &client_cred,
  501. NULL,
  502. NULL);
  503. if (GSS_ERROR(maj_stat))
  504. errx(1, "gss_acquire_cred_with_password: %s",
  505. gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
  506. } else {
  507. maj_stat = gss_acquire_cred(&min_stat,
  508. cname,
  509. GSS_C_INDEFINITE,
  510. GSS_C_NO_OID_SET,
  511. GSS_C_INITIATE,
  512. &client_cred,
  513. NULL,
  514. NULL);
  515. if (GSS_ERROR(maj_stat))
  516. errx(1, "gss_acquire_cred: %s",
  517. gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
  518. }
  519. if (limit_enctype_string) {
  520. krb5_error_code ret;
  521. ret = krb5_string_to_enctype(context,
  522. limit_enctype_string,
  523. &limit_enctype);
  524. if (ret)
  525. krb5_err(context, 1, ret, "krb5_string_to_enctype");
  526. }
  527. if (limit_enctype) {
  528. if (client_cred == NULL)
  529. errx(1, "client_cred missing");
  530. maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred,
  531. 1, &limit_enctype);
  532. if (maj_stat)
  533. errx(1, "gss_krb5_set_allowable_enctypes: %s",
  534. gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
  535. }
  536. loop(mechoid, nameoid, argv[0], client_cred,
  537. &sctx, &cctx, &actual_mech, &deleg_cred);
  538. if (verbose_flag)
  539. printf("resulting mech: %s\n", oid_to_string(actual_mech));
  540. if (ret_mech_string) {
  541. gss_OID retoid;
  542. retoid = string_to_oid(ret_mech_string);
  543. if (gss_oid_equal(retoid, actual_mech) == 0)
  544. errx(1, "actual_mech mech is not the expected type %s",
  545. ret_mech_string);
  546. }
  547. /* XXX should be actual_mech */
  548. if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) {
  549. time_t time;
  550. gss_buffer_desc authz_data;
  551. gss_buffer_desc in, out1, out2;
  552. krb5_keyblock *keyblock, *keyblock2;
  553. krb5_timestamp now;
  554. krb5_error_code ret;
  555. ret = krb5_timeofday(context, &now);
  556. if (ret)
  557. errx(1, "krb5_timeofday failed");
  558. /* client */
  559. maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
  560. &cctx,
  561. 1, /* version */
  562. &ctx);
  563. if (maj_stat != GSS_S_COMPLETE)
  564. errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
  565. gssapi_err(maj_stat, min_stat, actual_mech));
  566. maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
  567. if (maj_stat != GSS_S_COMPLETE)
  568. errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
  569. gssapi_err(maj_stat, min_stat, actual_mech));
  570. /* server */
  571. maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
  572. &sctx,
  573. 1, /* version */
  574. &ctx);
  575. if (maj_stat != GSS_S_COMPLETE)
  576. errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
  577. gssapi_err(maj_stat, min_stat, actual_mech));
  578. maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
  579. if (maj_stat != GSS_S_COMPLETE)
  580. errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
  581. gssapi_err(maj_stat, min_stat, actual_mech));
  582. maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
  583. sctx,
  584. &time);
  585. if (maj_stat != GSS_S_COMPLETE)
  586. errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
  587. gssapi_err(maj_stat, min_stat, actual_mech));
  588. if (time > now)
  589. errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
  590. "time authtime is before now: %ld %ld",
  591. (long)time, (long)now);
  592. maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
  593. sctx,
  594. &keyblock);
  595. if (maj_stat != GSS_S_COMPLETE)
  596. errx(1, "gsskrb5_export_service_keyblock failed: %s",
  597. gssapi_err(maj_stat, min_stat, actual_mech));
  598. krb5_free_keyblock(context, keyblock);
  599. maj_stat = gsskrb5_get_subkey(&min_stat,
  600. sctx,
  601. &keyblock);
  602. if (maj_stat != GSS_S_COMPLETE
  603. && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
  604. errx(1, "gsskrb5_get_subkey server failed: %s",
  605. gssapi_err(maj_stat, min_stat, actual_mech));
  606. if (maj_stat != GSS_S_COMPLETE)
  607. keyblock = NULL;
  608. else if (limit_enctype && keyblock->keytype != limit_enctype)
  609. errx(1, "gsskrb5_get_subkey wrong enctype");
  610. maj_stat = gsskrb5_get_subkey(&min_stat,
  611. cctx,
  612. &keyblock2);
  613. if (maj_stat != GSS_S_COMPLETE
  614. && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
  615. errx(1, "gsskrb5_get_subkey client failed: %s",
  616. gssapi_err(maj_stat, min_stat, actual_mech));
  617. if (maj_stat != GSS_S_COMPLETE)
  618. keyblock2 = NULL;
  619. else if (limit_enctype && keyblock->keytype != limit_enctype)
  620. errx(1, "gsskrb5_get_subkey wrong enctype");
  621. if (keyblock || keyblock2) {
  622. if (keyblock == NULL)
  623. errx(1, "server missing token keyblock");
  624. if (keyblock2 == NULL)
  625. errx(1, "client missing token keyblock");
  626. if (keyblock->keytype != keyblock2->keytype)
  627. errx(1, "enctype mismatch");
  628. if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
  629. errx(1, "key length mismatch");
  630. if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,
  631. keyblock2->keyvalue.length) != 0)
  632. errx(1, "key data mismatch");
  633. }
  634. if (session_enctype_string) {
  635. krb5_enctype enctype;
  636. ret = krb5_string_to_enctype(context,
  637. session_enctype_string,
  638. &enctype);
  639. if (ret)
  640. krb5_err(context, 1, ret, "krb5_string_to_enctype");
  641. if (enctype != keyblock->keytype)
  642. errx(1, "keytype is not the expected %d != %d",
  643. (int)enctype, (int)keyblock2->keytype);
  644. }
  645. if (keyblock)
  646. krb5_free_keyblock(context, keyblock);
  647. if (keyblock2)
  648. krb5_free_keyblock(context, keyblock2);
  649. maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
  650. sctx,
  651. &keyblock);
  652. if (maj_stat != GSS_S_COMPLETE
  653. && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
  654. errx(1, "gsskrb5_get_initiator_subkey failed: %s",
  655. gssapi_err(maj_stat, min_stat, actual_mech));
  656. if (maj_stat == GSS_S_COMPLETE) {
  657. if (limit_enctype && keyblock->keytype != limit_enctype)
  658. errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
  659. krb5_free_keyblock(context, keyblock);
  660. }
  661. maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
  662. sctx,
  663. 128,
  664. &authz_data);
  665. if (maj_stat == GSS_S_COMPLETE)
  666. gss_release_buffer(&min_stat, &authz_data);
  667. memset(&out1, 0, sizeof(out1));
  668. memset(&out2, 0, sizeof(out2));
  669. in.value = "foo";
  670. in.length = 3;
  671. gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
  672. 100, &out1);
  673. gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
  674. 100, &out2);
  675. if (out1.length != out2.length)
  676. errx(1, "prf len mismatch");
  677. if (memcmp(out1.value, out2.value, out1.length) != 0)
  678. errx(1, "prf data mismatch");
  679. gss_release_buffer(&min_stat, &out1);
  680. gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
  681. 100, &out1);
  682. if (out1.length != out2.length)
  683. errx(1, "prf len mismatch");
  684. if (memcmp(out1.value, out2.value, out1.length) != 0)
  685. errx(1, "prf data mismatch");
  686. gss_release_buffer(&min_stat, &out1);
  687. gss_release_buffer(&min_stat, &out2);
  688. in.value = "bar";
  689. in.length = 3;
  690. gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
  691. 100, &out1);
  692. gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
  693. 100, &out2);
  694. if (out1.length != out2.length)
  695. errx(1, "prf len mismatch");
  696. if (memcmp(out1.value, out2.value, out1.length) != 0)
  697. errx(1, "prf data mismatch");
  698. gss_release_buffer(&min_stat, &out1);
  699. gss_release_buffer(&min_stat, &out2);
  700. wrapunwrap_flag = 1;
  701. getverifymic_flag = 1;
  702. }
  703. if (wrapunwrap_flag) {
  704. wrapunwrap(cctx, sctx, 0, actual_mech);
  705. wrapunwrap(cctx, sctx, 1, actual_mech);
  706. wrapunwrap(sctx, cctx, 0, actual_mech);
  707. wrapunwrap(sctx, cctx, 1, actual_mech);
  708. }
  709. if (iov_flag) {
  710. wrapunwrap_iov(cctx, sctx, 0, actual_mech);
  711. wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
  712. wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
  713. wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
  714. wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
  715. wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
  716. wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
  717. wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
  718. wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
  719. wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
  720. wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
  721. wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
  722. /* works */
  723. wrapunwrap_iov(cctx, sctx, 0, actual_mech);
  724. wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
  725. wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
  726. wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
  727. wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech);
  728. wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
  729. wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
  730. wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
  731. wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
  732. wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
  733. wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
  734. wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
  735. }
  736. if (getverifymic_flag) {
  737. getverifymic(cctx, sctx, actual_mech);
  738. getverifymic(cctx, sctx, actual_mech);
  739. getverifymic(sctx, cctx, actual_mech);
  740. getverifymic(sctx, cctx, actual_mech);
  741. }
  742. gss_delete_sec_context(&min_stat, &cctx, NULL);
  743. gss_delete_sec_context(&min_stat, &sctx, NULL);
  744. if (deleg_cred != GSS_C_NO_CREDENTIAL) {
  745. gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
  746. gss_buffer_desc cb;
  747. if (verbose_flag)
  748. printf("checking actual mech (%s) on delegated cred\n",
  749. oid_to_string(actual_mech));
  750. loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2);
  751. gss_delete_sec_context(&min_stat, &cctx, NULL);
  752. gss_delete_sec_context(&min_stat, &sctx, NULL);
  753. gss_release_cred(&min_stat, &cred2);
  754. /* try again using SPNEGO */
  755. if (verbose_flag)
  756. printf("checking spnego on delegated cred\n");
  757. loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], deleg_cred, &sctx, &cctx,
  758. &actual_mech2, &cred2);
  759. gss_delete_sec_context(&min_stat, &cctx, NULL);
  760. gss_delete_sec_context(&min_stat, &sctx, NULL);
  761. gss_release_cred(&min_stat, &cred2);
  762. /* check export/import */
  763. if (ei_flag) {
  764. maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb);
  765. if (maj_stat != GSS_S_COMPLETE)
  766. errx(1, "export failed: %s",
  767. gssapi_err(maj_stat, min_stat, NULL));
  768. maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
  769. if (maj_stat != GSS_S_COMPLETE)
  770. errx(1, "import failed: %s",
  771. gssapi_err(maj_stat, min_stat, NULL));
  772. gss_release_buffer(&min_stat, &cb);
  773. gss_release_cred(&min_stat, &deleg_cred);
  774. if (verbose_flag)
  775. printf("checking actual mech (%s) on export/imported cred\n",
  776. oid_to_string(actual_mech));
  777. loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx,
  778. &actual_mech2, &deleg_cred);
  779. gss_release_cred(&min_stat, &deleg_cred);
  780. gss_delete_sec_context(&min_stat, &cctx, NULL);
  781. gss_delete_sec_context(&min_stat, &sctx, NULL);
  782. /* try again using SPNEGO */
  783. if (verbose_flag)
  784. printf("checking SPNEGO on export/imported cred\n");
  785. loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], cred2, &sctx, &cctx,
  786. &actual_mech2, &deleg_cred);
  787. gss_release_cred(&min_stat, &deleg_cred);
  788. gss_delete_sec_context(&min_stat, &cctx, NULL);
  789. gss_delete_sec_context(&min_stat, &sctx, NULL);
  790. gss_release_cred(&min_stat, &cred2);
  791. } else {
  792. gss_release_cred(&min_stat, &deleg_cred);
  793. }
  794. }
  795. empty_release();
  796. krb5_free_context(context);
  797. return 0;
  798. }