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 #include "shared.h"
00029
00030 struct _Gsasl_kerberos_v5_server_state
00031 {
00032 int firststep;
00033 Shishi *sh;
00034 char serverhello[BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN];
00035 char *random;
00036 int serverqops;
00037 uint32_t servermaxbuf;
00038 int clientqop;
00039 int clientmutual;
00040 uint32_t clientmaxbuf;
00041 char *username;
00042 char *userrealm;
00043 char *serverrealm;
00044 char *serverservice;
00045 char *serverhostname;
00046 char *password;
00047 Shishi_key *userkey;
00048 Shishi_key *sessionkey;
00049 Shishi_key *sessiontktkey;
00050 Shishi_ap *ap;
00051 Shishi_as *as;
00052 Shishi_safe *safe;
00053 };
00054
00055 int
00056 _gsasl_kerberos_v5_server_init (Gsasl_ctx * ctx)
00057 {
00058 if (!shishi_check_version (SHISHI_VERSION))
00059 return GSASL_UNKNOWN_MECHANISM;
00060
00061 return GSASL_OK;
00062 }
00063
00064 int
00065 _gsasl_kerberos_v5_server_start (Gsasl_session * sctx, void **mech_data)
00066 {
00067 struct _Gsasl_kerberos_v5_server_state *state;
00068 int err;
00069
00070 state = malloc (sizeof (*state));
00071 if (state == NULL)
00072 return GSASL_MALLOC_ERROR;
00073 memset (state, 0, sizeof (*state));
00074
00075 state->random = (char *) malloc (RANDOM_LEN);
00076 if (state->random == NULL)
00077 return GSASL_MALLOC_ERROR;
00078
00079 err = shishi_init_server (&state->sh);
00080 if (err)
00081 return GSASL_KERBEROS_V5_INIT_ERROR;
00082
00083 err = shishi_randomize (state->sh, state->random, RANDOM_LEN);
00084 if (err)
00085 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00086
00087
00088 err = shishi_key_random (state->sh, SHISHI_AES256_CTS_HMAC_SHA1_96,
00089 &state->sessiontktkey);
00090 if (err)
00091 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00092
00093 err = shishi_as (state->sh, &state->as);
00094 if (err)
00095 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00096
00097 state->firststep = 1;
00098 state->serverqops = GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT;
00099
00100 *mech_data = state;
00101
00102 return GSASL_OK;
00103 }
00104
00105 int
00106 _gsasl_kerberos_v5_server_step (Gsasl_session * sctx,
00107 void *mech_data,
00108 const char *input,
00109 size_t input_len,
00110 char *output, size_t * output_len)
00111 {
00112 struct _Gsasl_kerberos_v5_server_state *state = mech_data;
00113 Gsasl_server_callback_realm cb_realm;
00114 Gsasl_server_callback_qop cb_qop;
00115 Gsasl_server_callback_maxbuf cb_maxbuf;
00116 Gsasl_server_callback_cipher cb_cipher;
00117 Gsasl_server_callback_retrieve cb_retrieve;
00118 Gsasl_server_callback_service cb_service;
00119 unsigned char buf[BUFSIZ];
00120 size_t buflen;
00121 Gsasl_ctx *ctx;
00122 ASN1_TYPE asn1;
00123 int err;
00124
00125 ctx = gsasl_server_ctx_get (sctx);
00126 if (ctx == NULL)
00127 return GSASL_CANNOT_GET_CTX;
00128
00129 cb_realm = gsasl_server_callback_realm_get (ctx);
00130 cb_qop = gsasl_server_callback_qop_get (ctx);
00131 cb_maxbuf = gsasl_server_callback_maxbuf_get (ctx);
00132 cb_retrieve = gsasl_server_callback_retrieve_get (ctx);
00133 cb_service = gsasl_server_callback_service_get (ctx);
00134 if (cb_service == NULL)
00135 return GSASL_NEED_SERVER_SERVICE_CALLBACK;
00136
00137 if (state->firststep)
00138 {
00139 uint32_t tmp;
00140 unsigned char *p;
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 if (output && *output_len < BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN)
00164 return GSASL_TOO_SMALL_BUFFER;
00165
00166 p = &state->serverhello[0];
00167
00168 if (cb_qop)
00169 state->serverqops = cb_qop (sctx);
00170 *p = 0;
00171 if (state->serverqops & GSASL_QOP_AUTH)
00172 *p |= GSASL_QOP_AUTH;
00173 if (state->serverqops & GSASL_QOP_AUTH_INT)
00174 *p |= GSASL_QOP_AUTH_INT;
00175 if (state->serverqops & GSASL_QOP_AUTH_CONF)
00176 *p |= GSASL_QOP_AUTH_CONF;
00177
00178 *p |= MUTUAL;
00179
00180 if (!(state->serverqops & ~GSASL_QOP_AUTH))
00181 state->servermaxbuf = 0;
00182 else if (cb_maxbuf)
00183 state->servermaxbuf = cb_maxbuf (sctx);
00184 else
00185 state->servermaxbuf = MAXBUF_DEFAULT;
00186
00187 tmp = htonl (state->servermaxbuf);
00188 memcpy (&state->serverhello[BITMAP_LEN], &tmp, MAXBUF_LEN);
00189 memcpy (&state->serverhello[BITMAP_LEN + MAXBUF_LEN],
00190 state->random, RANDOM_LEN);
00191
00192 if (output)
00193 memcpy (output, state->serverhello, SERVER_HELLO_LEN);
00194 *output_len = BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN;
00195
00196 state->firststep = 0;
00197
00198 return GSASL_NEEDS_MORE;
00199 }
00200
00201 if (cb_retrieve)
00202 {
00203
00204
00205 if (*output_len < 2048)
00206 return GSASL_TOO_SMALL_BUFFER;
00207
00208 if (shishi_as_req_der_set (state->as, input, input_len) == SHISHI_OK)
00209 {
00210 Shishi_tkt *tkt;
00211 int etype, i;
00212
00213 tkt = shishi_as_tkt (state->as);
00214 if (!tkt)
00215 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00216
00217 i = 1;
00218 do
00219 {
00220 err = shishi_kdcreq_etype (state->sh,
00221 shishi_as_req (state->as),
00222 &etype, i);
00223 if (err == SHISHI_OK && shishi_cipher_supported_p (etype))
00224 break;
00225 }
00226 while (err == SHISHI_OK);
00227 if (err != SHISHI_OK)
00228 return err;
00229
00230
00231 err = shishi_key_random (state->sh, etype, &state->sessionkey);
00232 if (err)
00233 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00234
00235 err = shishi_tkt_key_set (tkt, state->sessionkey);
00236 if (err)
00237 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00238
00239 buflen = sizeof (buf) - 1;
00240 err = shishi_kdcreq_cname_get (state->sh,
00241 shishi_as_req (state->as),
00242 buf, &buflen);
00243 if (err != SHISHI_OK)
00244 return err;
00245 buf[buflen] = '\0';
00246 state->username = strdup (buf);
00247
00248 buflen = sizeof (buf) - 1;
00249 err = shishi_kdcreq_realm_get (state->sh,
00250 shishi_as_req (state->as),
00251 buf, &buflen);
00252 if (err != SHISHI_OK)
00253 return err;
00254 buf[buflen] = '\0';
00255 state->userrealm = strdup (buf);
00256
00257 buflen = sizeof (buf) - 1;
00258 err = cb_retrieve (sctx, state->username, NULL, state->userrealm,
00259 NULL, &buflen);
00260 if (err != GSASL_OK)
00261 return err;
00262
00263 state->password = malloc (buflen + 1);
00264 if (state->password == NULL)
00265 return GSASL_MALLOC_ERROR;
00266
00267 err = cb_retrieve (sctx, state->username, NULL, state->userrealm,
00268 state->password, &buflen);
00269 if (err != GSASL_OK)
00270 return err;
00271 state->password[buflen] = '\0';
00272
00273 buflen = sizeof (buf) - 1;
00274 if (cb_realm)
00275 {
00276 err = cb_realm (sctx, buf, &buflen, 0);
00277 if (err != GSASL_OK)
00278 return err;
00279 }
00280 else
00281 buflen = 0;
00282 buf[buflen] = '\0';
00283 state->serverrealm = strdup (buf);
00284
00285 buflen = sizeof (buf) - 1;
00286 err = cb_service (sctx, buf, &buflen, NULL, NULL);
00287 if (err != GSASL_OK)
00288 return err;
00289 buf[buflen] = '\0';
00290 state->serverservice = strdup (buf);
00291
00292 buflen = sizeof (buf) - 1;
00293 err = cb_service (sctx, NULL, NULL, buf, &buflen);
00294 if (err != GSASL_OK)
00295 return err;
00296 buf[buflen] = '\0';
00297 state->serverhostname = strdup (buf);
00298
00299
00300
00301
00302
00303 err = shishi_tkt_clientrealm_set (tkt, state->userrealm,
00304 state->username);
00305 if (err)
00306 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00307
00308 {
00309 char *p;
00310 p = malloc (strlen (state->serverservice) + strlen ("/") +
00311 strlen (state->serverhostname) + 1);
00312 if (p == NULL)
00313 return GSASL_MALLOC_ERROR;
00314 sprintf (p, "%s/%s", state->serverservice, state->serverhostname);
00315 err = shishi_tkt_serverrealm_set (tkt, state->serverrealm, p);
00316 free (p);
00317 if (err)
00318 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00319 }
00320
00321 buflen = sizeof (buf);
00322 err = shishi_as_derive_salt (state->sh,
00323 shishi_as_req (state->as),
00324 shishi_as_rep (state->as),
00325 buf, &buflen);
00326 if (err != SHISHI_OK)
00327 return err;
00328
00329 err = shishi_key_from_string (state->sh,
00330 etype,
00331 state->password,
00332 strlen (state->password),
00333 buf, buflen, NULL, &state->userkey);
00334 if (err != SHISHI_OK)
00335 return err;
00336
00337 err = shishi_tkt_build (tkt, state->sessiontktkey);
00338 if (err)
00339 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00340
00341 err = shishi_as_rep_build (state->as, state->userkey);
00342 if (err)
00343 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00344
00345 #if DEBUG
00346 shishi_kdcreq_print (state->sh, stderr, shishi_as_req (state->as));
00347 shishi_encticketpart_print (state->sh, stderr,
00348 shishi_tkt_encticketpart (tkt));
00349 shishi_ticket_print (state->sh, stderr, shishi_tkt_ticket (tkt));
00350 shishi_enckdcreppart_print (state->sh, stderr,
00351 shishi_tkt_enckdcreppart (state->as));
00352 shishi_kdcrep_print (state->sh, stderr, shishi_as_rep (state->as));
00353 #endif
00354
00355 err = shishi_as_rep_der (state->as, output, output_len);
00356 if (err)
00357 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00358
00359 return GSASL_NEEDS_MORE;
00360 }
00361 else if ((asn1 = shishi_der2asn1_apreq (state->sh, input, input_len)))
00362 {
00363 int adtype;
00364
00365 err = shishi_ap (state->sh, &state->ap);
00366 if (err)
00367 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00368
00369 shishi_ap_req_set (state->ap, asn1);
00370
00371 err = shishi_ap_req_process (state->ap, state->sessiontktkey);
00372 if (err)
00373 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00374
00375 #if DEBUG
00376 shishi_apreq_print (state->sh, stderr, shishi_ap_req (state->ap));
00377 shishi_ticket_print (state->sh, stderr,
00378 shishi_tkt_ticket (shishi_ap_tkt (state->ap)));
00379 shishi_authenticator_print (state->sh, stderr,
00380 shishi_ap_authenticator (state->ap));
00381 #endif
00382
00383 buflen = sizeof (buf);
00384 err = shishi_authenticator_authorizationdata
00385 (state->sh, shishi_ap_authenticator (state->ap),
00386 &adtype, buf, &buflen, 1);
00387 if (err)
00388 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00389
00390 if (adtype != 0xFF ||
00391 buflen < CLIENT_HELLO_LEN + SERVER_HELLO_LEN)
00392 return GSASL_AUTHENTICATION_ERROR;
00393
00394 {
00395 unsigned char clientbitmap;
00396
00397 memcpy (&clientbitmap, &buf[0], BITMAP_LEN);
00398 state->clientqop = 0;
00399 if (clientbitmap & GSASL_QOP_AUTH)
00400 state->clientqop |= GSASL_QOP_AUTH;
00401 if (clientbitmap & GSASL_QOP_AUTH_INT)
00402 state->clientqop |= GSASL_QOP_AUTH_INT;
00403 if (clientbitmap & GSASL_QOP_AUTH_CONF)
00404 state->clientqop |= GSASL_QOP_AUTH_CONF;
00405 if (clientbitmap & MUTUAL)
00406 state->clientmutual = 1;
00407 }
00408 memcpy (&state->clientmaxbuf, &input[BITMAP_LEN], MAXBUF_LEN);
00409 state->clientmaxbuf = ntohl (state->clientmaxbuf);
00410
00411 if (!(state->clientqop & state->serverqops))
00412 return GSASL_AUTHENTICATION_ERROR;
00413
00414
00415
00416 if (memcmp (&buf[CLIENT_HELLO_LEN],
00417 state->serverhello, SERVER_HELLO_LEN) != 0)
00418 return GSASL_AUTHENTICATION_ERROR;
00419
00420 {
00421 char cksum[BUFSIZ];
00422 int cksumlen;
00423 int cksumtype;
00424 Shishi_key *key;
00425
00426 key = shishi_tkt_key (shishi_as_tkt (state->as));
00427 cksumtype =
00428 shishi_cipher_defaultcksumtype (shishi_key_type (key));
00429 cksumlen = sizeof (cksum);
00430 err = shishi_checksum (state->sh, key,
00431 SHISHI_KEYUSAGE_APREQ_AUTHENTICATOR_CKSUM,
00432 cksumtype, buf, buflen, cksum, &cksumlen);
00433 if (err != SHISHI_OK)
00434 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00435
00436 buflen = sizeof (buf);
00437 err = shishi_authenticator_cksum
00438 (state->sh,
00439 shishi_ap_authenticator (state->ap), &cksumtype, buf, &buflen);
00440 if (err != SHISHI_OK)
00441 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00442
00443 if (buflen != cksumlen || memcmp (buf, cksum, buflen) != 0)
00444 return GSASL_AUTHENTICATION_ERROR;
00445 }
00446
00447
00448
00449 if (state->clientmutual)
00450 {
00451 err = shishi_ap_rep_build (state->ap);
00452 if (err)
00453 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00454
00455 err = shishi_ap_rep_der (state->ap, output, output_len);
00456 if (err)
00457 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00458 }
00459 else
00460 *output_len = 0;
00461
00462 return GSASL_OK;
00463 }
00464 }
00465 else
00466 {
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 return GSASL_NEED_SERVER_RETRIEVE_CALLBACK;
00481 }
00482
00483 *output_len = 0;
00484 return GSASL_NEEDS_MORE;
00485 }
00486
00487 int
00488 _gsasl_kerberos_v5_server_encode (Gsasl_session * sctx,
00489 void *mech_data,
00490 const char *input,
00491 size_t input_len,
00492 char *output, size_t * output_len)
00493 {
00494 struct _Gsasl_kerberos_v5_server_state *state = mech_data;
00495 int res;
00496
00497 if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
00498 {
00499 return GSASL_INTEGRITY_ERROR;
00500 }
00501 else if (state && state->sessionkey
00502 && state->clientqop & GSASL_QOP_AUTH_INT)
00503 {
00504 res = shishi_safe (state->sh, &state->safe);
00505 if (res != SHISHI_OK)
00506 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00507
00508 res = shishi_safe_set_user_data (state->sh,
00509 shishi_safe_safe (state->safe),
00510 input, input_len);
00511 if (res != SHISHI_OK)
00512 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00513
00514 res = shishi_safe_build (state->safe, state->sessionkey);
00515 if (res != SHISHI_OK)
00516 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00517
00518 res = shishi_safe_safe_der (state->safe, output, output_len);
00519 if (res != SHISHI_OK)
00520 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00521 }
00522 else
00523 {
00524 *output_len = input_len;
00525 *output = malloc (input_len);
00526 if (!*output)
00527 return GSASL_MALLOC_ERROR;
00528 memcpy (*output, input, input_len);
00529 }
00530
00531 return GSASL_OK;
00532 }
00533
00534 int
00535 _gsasl_kerberos_v5_server_decode (Gsasl_session * sctx,
00536 void *mech_data,
00537 const char *input,
00538 size_t input_len,
00539 char *output, size_t * output_len)
00540 {
00541 struct _Gsasl_kerberos_v5_server_state *state = mech_data;
00542 int res;
00543
00544 if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
00545 {
00546 return GSASL_INTEGRITY_ERROR;
00547 }
00548 else if (state && state->sessionkey
00549 && state->clientqop & GSASL_QOP_AUTH_INT)
00550 {
00551 Shishi_asn1 asn1safe;
00552
00553 res = shishi_safe (state->sh, &state->safe);
00554 if (res != SHISHI_OK)
00555 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00556
00557 res = shishi_safe_safe_der_set (state->safe, input, input_len);
00558 if (res != SHISHI_OK)
00559 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00560
00561 res = shishi_safe_verify (state->safe, state->sessionkey);
00562 if (res != SHISHI_OK)
00563 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00564
00565 res = shishi_safe_user_data (state->sh, shishi_safe_safe (state->safe),
00566 output, output_len);
00567 if (res != SHISHI_OK)
00568 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00569
00570 return GSASL_OK;
00571 }
00572 else
00573 {
00574 *output_len = input_len;
00575 *output = malloc (input_len);
00576 if (!*output)
00577 return GSASL_MALLOC_ERROR;
00578 memcpy (*output, input, input_len);
00579 }
00580
00581
00582 return GSASL_OK;
00583 }
00584
00585 int
00586 _gsasl_kerberos_v5_server_finish (Gsasl_session * sctx, void *mech_data)
00587 {
00588 struct _Gsasl_kerberos_v5_server_state *state = mech_data;
00589
00590 shishi_done (state->sh);
00591 if (state->username)
00592 free (state->username);
00593 if (state->password)
00594 free (state->password);
00595 if (state->random)
00596 free (state->random);
00597 free (state);
00598
00599 return GSASL_OK;
00600 }