00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "kerberos_v5.h"
00027
00028
00029 #include <shishi.h>
00030
00031 #ifdef HAVE_NETINET_IN_H
00032 #include <netinet/in.h>
00033 #endif
00034
00035 #define DEBUG 0
00036
00037 #define BITMAP_LEN 1
00038 #define MAXBUF_LEN 4
00039 #define RANDOM_LEN 16
00040 #define MUTUAL (1 << 3)
00041
00042 #define SERVER_HELLO_LEN BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN
00043 #define CLIENT_HELLO_LEN BITMAP_LEN + MAXBUF_LEN
00044
00045 #define MAXBUF_DEFAULT 65536
00046
00047
00048
00049 #ifdef USE_CLIENT
00050
00051 struct _Gsasl_kerberos_v5_client_state
00052 {
00053 int step;
00054 char serverhello[BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN];
00055 int serverqops;
00056 int clientqop;
00057 int servermutual;
00058 uint32_t servermaxbuf;
00059 uint32_t clientmaxbuf;
00060 Shishi *sh;
00061 Shishi_tkt *tkt;
00062 Shishi_as *as;
00063 Shishi_ap *ap;
00064 Shishi_key *sessionkey;
00065 Shishi_safe *safe;
00066 };
00067
00068 int
00069 _gsasl_kerberos_v5_client_init (Gsasl_ctx * ctx)
00070 {
00071 if (!shishi_check_version (SHISHI_VERSION))
00072 return GSASL_UNKNOWN_MECHANISM;
00073
00074 return GSASL_OK;
00075 }
00076
00077 int
00078 _gsasl_kerberos_v5_client_start (Gsasl_session * sctx, void **mech_data)
00079 {
00080 struct _Gsasl_kerberos_v5_client_state *state;
00081 Gsasl_ctx *ctx;
00082 int err;
00083
00084 state = malloc (sizeof (*state));
00085 if (state == NULL)
00086 return GSASL_MALLOC_ERROR;
00087
00088 memset (state, 0, sizeof (*state));
00089
00090 err = shishi_init (&state->sh);
00091 if (err)
00092 return GSASL_KERBEROS_V5_INIT_ERROR;
00093
00094 state->step = 0;
00095 state->clientqop = GSASL_QOP_AUTH_INT;
00096
00097 *mech_data = state;
00098
00099 return GSASL_OK;
00100 }
00101
00102 #define STEP_FIRST 0
00103 #define STEP_NONINFRA_SEND_ASREQ 1
00104 #define STEP_NONINFRA_WAIT_ASREP 2
00105 #define STEP_NONINFRA_SEND_APREQ 3
00106 #define STEP_NONINFRA_WAIT_APREP 4
00107 #define STEP_SUCCESS 5
00108
00109 int
00110 _gsasl_kerberos_v5_client_step (Gsasl_session * sctx,
00111 void *mech_data,
00112 const char *input,
00113 size_t input_len,
00114 char *output, size_t * output_len)
00115 {
00116 struct _Gsasl_kerberos_v5_client_state *state = mech_data;
00117 Gsasl_client_callback_authentication_id cb_authentication_id;
00118 Gsasl_client_callback_authorization_id cb_authorization_id;
00119 Gsasl_client_callback_qop cb_qop;
00120 Gsasl_client_callback_realm cb_realm;
00121 Gsasl_client_callback_password cb_password;
00122 Gsasl_client_callback_service cb_service;
00123 Gsasl_client_callback_maxbuf cb_maxbuf;
00124 Gsasl_ctx *ctx;
00125 int res;
00126 int len;
00127
00128 ctx = gsasl_client_ctx_get (sctx);
00129 if (ctx == NULL)
00130 return GSASL_CANNOT_GET_CTX;
00131
00132
00133 cb_realm = gsasl_client_callback_realm_get (ctx);
00134 cb_service = gsasl_client_callback_service_get (ctx);
00135 cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx);
00136 cb_authorization_id = gsasl_client_callback_authorization_id_get (ctx);
00137 cb_qop = gsasl_client_callback_qop_get (ctx);
00138 cb_maxbuf = gsasl_client_callback_maxbuf_get (ctx);
00139
00140
00141 cb_password = gsasl_client_callback_password_get (ctx);
00142 if (cb_password == NULL)
00143 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
00144
00145
00146 cb_service = gsasl_client_callback_service_get (ctx);
00147 if (cb_service == NULL)
00148 return GSASL_NEED_CLIENT_SERVICE_CALLBACK;
00149
00150 switch (state->step)
00151 {
00152 case STEP_FIRST:
00153 if (input == NULL)
00154 {
00155 *output_len = 0;
00156 return GSASL_NEEDS_MORE;
00157 }
00158
00159 if (input_len != SERVER_HELLO_LEN)
00160 return GSASL_MECHANISM_PARSE_ERROR;
00161
00162 memcpy (state->serverhello, input, input_len);
00163
00164 {
00165 unsigned char serverbitmap;
00166
00167 memcpy (&serverbitmap, input, BITMAP_LEN);
00168 state->serverqops = 0;
00169 if (serverbitmap & GSASL_QOP_AUTH)
00170 state->serverqops |= GSASL_QOP_AUTH;
00171 if (serverbitmap & GSASL_QOP_AUTH_INT)
00172 state->serverqops |= GSASL_QOP_AUTH_INT;
00173 if (serverbitmap & GSASL_QOP_AUTH_CONF)
00174 state->serverqops |= GSASL_QOP_AUTH_CONF;
00175 if (serverbitmap & MUTUAL)
00176 state->servermutual = 1;
00177 }
00178 memcpy (&state->servermaxbuf, &input[BITMAP_LEN], MAXBUF_LEN);
00179 state->servermaxbuf = ntohl (state->servermaxbuf);
00180
00181 if (cb_qop)
00182 state->clientqop = cb_qop (sctx, state->serverqops);
00183
00184 if (!(state->serverqops & state->clientqop &
00185 (GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF)))
00186 return GSASL_AUTHENTICATION_ERROR;
00187
00188
00189 if (!state->servermutual)
00190 return GSASL_AUTHENTICATION_ERROR;
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 state->step = STEP_NONINFRA_SEND_APREQ;
00205
00206
00207 case STEP_NONINFRA_SEND_ASREQ:
00208 res = shishi_as (state->sh, &state->as);
00209 if (res)
00210 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00211
00212 if (cb_authentication_id)
00213 {
00214 len = *output_len - 1;
00215 res = cb_authentication_id (sctx, output, &len);
00216 if (res != GSASL_OK)
00217 return res;
00218 output[len] = '\0';
00219
00220 res = shishi_kdcreq_set_cname (state->sh, shishi_as_req (state->as),
00221 SHISHI_NT_UNKNOWN, output);
00222 if (res != GSASL_OK)
00223 return res;
00224 }
00225
00226 if (cb_realm)
00227 {
00228 len = *output_len - 1;
00229 res = cb_realm (sctx, output, &len);
00230 if (res != GSASL_OK)
00231 return res;
00232 }
00233 else
00234 len = 0;
00235
00236 output[len] = '\0';
00237 res = shishi_kdcreq_set_realm (state->sh, shishi_as_req (state->as),
00238 output);
00239 if (res != GSASL_OK)
00240 return res;
00241
00242 if (cb_service)
00243 {
00244 char *sname[3];
00245 size_t servicelen = 0;
00246 size_t hostnamelen = 0;
00247
00248 res = cb_service (sctx, NULL, &servicelen, NULL, &hostnamelen,
00249
00250 NULL, NULL);
00251 if (res != GSASL_OK)
00252 return res;
00253
00254 if (*output_len < servicelen + 1 + hostnamelen + 1)
00255 return GSASL_TOO_SMALL_BUFFER;
00256
00257 sname[0] = &output[0];
00258 sname[1] = &output[servicelen + 2];
00259 sname[2] = NULL;
00260
00261 res = cb_service (sctx, sname[0], &servicelen,
00262 sname[1], &hostnamelen, NULL, NULL);
00263 if (res != GSASL_OK)
00264 return res;
00265
00266 sname[0][servicelen] = '\0';
00267 sname[1][hostnamelen] = '\0';
00268
00269 res = shishi_kdcreq_set_sname (state->sh, shishi_as_req (state->as),
00270 SHISHI_NT_UNKNOWN, sname);
00271 if (res != GSASL_OK)
00272 return res;
00273 }
00274
00275
00276
00277
00278 res = shishi_a2d (state->sh, shishi_as_req (state->as),
00279 output, output_len);
00280 if (res != SHISHI_OK)
00281 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00282
00283 state->step = STEP_NONINFRA_WAIT_ASREP;
00284
00285 res = GSASL_NEEDS_MORE;
00286 break;
00287
00288 case STEP_NONINFRA_WAIT_ASREP:
00289 if (shishi_as_rep_der_set (state->as, input, input_len) != SHISHI_OK)
00290 return GSASL_MECHANISM_PARSE_ERROR;
00291
00292
00293 len = *output_len - 1;
00294 res = cb_password (sctx, output, &len);
00295 if (res != GSASL_OK && res != GSASL_NEEDS_MORE)
00296 return res;
00297 output[len] = '\0';
00298
00299 res = shishi_as_rep_process (state->as, NULL, output);
00300 if (res != SHISHI_OK)
00301 return GSASL_AUTHENTICATION_ERROR;
00302
00303 state->step = STEP_NONINFRA_SEND_APREQ;
00304
00305
00306 case STEP_NONINFRA_SEND_APREQ:
00307 if (*output_len <= CLIENT_HELLO_LEN + SERVER_HELLO_LEN)
00308 return GSASL_TOO_SMALL_BUFFER;
00309
00310 if (!(state->clientqop & ~GSASL_QOP_AUTH))
00311 state->clientmaxbuf = 0;
00312 else if (cb_maxbuf)
00313 state->clientmaxbuf = cb_maxbuf (sctx, state->servermaxbuf);
00314 else
00315 state->clientmaxbuf = MAXBUF_DEFAULT;
00316
00317
00318 output[0] = state->clientqop | MUTUAL;
00319 {
00320 uint32_t tmp;
00321
00322 tmp = ntohl (state->clientmaxbuf);
00323 memcpy (&output[BITMAP_LEN], &tmp, MAXBUF_LEN);
00324 }
00325 memcpy (&output[CLIENT_HELLO_LEN], state->serverhello,
00326 SERVER_HELLO_LEN);
00327
00328 if (cb_authorization_id)
00329 {
00330 len = *output_len - CLIENT_HELLO_LEN + SERVER_HELLO_LEN;
00331 res = cb_authorization_id (sctx, &output[CLIENT_HELLO_LEN +
00332 SERVER_HELLO_LEN], &len);
00333 }
00334 else
00335 len = 0;
00336
00337 len += CLIENT_HELLO_LEN + SERVER_HELLO_LEN;
00338 res = shishi_ap_tktoptionsdata (state->sh,
00339 &state->ap,
00340 shishi_as_tkt (state->as),
00341 SHISHI_APOPTIONS_MUTUAL_REQUIRED,
00342 output, len);
00343 if (res != SHISHI_OK)
00344 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00345
00346 res = shishi_authenticator_add_authorizationdata
00347 (state->sh, shishi_ap_authenticator (state->ap), -1, output, len);
00348 if (res != SHISHI_OK)
00349 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00350
00351
00352
00353 res = shishi_ap_req_der (state->ap, output, output_len);
00354 if (res != SHISHI_OK)
00355 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00356
00357 state->step = STEP_NONINFRA_WAIT_APREP;
00358
00359 res = GSASL_NEEDS_MORE;
00360 break;
00361
00362 case STEP_NONINFRA_WAIT_APREP:
00363 if (shishi_ap_rep_der_set (state->ap, input, input_len) != SHISHI_OK)
00364 return GSASL_MECHANISM_PARSE_ERROR;
00365
00366 res = shishi_ap_rep_verify (state->ap);
00367 if (res != SHISHI_OK)
00368 return GSASL_AUTHENTICATION_ERROR;
00369
00370 state->step = STEP_SUCCESS;
00371
00372
00373 state->sessionkey = shishi_tkt_key (shishi_as_tkt (state->as));
00374
00375 *output_len = 0;
00376 res = GSASL_OK;
00377 break;
00378
00379 default:
00380 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00381 break;
00382 }
00383
00384 return res;
00385 }
00386
00387 int
00388 _gsasl_kerberos_v5_client_encode (Gsasl_session * sctx,
00389 void *mech_data,
00390 const char *input,
00391 size_t input_len,
00392 char *output, size_t * output_len)
00393 {
00394 struct _Gsasl_kerberos_v5_client_state *state = mech_data;
00395 int res;
00396
00397 if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
00398 {
00399
00400 }
00401 else if (state && state->sessionkey
00402 && state->clientqop & GSASL_QOP_AUTH_INT)
00403 {
00404 res = shishi_safe (state->sh, &state->safe);
00405 if (res != SHISHI_OK)
00406 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00407
00408 res = shishi_safe_set_user_data (state->sh,
00409 shishi_safe_safe (state->safe),
00410 input, input_len);
00411 if (res != SHISHI_OK)
00412 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00413
00414 res = shishi_safe_build (state->safe, state->sessionkey);
00415 if (res != SHISHI_OK)
00416 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00417
00418 res = shishi_safe_safe_der (state->safe, output, output_len);
00419 if (res != SHISHI_OK)
00420 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00421 }
00422 else
00423 {
00424 *output_len = input_len;
00425 if (output)
00426 memcpy (output, input, input_len);
00427 return GSASL_OK;
00428 }
00429
00430 return GSASL_OK;
00431 }
00432
00433 int
00434 _gsasl_kerberos_v5_client_decode (Gsasl_session * sctx,
00435 void *mech_data,
00436 const char *input,
00437 size_t input_len,
00438 char *output, size_t * output_len)
00439 {
00440 struct _Gsasl_kerberos_v5_client_state *state = mech_data;
00441
00442 puts ("cdecode");
00443
00444 if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
00445 {
00446
00447 }
00448 else if (state && state->sessionkey
00449 && state->clientqop & GSASL_QOP_AUTH_INT)
00450 {
00451 puts ("decode");
00452 }
00453 else
00454 {
00455 *output_len = input_len;
00456 if (output)
00457 memcpy (output, input, input_len);
00458 return GSASL_OK;
00459 }
00460
00461 return GSASL_OK;
00462 }
00463
00464 int
00465 _gsasl_kerberos_v5_client_finish (Gsasl_session * sctx, void *mech_data)
00466 {
00467 struct _Gsasl_kerberos_v5_client_state *state = mech_data;
00468
00469 shishi_done (state->sh);
00470 free (state);
00471
00472 return GSASL_OK;
00473 }
00474
00475 #endif
00476
00477
00478
00479 #ifdef USE_SERVER
00480
00481 struct _Gsasl_kerberos_v5_server_state
00482 {
00483 int firststep;
00484 Shishi *sh;
00485 char serverhello[BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN];
00486 char *random;
00487 int serverqops;
00488 uint32_t servermaxbuf;
00489 int clientqop;
00490 int clientmutual;
00491 uint32_t clientmaxbuf;
00492 char *username;
00493 char *userrealm;
00494 char *serverrealm;
00495 char *serverservice;
00496 char *serverhostname;
00497 char *password;
00498 Shishi_key *userkey;
00499 Shishi_key *sessionkey;
00500 Shishi_key *sessiontktkey;
00501 Shishi_ap *ap;
00502 Shishi_as *as;
00503 Shishi_safe *safe;
00504 };
00505
00506 int
00507 _gsasl_kerberos_v5_server_init (Gsasl_ctx * ctx)
00508 {
00509 if (!shishi_check_version (SHISHI_VERSION))
00510 return GSASL_UNKNOWN_MECHANISM;
00511
00512 return GSASL_OK;
00513 }
00514
00515 int
00516 _gsasl_kerberos_v5_server_start (Gsasl_session * sctx, void **mech_data)
00517 {
00518 struct _Gsasl_kerberos_v5_server_state *state;
00519 int err;
00520
00521 state = malloc (sizeof (*state));
00522 if (state == NULL)
00523 return GSASL_MALLOC_ERROR;
00524 memset (state, 0, sizeof (*state));
00525
00526 state->random = (char *) malloc (RANDOM_LEN);
00527 if (state->random == NULL)
00528 return GSASL_MALLOC_ERROR;
00529
00530 err = shishi_init_server (&state->sh);
00531 if (err)
00532 return GSASL_KERBEROS_V5_INIT_ERROR;
00533
00534 err = shishi_randomize (state->sh, state->random, RANDOM_LEN);
00535 if (err)
00536 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00537
00538
00539 err = shishi_key_random (state->sh, SHISHI_AES256_CTS_HMAC_SHA1_96,
00540 &state->sessiontktkey);
00541 if (err)
00542 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00543
00544 err = shishi_as (state->sh, &state->as);
00545 if (err)
00546 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00547
00548 state->firststep = 1;
00549 state->serverqops = GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT;
00550
00551 *mech_data = state;
00552
00553 return GSASL_OK;
00554 }
00555
00556 int
00557 _gsasl_kerberos_v5_server_step (Gsasl_session * sctx,
00558 void *mech_data,
00559 const char *input,
00560 size_t input_len,
00561 char *output, size_t * output_len)
00562 {
00563 struct _Gsasl_kerberos_v5_server_state *state = mech_data;
00564 Gsasl_server_callback_realm cb_realm;
00565 Gsasl_server_callback_qop cb_qop;
00566 Gsasl_server_callback_maxbuf cb_maxbuf;
00567 Gsasl_server_callback_cipher cb_cipher;
00568 Gsasl_server_callback_retrieve cb_retrieve;
00569 Gsasl_server_callback_service cb_service;
00570 unsigned char buf[BUFSIZ];
00571 size_t buflen;
00572 Gsasl_ctx *ctx;
00573 ASN1_TYPE asn1;
00574 int err;
00575
00576 ctx = gsasl_server_ctx_get (sctx);
00577 if (ctx == NULL)
00578 return GSASL_CANNOT_GET_CTX;
00579
00580 cb_realm = gsasl_server_callback_realm_get (ctx);
00581 cb_qop = gsasl_server_callback_qop_get (ctx);
00582 cb_maxbuf = gsasl_server_callback_maxbuf_get (ctx);
00583 cb_retrieve = gsasl_server_callback_retrieve_get (ctx);
00584 cb_service = gsasl_server_callback_service_get (ctx);
00585 if (cb_service == NULL)
00586 return GSASL_NEED_SERVER_SERVICE_CALLBACK;
00587
00588 if (state->firststep)
00589 {
00590 uint32_t tmp;
00591 unsigned char *p;
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614 if (output && *output_len < BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN)
00615 return GSASL_TOO_SMALL_BUFFER;
00616
00617 p = &state->serverhello[0];
00618
00619 if (cb_qop)
00620 state->serverqops = cb_qop (sctx);
00621 *p = 0;
00622 if (state->serverqops & GSASL_QOP_AUTH)
00623 *p |= GSASL_QOP_AUTH;
00624 if (state->serverqops & GSASL_QOP_AUTH_INT)
00625 *p |= GSASL_QOP_AUTH_INT;
00626 if (state->serverqops & GSASL_QOP_AUTH_CONF)
00627 *p |= GSASL_QOP_AUTH_CONF;
00628
00629 *p |= MUTUAL;
00630
00631 if (!(state->serverqops & ~GSASL_QOP_AUTH))
00632 state->servermaxbuf = 0;
00633 else if (cb_maxbuf)
00634 state->servermaxbuf = cb_maxbuf (sctx);
00635 else
00636 state->servermaxbuf = MAXBUF_DEFAULT;
00637
00638 tmp = htonl (state->servermaxbuf);
00639 memcpy (&state->serverhello[BITMAP_LEN], &tmp, MAXBUF_LEN);
00640 memcpy (&state->serverhello[BITMAP_LEN + MAXBUF_LEN],
00641 state->random, RANDOM_LEN);
00642
00643 if (output)
00644 memcpy (output, state->serverhello, SERVER_HELLO_LEN);
00645 *output_len = BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN;
00646
00647 state->firststep = 0;
00648
00649 return GSASL_NEEDS_MORE;
00650 }
00651
00652 if (cb_retrieve)
00653 {
00654
00655
00656 if (*output_len < 2048)
00657 return GSASL_TOO_SMALL_BUFFER;
00658
00659 if (shishi_as_req_der_set (state->as, input, input_len) == SHISHI_OK)
00660 {
00661 Shishi_tkt *tkt;
00662 int etype, i;
00663
00664 tkt = shishi_as_tkt (state->as);
00665 if (!tkt)
00666 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00667
00668 i = 1;
00669 do
00670 {
00671 err = shishi_kdcreq_etype (state->sh,
00672 shishi_as_req (state->as),
00673 &etype, i);
00674 if (err == SHISHI_OK && shishi_cipher_supported_p (etype))
00675 break;
00676 }
00677 while (err == SHISHI_OK);
00678 if (err != SHISHI_OK)
00679 return err;
00680
00681
00682 err = shishi_key_random (state->sh, etype, &state->sessionkey);
00683 if (err)
00684 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00685
00686 err = shishi_tkt_key_set (tkt, state->sessionkey);
00687 if (err)
00688 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00689
00690 buflen = sizeof (buf) - 1;
00691 err = shishi_kdcreq_cname_get (state->sh,
00692 shishi_as_req (state->as),
00693 buf, &buflen);
00694 if (err != SHISHI_OK)
00695 return err;
00696 buf[buflen] = '\0';
00697 state->username = strdup (buf);
00698
00699 buflen = sizeof (buf) - 1;
00700 err = shishi_kdcreq_realm_get (state->sh,
00701 shishi_as_req (state->as),
00702 buf, &buflen);
00703 if (err != SHISHI_OK)
00704 return err;
00705 buf[buflen] = '\0';
00706 state->userrealm = strdup (buf);
00707
00708 buflen = sizeof (buf) - 1;
00709 err = cb_retrieve (sctx, state->username, NULL, state->userrealm,
00710 NULL, &buflen);
00711 if (err != GSASL_OK)
00712 return err;
00713
00714 state->password = malloc (buflen + 1);
00715 if (state->password == NULL)
00716 return GSASL_MALLOC_ERROR;
00717
00718 err = cb_retrieve (sctx, state->username, NULL, state->userrealm,
00719 state->password, &buflen);
00720 if (err != GSASL_OK)
00721 return err;
00722 state->password[buflen] = '\0';
00723
00724 buflen = sizeof (buf) - 1;
00725 if (cb_realm)
00726 {
00727 err = cb_realm (sctx, buf, &buflen, 0);
00728 if (err != GSASL_OK)
00729 return err;
00730 }
00731 else
00732 buflen = 0;
00733 buf[buflen] = '\0';
00734 state->serverrealm = strdup (buf);
00735
00736 buflen = sizeof (buf) - 1;
00737 err = cb_service (sctx, buf, &buflen, NULL, NULL);
00738 if (err != GSASL_OK)
00739 return err;
00740 buf[buflen] = '\0';
00741 state->serverservice = strdup (buf);
00742
00743 buflen = sizeof (buf) - 1;
00744 err = cb_service (sctx, NULL, NULL, buf, &buflen);
00745 if (err != GSASL_OK)
00746 return err;
00747 buf[buflen] = '\0';
00748 state->serverhostname = strdup (buf);
00749
00750
00751
00752
00753
00754 err = shishi_tkt_clientrealm_set (tkt, state->userrealm,
00755 state->username);
00756 if (err)
00757 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00758
00759 {
00760 char *p;
00761 p = malloc (strlen (state->serverservice) + strlen ("/") +
00762 strlen (state->serverhostname) + 1);
00763 if (p == NULL)
00764 return GSASL_MALLOC_ERROR;
00765 sprintf (p, "%s/%s", state->serverservice, state->serverhostname);
00766 err = shishi_tkt_serverrealm_set (tkt, state->serverrealm, p);
00767 free (p);
00768 if (err)
00769 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00770 }
00771
00772 buflen = sizeof (buf);
00773 err = shishi_as_derive_salt (state->sh,
00774 shishi_as_req (state->as),
00775 shishi_as_rep (state->as),
00776 buf, &buflen);
00777 if (err != SHISHI_OK)
00778 return err;
00779
00780 err = shishi_key_from_string (state->sh,
00781 etype,
00782 state->password,
00783 strlen (state->password),
00784 buf, buflen, NULL, &state->userkey);
00785 if (err != SHISHI_OK)
00786 return err;
00787
00788 err = shishi_tkt_build (tkt, state->sessiontktkey);
00789 if (err)
00790 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00791
00792 err = shishi_as_rep_build (state->as, state->userkey);
00793 if (err)
00794 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00795
00796 #if DEBUG
00797 shishi_kdcreq_print (state->sh, stderr, shishi_as_req (state->as));
00798 shishi_encticketpart_print (state->sh, stderr,
00799 shishi_tkt_encticketpart (tkt));
00800 shishi_ticket_print (state->sh, stderr, shishi_tkt_ticket (tkt));
00801 shishi_enckdcreppart_print (state->sh, stderr,
00802 shishi_tkt_enckdcreppart (state->as));
00803 shishi_kdcrep_print (state->sh, stderr, shishi_as_rep (state->as));
00804 #endif
00805
00806 err = shishi_as_rep_der (state->as, output, output_len);
00807 if (err)
00808 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00809
00810 return GSASL_NEEDS_MORE;
00811 }
00812 else if ((asn1 = shishi_der2asn1_apreq (state->sh, input, input_len)))
00813 {
00814 int adtype;
00815
00816 err = shishi_ap (state->sh, &state->ap);
00817 if (err)
00818 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00819
00820 shishi_ap_req_set (state->ap, asn1);
00821
00822 err = shishi_ap_req_process (state->ap, state->sessiontktkey);
00823 if (err)
00824 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00825
00826 #if DEBUG
00827 shishi_apreq_print (state->sh, stderr, shishi_ap_req (state->ap));
00828 shishi_ticket_print (state->sh, stderr,
00829 shishi_tkt_ticket (shishi_ap_tkt (state->ap)));
00830 shishi_authenticator_print (state->sh, stderr,
00831 shishi_ap_authenticator (state->ap));
00832 #endif
00833
00834 buflen = sizeof (buf);
00835 err = shishi_authenticator_authorizationdata
00836 (state->sh, shishi_ap_authenticator (state->ap),
00837 &adtype, buf, &buflen, 1);
00838 if (err)
00839 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00840
00841 if (adtype != 0xFF ||
00842 buflen < CLIENT_HELLO_LEN + SERVER_HELLO_LEN)
00843 return GSASL_AUTHENTICATION_ERROR;
00844
00845 {
00846 unsigned char clientbitmap;
00847
00848 memcpy (&clientbitmap, &buf[0], BITMAP_LEN);
00849 state->clientqop = 0;
00850 if (clientbitmap & GSASL_QOP_AUTH)
00851 state->clientqop |= GSASL_QOP_AUTH;
00852 if (clientbitmap & GSASL_QOP_AUTH_INT)
00853 state->clientqop |= GSASL_QOP_AUTH_INT;
00854 if (clientbitmap & GSASL_QOP_AUTH_CONF)
00855 state->clientqop |= GSASL_QOP_AUTH_CONF;
00856 if (clientbitmap & MUTUAL)
00857 state->clientmutual = 1;
00858 }
00859 memcpy (&state->clientmaxbuf, &input[BITMAP_LEN], MAXBUF_LEN);
00860 state->clientmaxbuf = ntohl (state->clientmaxbuf);
00861
00862 if (!(state->clientqop & state->serverqops))
00863 return GSASL_AUTHENTICATION_ERROR;
00864
00865
00866
00867 if (memcmp (&buf[CLIENT_HELLO_LEN],
00868 state->serverhello, SERVER_HELLO_LEN) != 0)
00869 return GSASL_AUTHENTICATION_ERROR;
00870
00871 {
00872 char cksum[BUFSIZ];
00873 int cksumlen;
00874 int cksumtype;
00875 Shishi_key *key;
00876
00877 key = shishi_tkt_key (shishi_as_tkt (state->as));
00878 cksumtype =
00879 shishi_cipher_defaultcksumtype (shishi_key_type (key));
00880 cksumlen = sizeof (cksum);
00881 err = shishi_checksum (state->sh, key,
00882 SHISHI_KEYUSAGE_APREQ_AUTHENTICATOR_CKSUM,
00883 cksumtype, buf, buflen, cksum, &cksumlen);
00884 if (err != SHISHI_OK)
00885 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00886
00887 buflen = sizeof (buf);
00888 err = shishi_authenticator_cksum
00889 (state->sh,
00890 shishi_ap_authenticator (state->ap), &cksumtype, buf, &buflen);
00891 if (err != SHISHI_OK)
00892 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00893
00894 if (buflen != cksumlen || memcmp (buf, cksum, buflen) != 0)
00895 return GSASL_AUTHENTICATION_ERROR;
00896 }
00897
00898
00899
00900 if (state->clientmutual)
00901 {
00902 err = shishi_ap_rep_build (state->ap);
00903 if (err)
00904 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00905
00906 err = shishi_ap_rep_der (state->ap, output, output_len);
00907 if (err)
00908 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00909 }
00910 else
00911 *output_len = 0;
00912
00913 return GSASL_OK;
00914 }
00915 }
00916 else
00917 {
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931 return GSASL_NEED_SERVER_RETRIEVE_CALLBACK;
00932 }
00933
00934 *output_len = 0;
00935 return GSASL_NEEDS_MORE;
00936 }
00937
00938 int
00939 _gsasl_kerberos_v5_server_encode (Gsasl_session * sctx,
00940 void *mech_data,
00941 const char *input,
00942 size_t input_len,
00943 char *output, size_t * output_len)
00944 {
00945 struct _Gsasl_kerberos_v5_server_state *state = mech_data;
00946 int res;
00947
00948 if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
00949 {
00950
00951 }
00952 else if (state && state->sessionkey
00953 && state->clientqop & GSASL_QOP_AUTH_INT)
00954 {
00955 res = shishi_safe (state->sh, &state->safe);
00956 if (res != SHISHI_OK)
00957 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00958
00959 res = shishi_safe_set_user_data (state->sh,
00960 shishi_safe_safe (state->safe),
00961 input, input_len);
00962 if (res != SHISHI_OK)
00963 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00964
00965 res = shishi_safe_build (state->safe, state->sessionkey);
00966 if (res != SHISHI_OK)
00967 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00968
00969 res = shishi_safe_safe_der (state->safe, output, output_len);
00970 if (res != SHISHI_OK)
00971 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00972 }
00973 else
00974 {
00975 *output_len = input_len;
00976 if (output)
00977 memcpy (output, input, input_len);
00978 return GSASL_OK;
00979 }
00980
00981 return GSASL_OK;
00982 }
00983
00984 int
00985 _gsasl_kerberos_v5_server_decode (Gsasl_session * sctx,
00986 void *mech_data,
00987 const char *input,
00988 size_t input_len,
00989 char *output, size_t * output_len)
00990 {
00991 struct _Gsasl_kerberos_v5_server_state *state = mech_data;
00992 int res;
00993
00994 if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
00995 {
00996
00997 }
00998 else if (state && state->sessionkey
00999 && state->clientqop & GSASL_QOP_AUTH_INT)
01000 {
01001 Shishi_asn1 asn1safe;
01002
01003 res = shishi_safe (state->sh, &state->safe);
01004 if (res != SHISHI_OK)
01005 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
01006
01007 res = shishi_safe_safe_der_set (state->safe, input, input_len);
01008 printf ("len %d err %d\n", input_len, res);
01009 if (res != SHISHI_OK)
01010 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
01011
01012 res = shishi_safe_verify (state->safe, state->sessionkey);
01013 if (res != SHISHI_OK)
01014 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
01015
01016 res = shishi_safe_user_data (state->sh, shishi_safe_safe (state->safe),
01017 output, output_len);
01018 if (res != SHISHI_OK)
01019 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
01020 printf ("len=%d\n", *output_len);
01021 return GSASL_OK;
01022 }
01023 else
01024 {
01025 *output_len = input_len;
01026 if (output)
01027 memcpy (output, input, input_len);
01028 return GSASL_OK;
01029 }
01030
01031
01032 return GSASL_OK;
01033 }
01034
01035 int
01036 _gsasl_kerberos_v5_server_finish (Gsasl_session * sctx, void *mech_data)
01037 {
01038 struct _Gsasl_kerberos_v5_server_state *state = mech_data;
01039
01040 shishi_done (state->sh);
01041 if (state->username)
01042 free (state->username);
01043 if (state->password)
01044 free (state->password);
01045 if (state->random)
01046 free (state->random);
01047 free (state);
01048
01049 return GSASL_OK;
01050 }
01051 #endif