void _gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor) { krb5_keyblock *key; krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, (int32_t *)&ctx->gk5c.seqnumlo); ctx->gk5c.seqnumhi = 0; if (acceptor) { if (ctx->auth_context->local_subkey) key = ctx->auth_context->local_subkey; else key = ctx->auth_context->remote_subkey; } else { if (ctx->auth_context->remote_subkey) key = ctx->auth_context->remote_subkey; else key = ctx->auth_context->local_subkey; } if (key == NULL) key = ctx->auth_context->keyblock; if (key == NULL) return; switch (key->keytype) { case ETYPE_DES_CBC_CRC: case ETYPE_DES_CBC_MD4: case ETYPE_DES_CBC_MD5: case ETYPE_DES3_CBC_MD5: case ETYPE_OLD_DES3_CBC_SHA1: case ETYPE_DES3_CBC_SHA1: case ETYPE_ARCFOUR_HMAC_MD5: case ETYPE_ARCFOUR_HMAC_MD5_56: break; default : ctx->more_flags |= IS_CFX; ctx->gk5c.flags &= ~(GK5C_ACCEPTOR_SUBKEY | GK5C_DCE_STYLE); if (acceptor) { ctx->gk5c.flags |= GK5C_ACCEPTOR; if (ctx->auth_context->local_subkey) ctx->gk5c.flags |= GK5C_ACCEPTOR_SUBKEY; } else { if (ctx->auth_context->remote_subkey) ctx->gk5c.flags |= GK5C_ACCEPTOR_SUBKEY; } if (ctx->flags & GSS_C_DCE_STYLE) ctx->gk5c.flags |= GK5C_DCE_STYLE; break; } if (ctx->gk5c.crypto) krb5_crypto_destroy(context, ctx->gk5c.crypto); krb5_crypto_init(context, key, 0, &ctx->gk5c.crypto); }
static void test_ap(krb5_context context, krb5_principal target, krb5_principal server, krb5_keytab keytab, krb5_ccache ccache, const krb5_flags client_flags) { krb5_error_code ret; krb5_auth_context client_ac = NULL, server_ac = NULL; krb5_data data; krb5_flags server_flags; krb5_ticket *ticket = NULL; int32_t server_seq, client_seq; ret = krb5_mk_req_exact(context, &client_ac, client_flags, target, NULL, ccache, &data); if (ret) krb5_err(context, 1, ret, "krb5_mk_req_exact"); ret = krb5_rd_req(context, &server_ac, &data, server, keytab, &server_flags, &ticket); if (ret) krb5_err(context, 1, ret, "krb5_rd_req"); if (server_flags & AP_OPTS_MUTUAL_REQUIRED) { krb5_ap_rep_enc_part *repl; krb5_data_free(&data); if ((client_flags & AP_OPTS_MUTUAL_REQUIRED) == 0) krb5_errx(context, 1, "client flag missing mutual req"); ret = krb5_mk_rep (context, server_ac, &data); if (ret) krb5_err(context, 1, ret, "krb5_mk_rep"); ret = krb5_rd_rep (context, client_ac, &data, &repl); if (ret) krb5_err(context, 1, ret, "krb5_rd_rep"); krb5_free_ap_rep_enc_part (context, repl); } else { if (client_flags & AP_OPTS_MUTUAL_REQUIRED) krb5_errx(context, 1, "server flag missing mutual req"); } krb5_auth_con_getremoteseqnumber(context, server_ac, &server_seq); krb5_auth_con_getremoteseqnumber(context, client_ac, &client_seq); if (server_seq != client_seq) krb5_errx(context, 1, "seq num differ"); krb5_auth_con_getlocalseqnumber(context, server_ac, &server_seq); krb5_auth_con_getlocalseqnumber(context, client_ac, &client_seq); if (server_seq != client_seq) krb5_errx(context, 1, "seq num differ"); krb5_data_free(&data); krb5_auth_con_free(context, client_ac); krb5_auth_con_free(context, server_ac); if (verify_pac) { krb5_pac pac; ret = krb5_ticket_get_authorization_data_type(context, ticket, KRB5_AUTHDATA_WIN2K_PAC, &data); if (ret) krb5_err(context, 1, ret, "get pac"); ret = krb5_pac_parse(context, data.data, data.length, &pac); if (ret) krb5_err(context, 1, ret, "pac parse"); krb5_pac_free(context, pac); } krb5_free_ticket(context, ticket); }
static OM_uint32 acceptor_wait_for_dcestyle(OM_uint32 * minor_status, gsskrb5_ctx ctx, krb5_context context, const gss_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t * src_name, gss_OID * mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec, gss_cred_id_t * delegated_cred_handle) { OM_uint32 ret; krb5_error_code kret; krb5_data inbuf; int32_t r_seq_number, l_seq_number; /* * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP */ inbuf.length = input_token_buffer->length; inbuf.data = input_token_buffer->value; /* * We need to remeber the old remote seq_number, then check if the * client has replied with our local seq_number, and then reset * the remote seq_number to the old value */ { kret = krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &l_seq_number); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } kret = krb5_auth_con_getremoteseqnumber(context, ctx->auth_context, &r_seq_number); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } kret = krb5_auth_con_setremoteseqnumber(context, ctx->auth_context, l_seq_number); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } } /* * We need to verify the AP_REP, but we need to flag that this is * DCE_STYLE, so don't check the timestamps this time, but put the * flag DO_TIME back afterward. */ { krb5_ap_rep_enc_part *repl; int32_t auth_flags; krb5_auth_con_removeflags(context, ctx->auth_context, KRB5_AUTH_CONTEXT_DO_TIME, &auth_flags); kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } krb5_free_ap_rep_enc_part(context, repl); krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); } /* We need to check the liftime */ { OM_uint32 lifetime_rec; ret = _gsskrb5_lifetime_left(minor_status, context, ctx->lifetime, &lifetime_rec); if (ret) { return ret; } if (lifetime_rec == 0) { return GSS_S_CONTEXT_EXPIRED; } if (time_rec) *time_rec = lifetime_rec; } /* We need to give the caller the flags which are in use */ if (ret_flags) *ret_flags = ctx->flags; if (src_name) { kret = krb5_copy_principal(context, ctx->source, (gsskrb5_name*)src_name); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } } /* * After the krb5_rd_rep() the remote and local seq_number should * be the same, because the client just replies the seq_number * from our AP-REP in its AP-REP, but then the client uses the * seq_number from its AP-REQ for GSS_wrap() */ { int32_t tmp_r_seq_number, tmp_l_seq_number; kret = krb5_auth_con_getremoteseqnumber(context, ctx->auth_context, &tmp_r_seq_number); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } kret = krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &tmp_l_seq_number); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } /* * Here we check if the client has responsed with our local seq_number, */ if (tmp_r_seq_number != tmp_l_seq_number) { return GSS_S_UNSEQ_TOKEN; } } /* * We need to reset the remote seq_number, because the client will use, * the old one for the GSS_wrap() calls */ { kret = krb5_auth_con_setremoteseqnumber(context, ctx->auth_context, r_seq_number); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } } return gsskrb5_acceptor_ready(minor_status, ctx, context, delegated_cred_handle); }
OM_uint32 _gssapi_wrap_arcfour(OM_uint32 * minor_status, const gsskrb5_ctx context_handle, krb5_context context, int conf_req_flag, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, int * conf_state, gss_buffer_t output_message_buffer, krb5_keyblock *key) { u_char Klocaldata[16], k6_data[16], *p, *p0; size_t len, total_len, datalen; krb5_keyblock Klocal; krb5_error_code ret; int32_t seq_number; if (conf_state) *conf_state = 0; datalen = input_message_buffer->length; if (IS_DCE_STYLE(context_handle)) { len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); total_len += datalen; } else { datalen += 1; /* padding */ len = datalen + GSS_ARCFOUR_WRAP_TOKEN_SIZE; _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); } output_message_buffer->length = total_len; output_message_buffer->value = malloc (total_len); if (output_message_buffer->value == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } p0 = _gssapi_make_mech_header(output_message_buffer->value, len, GSS_KRB5_MECHANISM); p = p0; *p++ = 0x02; /* TOK_ID */ *p++ = 0x01; *p++ = 0x11; /* SGN_ALG */ *p++ = 0x00; if (conf_req_flag) { *p++ = 0x10; /* SEAL_ALG */ *p++ = 0x00; } else { *p++ = 0xff; /* SEAL_ALG */ *p++ = 0xff; } *p++ = 0xff; /* Filler */ *p++ = 0xff; p = NULL; HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); krb5_auth_con_getlocalseqnumber (context, context_handle->auth_context, &seq_number); _gss_mg_encode_be_uint32(seq_number, p0 + 8); krb5_auth_con_setlocalseqnumber (context, context_handle->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); memset (p0 + 8 + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4); krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */ /* p points to data */ p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE; memcpy(p, input_message_buffer->value, input_message_buffer->length); if (!IS_DCE_STYLE(context_handle)) p[input_message_buffer->length] = 1; /* padding */ ret = arcfour_mic_cksum(context, key, KRB5_KU_USAGE_SEAL, p0 + 16, 8, /* SGN_CKSUM */ p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */ p0 + 24, 8, /* Confounder */ p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen); if (ret) { *minor_status = ret; _gsskrb5_release_buffer(minor_status, output_message_buffer); return GSS_S_FAILURE; } { int i; Klocal.keytype = key->keytype; Klocal.keyvalue.data = Klocaldata; Klocal.keyvalue.length = sizeof(Klocaldata); for (i = 0; i < 16; i++) Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; } ret = arcfour_mic_key(context, &Klocal, p0 + 8, 4, /* SND_SEQ */ k6_data, sizeof(k6_data)); memset(Klocaldata, 0, sizeof(Klocaldata)); if (ret) { _gsskrb5_release_buffer(minor_status, output_message_buffer); *minor_status = ret; return GSS_S_FAILURE; } if(conf_req_flag) { EVP_CIPHER_CTX rc4_key; EVP_CIPHER_CTX_init(&rc4_key); EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8 + datalen); EVP_CIPHER_CTX_cleanup(&rc4_key); } memset(k6_data, 0, sizeof(k6_data)); ret = arcfour_mic_key(context, key, p0 + 16, 8, /* SGN_CKSUM */ k6_data, sizeof(k6_data)); if (ret) { _gsskrb5_release_buffer(minor_status, output_message_buffer); *minor_status = ret; return GSS_S_FAILURE; } { EVP_CIPHER_CTX rc4_key; EVP_CIPHER_CTX_init(&rc4_key); EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); EVP_Cipher(&rc4_key, p0 + 8, p0 + 8 /* SND_SEQ */, 8); EVP_CIPHER_CTX_cleanup(&rc4_key); memset(k6_data, 0, sizeof(k6_data)); } if (conf_state) *conf_state = conf_req_flag; *minor_status = 0; return GSS_S_COMPLETE; }
OM_uint32 _gssapi_get_mic_arcfour(OM_uint32 * minor_status, const gsskrb5_ctx context_handle, krb5_context context, gss_qop_t qop_req, const gss_buffer_t message_buffer, gss_buffer_t message_token, krb5_keyblock *key) { krb5_error_code ret; int32_t seq_number; size_t len, total_len; u_char k6_data[16], *p0, *p; EVP_CIPHER_CTX rc4_key; _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM); message_token->length = total_len; message_token->value = malloc (total_len); if (message_token->value == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } p0 = _gssapi_make_mech_header(message_token->value, len, GSS_KRB5_MECHANISM); p = p0; *p++ = 0x01; /* TOK_ID */ *p++ = 0x01; *p++ = 0x11; /* SGN_ALG */ *p++ = 0x00; *p++ = 0xff; /* Filler */ *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; p = NULL; ret = arcfour_mic_cksum(context, key, KRB5_KU_USAGE_SIGN, p0 + 16, 8, /* SGN_CKSUM */ p0, 8, /* TOK_ID, SGN_ALG, Filer */ message_buffer->value, message_buffer->length, NULL, 0); if (ret) { _gsskrb5_release_buffer(minor_status, message_token); *minor_status = ret; return GSS_S_FAILURE; } ret = arcfour_mic_key(context, key, p0 + 16, 8, /* SGN_CKSUM */ k6_data, sizeof(k6_data)); if (ret) { _gsskrb5_release_buffer(minor_status, message_token); *minor_status = ret; return GSS_S_FAILURE; } HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); krb5_auth_con_getlocalseqnumber (context, context_handle->auth_context, &seq_number); p = p0 + 8; /* SND_SEQ */ _gss_mg_encode_be_uint32(seq_number, p); krb5_auth_con_setlocalseqnumber (context, context_handle->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4); EVP_CIPHER_CTX_init(&rc4_key); EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); EVP_Cipher(&rc4_key, p, p, 8); EVP_CIPHER_CTX_cleanup(&rc4_key); memset(k6_data, 0, sizeof(k6_data)); *minor_status = 0; return GSS_S_COMPLETE; }
static OM_uint32 export_lucid_sec_context_v1(OM_uint32 *minor_status, gsskrb5_ctx context_handle, krb5_context context, gss_buffer_set_t *data_set) { krb5_storage *sp = NULL; OM_uint32 major_status = GSS_S_COMPLETE; krb5_error_code ret; krb5_keyblock *key = NULL; int32_t number; int is_cfx; krb5_data data; *minor_status = 0; HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); _gsskrb5i_is_cfx(context_handle, &is_cfx); sp = krb5_storage_emem(); if (sp == NULL) { _gsskrb5_clear_status(); ret = ENOMEM; goto out; } ret = krb5_store_int32(sp, 1); if (ret) goto out; ret = krb5_store_int32(sp, (context_handle->more_flags & LOCAL) ? 1 : 0); if (ret) goto out; ret = krb5_store_int32(sp, context_handle->lifetime); if (ret) goto out; krb5_auth_con_getlocalseqnumber (context, context_handle->auth_context, &number); ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */ if (ret) goto out; ret = krb5_store_uint32(sp, (uint32_t)number); if (ret) goto out; krb5_auth_getremoteseqnumber (context, context_handle->auth_context, &number); ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */ if (ret) goto out; ret = krb5_store_uint32(sp, (uint32_t)number); if (ret) goto out; ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0); if (ret) goto out; ret = _gsskrb5i_get_token_key(context_handle, context, &key); if (ret) goto out; if (is_cfx == 0) { int sign_alg, seal_alg; switch (key->keytype) { case ETYPE_DES_CBC_CRC: case ETYPE_DES_CBC_MD4: case ETYPE_DES_CBC_MD5: sign_alg = 0; seal_alg = 0; break; case ETYPE_DES3_CBC_MD5: case ETYPE_DES3_CBC_SHA1: sign_alg = 4; seal_alg = 2; break; case ETYPE_ARCFOUR_HMAC_MD5: case ETYPE_ARCFOUR_HMAC_MD5_56: sign_alg = 17; seal_alg = 16; break; default: sign_alg = -1; seal_alg = -1; break; } ret = krb5_store_int32(sp, sign_alg); if (ret) goto out; ret = krb5_store_int32(sp, seal_alg); if (ret) goto out; /* ctx_key */ ret = krb5_store_keyblock(sp, *key); if (ret) goto out; } else { int subkey_p = (context_handle->more_flags & ACCEPTOR_SUBKEY) ? 1 : 0; /* have_acceptor_subkey */ ret = krb5_store_int32(sp, subkey_p); if (ret) goto out; /* ctx_key */ ret = krb5_store_keyblock(sp, *key); if (ret) goto out; /* acceptor_subkey */ if (subkey_p) { ret = krb5_store_keyblock(sp, *key); if (ret) goto out; } } ret = krb5_storage_to_data(sp, &data); if (ret) goto out; { gss_buffer_desc ad_data; ad_data.value = data.data; ad_data.length = data.length; ret = gss_add_buffer_set_member(minor_status, &ad_data, data_set); krb5_data_free(&data); if (ret) goto out; } out: if (key) krb5_free_keyblock (context, key); if (sp) krb5_storage_free(sp); if (ret) { *minor_status = ret; major_status = GSS_S_FAILURE; } HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return major_status; }