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_client_state
00031 {
00032 int step;
00033 char serverhello[BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN];
00034 int serverqops;
00035 int clientqop;
00036 int servermutual;
00037 uint32_t servermaxbuf;
00038 uint32_t clientmaxbuf;
00039 Shishi *sh;
00040 Shishi_tkt *tkt;
00041 Shishi_as *as;
00042 Shishi_ap *ap;
00043 Shishi_key *sessionkey;
00044 Shishi_safe *safe;
00045 };
00046
00047 int
00048 _gsasl_kerberos_v5_client_init (Gsasl_ctx * ctx)
00049 {
00050 if (!shishi_check_version (SHISHI_VERSION))
00051 return GSASL_UNKNOWN_MECHANISM;
00052
00053 return GSASL_OK;
00054 }
00055
00056 int
00057 _gsasl_kerberos_v5_client_start (Gsasl_session * sctx, void **mech_data)
00058 {
00059 struct _Gsasl_kerberos_v5_client_state *state;
00060 Gsasl_ctx *ctx;
00061 int err;
00062
00063 state = malloc (sizeof (*state));
00064 if (state == NULL)
00065 return GSASL_MALLOC_ERROR;
00066
00067 memset (state, 0, sizeof (*state));
00068
00069 err = shishi_init (&state->sh);
00070 if (err)
00071 return GSASL_KERBEROS_V5_INIT_ERROR;
00072
00073 state->step = 0;
00074 state->clientqop = GSASL_QOP_AUTH_INT;
00075
00076 *mech_data = state;
00077
00078 return GSASL_OK;
00079 }
00080
00081 #define STEP_FIRST 0
00082 #define STEP_NONINFRA_SEND_ASREQ 1
00083 #define STEP_NONINFRA_WAIT_ASREP 2
00084 #define STEP_NONINFRA_SEND_APREQ 3
00085 #define STEP_NONINFRA_WAIT_APREP 4
00086 #define STEP_SUCCESS 5
00087
00088 int
00089 _gsasl_kerberos_v5_client_step (Gsasl_session * sctx,
00090 void *mech_data,
00091 const char *input,
00092 size_t input_len,
00093 char *output, size_t * output_len)
00094 {
00095 struct _Gsasl_kerberos_v5_client_state *state = mech_data;
00096 Gsasl_client_callback_authentication_id cb_authentication_id;
00097 Gsasl_client_callback_authorization_id cb_authorization_id;
00098 Gsasl_client_callback_qop cb_qop;
00099 Gsasl_client_callback_realm cb_realm;
00100 Gsasl_client_callback_password cb_password;
00101 Gsasl_client_callback_service cb_service;
00102 Gsasl_client_callback_maxbuf cb_maxbuf;
00103 Gsasl_ctx *ctx;
00104 int res;
00105 int len;
00106
00107 ctx = gsasl_client_ctx_get (sctx);
00108 if (ctx == NULL)
00109 return GSASL_CANNOT_GET_CTX;
00110
00111
00112 cb_realm = gsasl_client_callback_realm_get (ctx);
00113 cb_service = gsasl_client_callback_service_get (ctx);
00114 cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx);
00115 cb_authorization_id = gsasl_client_callback_authorization_id_get (ctx);
00116 cb_qop = gsasl_client_callback_qop_get (ctx);
00117 cb_maxbuf = gsasl_client_callback_maxbuf_get (ctx);
00118
00119
00120 cb_password = gsasl_client_callback_password_get (ctx);
00121 if (cb_password == NULL)
00122 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
00123
00124
00125 cb_service = gsasl_client_callback_service_get (ctx);
00126 if (cb_service == NULL)
00127 return GSASL_NEED_CLIENT_SERVICE_CALLBACK;
00128
00129 switch (state->step)
00130 {
00131 case STEP_FIRST:
00132 if (input == NULL)
00133 {
00134 *output_len = 0;
00135 return GSASL_NEEDS_MORE;
00136 }
00137
00138 if (input_len != SERVER_HELLO_LEN)
00139 return GSASL_MECHANISM_PARSE_ERROR;
00140
00141 memcpy (state->serverhello, input, input_len);
00142
00143 {
00144 unsigned char serverbitmap;
00145
00146 memcpy (&serverbitmap, input, BITMAP_LEN);
00147 state->serverqops = 0;
00148 if (serverbitmap & GSASL_QOP_AUTH)
00149 state->serverqops |= GSASL_QOP_AUTH;
00150 if (serverbitmap & GSASL_QOP_AUTH_INT)
00151 state->serverqops |= GSASL_QOP_AUTH_INT;
00152 if (serverbitmap & GSASL_QOP_AUTH_CONF)
00153 state->serverqops |= GSASL_QOP_AUTH_CONF;
00154 if (serverbitmap & MUTUAL)
00155 state->servermutual = 1;
00156 }
00157 memcpy (&state->servermaxbuf, &input[BITMAP_LEN], MAXBUF_LEN);
00158 state->servermaxbuf = ntohl (state->servermaxbuf);
00159
00160 if (cb_qop)
00161 state->clientqop = cb_qop (sctx, state->serverqops);
00162
00163 if (!(state->serverqops & state->clientqop &
00164 (GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF)))
00165 return GSASL_AUTHENTICATION_ERROR;
00166
00167
00168 if (!state->servermutual)
00169 return GSASL_AUTHENTICATION_ERROR;
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 state->step = STEP_NONINFRA_SEND_APREQ;
00184
00185
00186 case STEP_NONINFRA_SEND_ASREQ:
00187 res = shishi_as (state->sh, &state->as);
00188 if (res)
00189 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00190
00191 if (cb_authentication_id)
00192 {
00193 len = *output_len - 1;
00194 res = cb_authentication_id (sctx, output, &len);
00195 if (res != GSASL_OK)
00196 return res;
00197 output[len] = '\0';
00198
00199 res = shishi_kdcreq_set_cname (state->sh, shishi_as_req (state->as),
00200 SHISHI_NT_UNKNOWN, output);
00201 if (res != GSASL_OK)
00202 return res;
00203 }
00204
00205 if (cb_realm)
00206 {
00207 len = *output_len - 1;
00208 res = cb_realm (sctx, output, &len);
00209 if (res != GSASL_OK)
00210 return res;
00211 }
00212 else
00213 len = 0;
00214
00215 output[len] = '\0';
00216 res = shishi_kdcreq_set_realm (state->sh, shishi_as_req (state->as),
00217 output);
00218 if (res != GSASL_OK)
00219 return res;
00220
00221 if (cb_service)
00222 {
00223 char *sname[3];
00224 size_t servicelen = 0;
00225 size_t hostnamelen = 0;
00226
00227 res = cb_service (sctx, NULL, &servicelen, NULL, &hostnamelen,
00228
00229 NULL, NULL);
00230 if (res != GSASL_OK)
00231 return res;
00232
00233 if (*output_len < servicelen + 1 + hostnamelen + 1)
00234 return GSASL_TOO_SMALL_BUFFER;
00235
00236 sname[0] = &output[0];
00237 sname[1] = &output[servicelen + 2];
00238 sname[2] = NULL;
00239
00240 res = cb_service (sctx, sname[0], &servicelen,
00241 sname[1], &hostnamelen, NULL, NULL);
00242 if (res != GSASL_OK)
00243 return res;
00244
00245 sname[0][servicelen] = '\0';
00246 sname[1][hostnamelen] = '\0';
00247
00248 res = shishi_kdcreq_set_sname (state->sh, shishi_as_req (state->as),
00249 SHISHI_NT_UNKNOWN, sname);
00250 if (res != GSASL_OK)
00251 return res;
00252 }
00253
00254
00255
00256
00257 res = shishi_a2d (state->sh, shishi_as_req (state->as),
00258 output, output_len);
00259 if (res != SHISHI_OK)
00260 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00261
00262 state->step = STEP_NONINFRA_WAIT_ASREP;
00263
00264 res = GSASL_NEEDS_MORE;
00265 break;
00266
00267 case STEP_NONINFRA_WAIT_ASREP:
00268 if (shishi_as_rep_der_set (state->as, input, input_len) != SHISHI_OK)
00269 return GSASL_MECHANISM_PARSE_ERROR;
00270
00271
00272 len = *output_len - 1;
00273 res = cb_password (sctx, output, &len);
00274 if (res != GSASL_OK && res != GSASL_NEEDS_MORE)
00275 return res;
00276 output[len] = '\0';
00277
00278 res = shishi_as_rep_process (state->as, NULL, output);
00279 if (res != SHISHI_OK)
00280 return GSASL_AUTHENTICATION_ERROR;
00281
00282 state->step = STEP_NONINFRA_SEND_APREQ;
00283
00284
00285 case STEP_NONINFRA_SEND_APREQ:
00286 if (*output_len <= CLIENT_HELLO_LEN + SERVER_HELLO_LEN)
00287 return GSASL_TOO_SMALL_BUFFER;
00288
00289 if (!(state->clientqop & ~GSASL_QOP_AUTH))
00290 state->clientmaxbuf = 0;
00291 else if (cb_maxbuf)
00292 state->clientmaxbuf = cb_maxbuf (sctx, state->servermaxbuf);
00293 else
00294 state->clientmaxbuf = MAXBUF_DEFAULT;
00295
00296
00297 output[0] = state->clientqop | MUTUAL;
00298 {
00299 uint32_t tmp;
00300
00301 tmp = ntohl (state->clientmaxbuf);
00302 memcpy (&output[BITMAP_LEN], &tmp, MAXBUF_LEN);
00303 }
00304 memcpy (&output[CLIENT_HELLO_LEN], state->serverhello,
00305 SERVER_HELLO_LEN);
00306
00307 if (cb_authorization_id)
00308 {
00309 len = *output_len - CLIENT_HELLO_LEN + SERVER_HELLO_LEN;
00310 res = cb_authorization_id (sctx, &output[CLIENT_HELLO_LEN +
00311 SERVER_HELLO_LEN], &len);
00312 }
00313 else
00314 len = 0;
00315
00316 len += CLIENT_HELLO_LEN + SERVER_HELLO_LEN;
00317 res = shishi_ap_tktoptionsdata (state->sh,
00318 &state->ap,
00319 shishi_as_tkt (state->as),
00320 SHISHI_APOPTIONS_MUTUAL_REQUIRED,
00321 output, len);
00322 if (res != SHISHI_OK)
00323 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00324
00325 res = shishi_authenticator_add_authorizationdata
00326 (state->sh, shishi_ap_authenticator (state->ap), -1, output, len);
00327 if (res != SHISHI_OK)
00328 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00329
00330
00331
00332 res = shishi_ap_req_der (state->ap, output, output_len);
00333 if (res != SHISHI_OK)
00334 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00335
00336 state->step = STEP_NONINFRA_WAIT_APREP;
00337
00338 res = GSASL_NEEDS_MORE;
00339 break;
00340
00341 case STEP_NONINFRA_WAIT_APREP:
00342 if (shishi_ap_rep_der_set (state->ap, input, input_len) != SHISHI_OK)
00343 return GSASL_MECHANISM_PARSE_ERROR;
00344
00345 res = shishi_ap_rep_verify (state->ap);
00346 if (res != SHISHI_OK)
00347 return GSASL_AUTHENTICATION_ERROR;
00348
00349 state->step = STEP_SUCCESS;
00350
00351
00352 state->sessionkey = shishi_tkt_key (shishi_as_tkt (state->as));
00353
00354 *output_len = 0;
00355 res = GSASL_OK;
00356 break;
00357
00358 default:
00359 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00360 break;
00361 }
00362
00363 return res;
00364 }
00365
00366 int
00367 _gsasl_kerberos_v5_client_encode (Gsasl_session * sctx,
00368 void *mech_data,
00369 const char *input,
00370 size_t input_len,
00371 char **output, size_t * output_len)
00372 {
00373 struct _Gsasl_kerberos_v5_client_state *state = mech_data;
00374 int res;
00375
00376 if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
00377 {
00378 return GSASL_INTEGRITY_ERROR;
00379 }
00380 else if (state && state->sessionkey
00381 && state->clientqop & GSASL_QOP_AUTH_INT)
00382 {
00383 res = shishi_safe (state->sh, &state->safe);
00384 if (res != SHISHI_OK)
00385 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00386
00387 res = shishi_safe_set_user_data (state->sh,
00388 shishi_safe_safe (state->safe),
00389 input, input_len);
00390 if (res != SHISHI_OK)
00391 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00392
00393 res = shishi_safe_build (state->safe, state->sessionkey);
00394 if (res != SHISHI_OK)
00395 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00396
00397 res = shishi_safe_safe_der (state->safe, output, output_len);
00398 if (res != SHISHI_OK)
00399 return GSASL_KERBEROS_V5_INTERNAL_ERROR;
00400 }
00401 else
00402 {
00403 *output_len = input_len;
00404 *output = malloc (input_len);
00405 if (!*output)
00406 return GSASL_MALLOC_ERROR;
00407 memcpy (*output, input, input_len);
00408 }
00409
00410 return GSASL_OK;
00411 }
00412
00413 int
00414 _gsasl_kerberos_v5_client_decode (Gsasl_session * sctx,
00415 void *mech_data,
00416 const char *input,
00417 size_t input_len,
00418 char *output, size_t * output_len)
00419 {
00420 struct _Gsasl_kerberos_v5_client_state *state = mech_data;
00421
00422 if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
00423 {
00424 return GSASL_INTEGRITY_ERROR;
00425 }
00426 else if (state && state->sessionkey
00427 && state->clientqop & GSASL_QOP_AUTH_INT)
00428 {
00429 return GSASL_INTEGRITY_ERROR;
00430 }
00431 else
00432 {
00433 *output_len = input_len;
00434 *output = malloc (input_len);
00435 if (!*output)
00436 return GSASL_MALLOC_ERROR;
00437 memcpy (*output, input, input_len);
00438 }
00439
00440 return GSASL_OK;
00441 }
00442
00443 int
00444 _gsasl_kerberos_v5_client_finish (Gsasl_session * sctx, void *mech_data)
00445 {
00446 struct _Gsasl_kerberos_v5_client_state *state = mech_data;
00447
00448 shishi_done (state->sh);
00449 free (state);
00450
00451 return GSASL_OK;
00452 }