/* * Marshal a KRB-PRIV message into der_out, encrypted with key. Store the * ciphertext in enc_out. Use the timestamp and sequence number from rdata and * the addresses from local_addr and remote_addr (the second of which may be * NULL). der_out and enc_out should be freed by the caller when finished. */ static krb5_error_code create_krbpriv(krb5_context context, const krb5_data *userdata, krb5_key key, const krb5_replay_data *rdata, krb5_address *local_addr, krb5_address *remote_addr, krb5_data *cstate, krb5_data *der_out, krb5_enc_data *enc_out) { krb5_enctype enctype = krb5_k_key_enctype(context, key); krb5_error_code ret; krb5_priv privmsg; krb5_priv_enc_part encpart; krb5_data *der_encpart = NULL, *der_krbpriv; size_t enclen; memset(&privmsg, 0, sizeof(privmsg)); privmsg.enc_part.kvno = 0; privmsg.enc_part.enctype = enctype; encpart.user_data = *userdata; encpart.s_address = local_addr; encpart.r_address = remote_addr; encpart.timestamp = rdata->timestamp; encpart.usec = rdata->usec; encpart.seq_number = rdata->seq; /* Start by encoding the to-be-encrypted part of the message. */ ret = encode_krb5_enc_priv_part(&encpart, &der_encpart); if (ret) return ret; /* put together an eblock for this encryption */ ret = krb5_c_encrypt_length(context, enctype, der_encpart->length, &enclen); if (ret) goto cleanup; ret = alloc_data(&privmsg.enc_part.ciphertext, enclen); if (ret) goto cleanup; ret = krb5_k_encrypt(context, key, KRB5_KEYUSAGE_KRB_PRIV_ENCPART, (cstate->length > 0) ? cstate : NULL, der_encpart, &privmsg.enc_part); if (ret) goto cleanup; ret = encode_krb5_priv(&privmsg, &der_krbpriv); if (ret) goto cleanup; *der_out = *der_krbpriv; free(der_krbpriv); *enc_out = privmsg.enc_part; memset(&privmsg.enc_part, 0, sizeof(privmsg.enc_part)); cleanup: zapfree(privmsg.enc_part.ciphertext.data, privmsg.enc_part.ciphertext.length); zapfreedata(der_encpart); return ret; }
krb5_error_code KRB5_CALLCONV krb5_auth_con_initivector(krb5_context context, krb5_auth_context auth_context) { krb5_error_code ret; krb5_enctype enctype; if (auth_context->key) { size_t blocksize; enctype = krb5_k_key_enctype(context, auth_context->key); if ((ret = krb5_c_block_size(context, enctype, &blocksize))) return(ret); if ((auth_context->i_vector = (krb5_pointer)calloc(1,blocksize))) { return 0; } return ENOMEM; } return EINVAL; /* XXX need an error for no keyblock */ }
static krb5_error_code mk_priv_basic(krb5_context context, const krb5_data *userdata, krb5_key key, krb5_replay_data *replaydata, krb5_address *local_addr, krb5_address *remote_addr, krb5_data *cstate, krb5_data *outbuf) { krb5_enctype enctype = krb5_k_key_enctype(context, key); krb5_error_code retval; krb5_priv privmsg; krb5_priv_enc_part privmsg_enc_part; krb5_data *scratch1, *scratch2; size_t enclen; privmsg.enc_part.kvno = 0; /* XXX allow user-set? */ privmsg.enc_part.enctype = enctype; privmsg_enc_part.user_data = *userdata; privmsg_enc_part.s_address = local_addr; privmsg_enc_part.r_address = remote_addr; /* We should check too make sure one exists. */ privmsg_enc_part.timestamp = replaydata->timestamp; privmsg_enc_part.usec = replaydata->usec; privmsg_enc_part.seq_number = replaydata->seq; /* start by encoding to-be-encrypted part of the message */ if ((retval = encode_krb5_enc_priv_part(&privmsg_enc_part, &scratch1))) return retval; /* put together an eblock for this encryption */ if ((retval = krb5_c_encrypt_length(context, enctype, scratch1->length, &enclen))) goto clean_scratch; privmsg.enc_part.ciphertext.length = enclen; if (!(privmsg.enc_part.ciphertext.data = malloc(privmsg.enc_part.ciphertext.length))) { retval = ENOMEM; goto clean_scratch; } if ((retval = krb5_k_encrypt(context, key, KRB5_KEYUSAGE_KRB_PRIV_ENCPART, (cstate->length > 0) ? cstate : NULL, scratch1, &privmsg.enc_part))) goto clean_encpart; if ((retval = encode_krb5_priv(&privmsg, &scratch2))) goto clean_encpart; *outbuf = *scratch2; free(scratch2); retval = 0; clean_encpart: memset(privmsg.enc_part.ciphertext.data, 0, privmsg.enc_part.ciphertext.length); free(privmsg.enc_part.ciphertext.data); privmsg.enc_part.ciphertext.length = 0; privmsg.enc_part.ciphertext.data = 0; clean_scratch: memset(scratch1->data, 0, scratch1->length); krb5_free_data(context, scratch1); return retval; }
OM_uint32 KRB5_CALLCONV krb5_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context, int prf_key, const gss_buffer_t prf_in, ssize_t desired_output_len, gss_buffer_t prf_out) { krb5_error_code code; krb5_key key = NULL; krb5_gss_ctx_id_t ctx; int i; OM_uint32 minor; size_t prflen; krb5_data t, ns; unsigned char *p; prf_out->length = 0; prf_out->value = NULL; t.length = 0; t.data = NULL; ns.length = 0; ns.data = NULL; ctx = (krb5_gss_ctx_id_t)context; switch (prf_key) { case GSS_C_PRF_KEY_FULL: if (ctx->have_acceptor_subkey) { key = ctx->acceptor_subkey; break; } /* fallthrough */ case GSS_C_PRF_KEY_PARTIAL: key = ctx->subkey; break; default: code = EINVAL; goto cleanup; } if (key == NULL) { code = EINVAL; goto cleanup; } prf_out->value = k5alloc(desired_output_len, &code); if (prf_out->value == NULL) { code = KG_INPUT_TOO_LONG; goto cleanup; } prf_out->length = desired_output_len; code = krb5_c_prf_length(ctx->k5_context, krb5_k_key_enctype(ctx->k5_context, key), &prflen); if (code != 0) goto cleanup; ns.length = 4 + prf_in->length; ns.data = k5alloc(ns.length, &code); if (ns.data == NULL) { code = KG_INPUT_TOO_LONG; goto cleanup; } t.length = prflen; t.data = k5alloc(t.length, &code); if (t.data == NULL) goto cleanup; memcpy(ns.data + 4, prf_in->value, prf_in->length); i = 0; p = (unsigned char *)prf_out->value; while (desired_output_len > 0) { store_32_be(i, ns.data); code = krb5_k_prf(ctx->k5_context, key, &ns, &t); if (code != 0) goto cleanup; memcpy(p, t.data, MIN(t.length, desired_output_len)); p += t.length; desired_output_len -= t.length; i++; } cleanup: if (code != 0) gss_release_buffer(&minor, prf_out); krb5_free_data_contents(ctx->k5_context, &ns); krb5_free_data_contents(ctx->k5_context, &t); *minor_status = (OM_uint32)code; return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE; }
krb5_error_code KRB5_CALLCONV krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context, krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_data *outbuf) { krb5_error_code retval; krb5_checksum checksum; krb5_checksum *checksump = 0; krb5_auth_context new_auth_context; krb5_enctype *desired_etypes = NULL; krb5_ap_req request; krb5_data *scratch = 0; krb5_data *toutbuf; request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK; request.authenticator.ciphertext.data = NULL; request.ticket = 0; if (!in_creds->ticket.length) return(KRB5_NO_TKT_SUPPLIED); if ((ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) && !(ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) return(EINVAL); /* we need a native ticket */ if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket))) return(retval); /* verify that the ticket is not expired */ if ((retval = krb5int_validate_times(context, &in_creds->times)) != 0) goto cleanup; /* generate auth_context if needed */ if (*auth_context == NULL) { if ((retval = krb5_auth_con_init(context, &new_auth_context))) goto cleanup; *auth_context = new_auth_context; } if ((*auth_context)->key != NULL) { krb5_k_free_key(context, (*auth_context)->key); (*auth_context)->key = NULL; } /* set auth context keyblock */ if ((retval = krb5_k_create_key(context, &in_creds->keyblock, &((*auth_context)->key)))) goto cleanup; /* generate seq number if needed */ if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && ((*auth_context)->local_seq_number == 0)) { if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock, &(*auth_context)->local_seq_number))) goto cleanup; } /* generate subkey if needed */ if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->send_subkey)) { retval = k5_generate_and_save_subkey(context, *auth_context, &in_creds->keyblock, in_creds->keyblock.enctype); if (retval) goto cleanup; } if (!in_data && (*auth_context)->checksum_func) { retval = (*auth_context)->checksum_func( context, *auth_context, (*auth_context)->checksum_func_data, &in_data); if (retval) goto cleanup; } if (in_data) { if ((*auth_context)->req_cksumtype == 0x8003) { /* XXX Special hack for GSSAPI */ checksum.checksum_type = 0x8003; checksum.length = in_data->length; checksum.contents = (krb5_octet *) in_data->data; } else { krb5_enctype enctype = krb5_k_key_enctype(context, (*auth_context)->key); krb5_cksumtype cksumtype = ap_req_cksum(context, *auth_context, enctype); if ((retval = krb5_k_make_checksum(context, cksumtype, (*auth_context)->key, KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM, in_data, &checksum))) goto cleanup_cksum; } checksump = &checksum; } /* Generate authenticator */ if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof( krb5_authenticator))) == NULL) { retval = ENOMEM; goto cleanup_cksum; } if (ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) { if ((*auth_context)->permitted_etypes == NULL) { retval = krb5_get_tgs_ktypes(context, in_creds->server, &desired_etypes); if (retval) goto cleanup_cksum; } else desired_etypes = (*auth_context)->permitted_etypes; } TRACE_MK_REQ(context, in_creds, (*auth_context)->local_seq_number, (*auth_context)->send_subkey, &in_creds->keyblock); if ((retval = generate_authenticator(context, (*auth_context)->authentp, in_creds->client, checksump, (*auth_context)->send_subkey, (*auth_context)->local_seq_number, in_creds->authdata, (*auth_context)->ad_context, desired_etypes, in_creds->keyblock.enctype))) goto cleanup_cksum; /* encode the authenticator */ if ((retval = encode_krb5_authenticator((*auth_context)->authentp, &scratch))) goto cleanup_cksum; /* call the encryption routine */ if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock, KRB5_KEYUSAGE_AP_REQ_AUTH, scratch, &request.authenticator))) goto cleanup_cksum; if ((retval = encode_krb5_ap_req(&request, &toutbuf))) goto cleanup_cksum; *outbuf = *toutbuf; free(toutbuf); cleanup_cksum: /* Null out these fields, to prevent pointer sharing problems; * they were supplied by the caller */ if ((*auth_context)->authentp != NULL) { (*auth_context)->authentp->client = NULL; (*auth_context)->authentp->checksum = NULL; } if (checksump && checksump->checksum_type != 0x8003) free(checksump->contents); cleanup: if (desired_etypes && desired_etypes != (*auth_context)->permitted_etypes) free(desired_etypes); if (request.ticket) krb5_free_ticket(context, request.ticket); if (request.authenticator.ciphertext.data) { (void) memset(request.authenticator.ciphertext.data, 0, request.authenticator.ciphertext.length); free(request.authenticator.ciphertext.data); } if (scratch) { memset(scratch->data, 0, scratch->length); free(scratch->data); free(scratch); } return retval; }
static krb5_error_code rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, const krb5_ap_req *req, krb5_const_principal server, krb5_keytab keytab, krb5_flags *ap_req_options, krb5_ticket **ticket, int check_valid_flag) { krb5_error_code retval = 0; krb5_enctype *desired_etypes = NULL; int desired_etypes_len = 0; int rfc4537_etypes_len = 0; krb5_enctype *permitted_etypes = NULL; int permitted_etypes_len = 0; krb5_keyblock decrypt_key; decrypt_key.enctype = ENCTYPE_NULL; decrypt_key.contents = NULL; req->ticket->enc_part2 = NULL; /* if (req->ap_options & AP_OPTS_USE_SESSION_KEY) do we need special processing here ? */ /* decrypt the ticket */ if ((*auth_context)->key) { /* User to User authentication */ if ((retval = krb5_decrypt_tkt_part(context, &(*auth_context)->key->keyblock, req->ticket))) goto cleanup; if (check_valid_flag) { decrypt_key = (*auth_context)->key->keyblock; (*auth_context)->key->keyblock.contents = NULL; } krb5_k_free_key(context, (*auth_context)->key); (*auth_context)->key = NULL; } else { retval = decrypt_ticket(context, req, server, keytab, check_valid_flag ? &decrypt_key : NULL); if (retval) goto cleanup; } TRACE_RD_REQ_TICKET(context, req->ticket->enc_part2->client, req->ticket->server, req->ticket->enc_part2->session); /* XXX this is an evil hack. check_valid_flag is set iff the call is not from inside the kdc. we can use this to determine which key usage to use */ #ifndef LEAN_CLIENT if ((retval = decrypt_authenticator(context, req, &((*auth_context)->authentp), check_valid_flag))) goto cleanup; #endif if (!krb5_principal_compare(context, (*auth_context)->authentp->client, req->ticket->enc_part2->client)) { retval = KRB5KRB_AP_ERR_BADMATCH; goto cleanup; } if ((*auth_context)->remote_addr && !krb5_address_search(context, (*auth_context)->remote_addr, req->ticket->enc_part2->caddrs)) { retval = KRB5KRB_AP_ERR_BADADDR; goto cleanup; } if (!server) { server = req->ticket->server; } /* Get an rcache if necessary. */ if (((*auth_context)->rcache == NULL) && ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && server) { if ((retval = krb5_get_server_rcache(context, krb5_princ_component(context,server,0), &(*auth_context)->rcache))) goto cleanup; } /* okay, now check cross-realm policy */ #if defined(_SINGLE_HOP_ONLY) /* Single hop cross-realm tickets only */ { krb5_transited *trans = &(req->ticket->enc_part2->transited); /* If the transited list is empty, then we have at most one hop */ if (trans->tr_contents.length > 0 && trans->tr_contents.data[0]) retval = KRB5KRB_AP_ERR_ILL_CR_TKT; } #elif defined(_NO_CROSS_REALM) /* No cross-realm tickets */ { char * lrealm; krb5_data * realm; krb5_transited * trans; realm = krb5_princ_realm(context, req->ticket->enc_part2->client); trans = &(req->ticket->enc_part2->transited); /* * If the transited list is empty, then we have at most one hop * So we also have to check that the client's realm is the local one */ krb5_get_default_realm(context, &lrealm); if ((trans->tr_contents.length > 0 && trans->tr_contents.data[0]) || !data_eq_string(*realm, lrealm)) { retval = KRB5KRB_AP_ERR_ILL_CR_TKT; } free(lrealm); } #else /* Hierarchical Cross-Realm */ { krb5_data * realm; krb5_transited * trans; realm = krb5_princ_realm(context, req->ticket->enc_part2->client); trans = &(req->ticket->enc_part2->transited); /* * If the transited list is not empty, then check that all realms * transited are within the hierarchy between the client's realm * and the local realm. */ if (trans->tr_contents.length > 0 && trans->tr_contents.data[0]) { retval = krb5_check_transited_list(context, &(trans->tr_contents), realm, krb5_princ_realm (context,server)); } } #endif if (retval) goto cleanup; /* only check rcache if sender has provided one---some services may not be able to use replay caches (such as datagram servers) */ if ((*auth_context)->rcache) { krb5_donot_replay rep; krb5_tkt_authent tktauthent; tktauthent.ticket = req->ticket; tktauthent.authenticator = (*auth_context)->authentp; if (!(retval = krb5_auth_to_rep(context, &tktauthent, &rep))) { retval = krb5_rc_hash_message(context, &req->authenticator.ciphertext, &rep.msghash); if (!retval) { retval = krb5_rc_store(context, (*auth_context)->rcache, &rep); free(rep.msghash); } free(rep.server); free(rep.client); } if (retval) goto cleanup; } retval = krb5int_validate_times(context, &req->ticket->enc_part2->times); if (retval != 0) goto cleanup; if ((retval = krb5_check_clockskew(context, (*auth_context)->authentp->ctime))) goto cleanup; if (check_valid_flag) { if (req->ticket->enc_part2->flags & TKT_FLG_INVALID) { retval = KRB5KRB_AP_ERR_TKT_INVALID; goto cleanup; } if ((retval = krb5_authdata_context_init(context, &(*auth_context)->ad_context))) goto cleanup; if ((retval = krb5int_authdata_verify(context, (*auth_context)->ad_context, AD_USAGE_MASK, auth_context, &decrypt_key, req))) goto cleanup; } /* read RFC 4537 etype list from sender */ retval = decode_etype_list(context, (*auth_context)->authentp, &desired_etypes, &rfc4537_etypes_len); if (retval != 0) goto cleanup; if (desired_etypes == NULL) desired_etypes = (krb5_enctype *)calloc(4, sizeof(krb5_enctype)); else desired_etypes = (krb5_enctype *)realloc(desired_etypes, (rfc4537_etypes_len + 4) * sizeof(krb5_enctype)); if (desired_etypes == NULL) { retval = ENOMEM; goto cleanup; } desired_etypes_len = rfc4537_etypes_len; /* * RFC 4537: * * If the EtypeList is present and the server prefers an enctype from * the client's enctype list over that of the AP-REQ authenticator * subkey (if that is present) or the service ticket session key, the * server MUST create a subkey using that enctype. This negotiated * subkey is sent in the subkey field of AP-REP message, and it is then * used as the protocol key or base key [RFC3961] for subsequent * communication. * * If the enctype of the ticket session key is included in the enctype * list sent by the client, it SHOULD be the last on the list; * otherwise, this enctype MUST NOT be negotiated if it was not included * in the list. * * The second paragraph does appear to contradict the first with respect * to whether it is legal to negotiate the ticket session key type if it * is absent in the EtypeList. A literal reading suggests that we can use * the AP-REQ subkey enctype. Also a client has no way of distinguishing * a server that does not RFC 4537 from one that has chosen the same * enctype as the ticket session key for the acceptor subkey, surely. */ if ((*auth_context)->authentp->subkey != NULL) { desired_etypes[desired_etypes_len++] = (*auth_context)->authentp->subkey->enctype; } desired_etypes[desired_etypes_len++] = req->ticket->enc_part2->session->enctype; desired_etypes[desired_etypes_len] = ENCTYPE_NULL; if (((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) == 0) { if ((*auth_context)->permitted_etypes != NULL) { permitted_etypes = (*auth_context)->permitted_etypes; } else { retval = krb5_get_permitted_enctypes(context, &permitted_etypes); if (retval != 0) goto cleanup; } permitted_etypes_len = krb5int_count_etypes(permitted_etypes); } else { permitted_etypes = NULL; permitted_etypes_len = 0; } /* check if the various etypes are permitted */ retval = negotiate_etype(context, desired_etypes, desired_etypes_len, rfc4537_etypes_len, permitted_etypes, permitted_etypes_len, &(*auth_context)->negotiated_etype); if (retval != 0) goto cleanup; TRACE_RD_REQ_NEGOTIATED_ETYPE(context, (*auth_context)->negotiated_etype); assert((*auth_context)->negotiated_etype != ENCTYPE_NULL); (*auth_context)->remote_seq_number = (*auth_context)->authentp->seq_number; if ((*auth_context)->authentp->subkey) { TRACE_RD_REQ_SUBKEY(context, (*auth_context)->authentp->subkey); if ((retval = krb5_k_create_key(context, (*auth_context)->authentp->subkey, &((*auth_context)->recv_subkey)))) goto cleanup; retval = krb5_k_create_key(context, (*auth_context)->authentp->subkey, &((*auth_context)->send_subkey)); if (retval) { krb5_k_free_key(context, (*auth_context)->recv_subkey); (*auth_context)->recv_subkey = NULL; goto cleanup; } } else { (*auth_context)->recv_subkey = 0; (*auth_context)->send_subkey = 0; } if ((retval = krb5_k_create_key(context, req->ticket->enc_part2->session, &((*auth_context)->key)))) goto cleanup; debug_log_authz_data("ticket", req->ticket->enc_part2->authorization_data); /* * If not AP_OPTS_MUTUAL_REQUIRED then and sequence numbers are used * then the default sequence number is the one's complement of the * sequence number sent ot us. */ if ((!(req->ap_options & AP_OPTS_MUTUAL_REQUIRED)) && (*auth_context)->remote_seq_number) { (*auth_context)->local_seq_number ^= (*auth_context)->remote_seq_number; } if (ticket) if ((retval = krb5_copy_ticket(context, req->ticket, ticket))) goto cleanup; if (ap_req_options) { *ap_req_options = req->ap_options & AP_OPTS_WIRE_MASK; if (rfc4537_etypes_len != 0) *ap_req_options |= AP_OPTS_ETYPE_NEGOTIATION; if ((*auth_context)->negotiated_etype != krb5_k_key_enctype(context, (*auth_context)->key)) *ap_req_options |= AP_OPTS_USE_SUBKEY; } retval = 0; cleanup: if (desired_etypes != NULL) free(desired_etypes); if (permitted_etypes != NULL && permitted_etypes != (*auth_context)->permitted_etypes) free(permitted_etypes); if (retval) { /* only free if we're erroring out...otherwise some applications will need the output. */ if (req->ticket->enc_part2) krb5_free_enc_tkt_part(context, req->ticket->enc_part2); req->ticket->enc_part2 = NULL; } if (check_valid_flag) krb5_free_keyblock_contents(context, &decrypt_key); return retval; }
krb5_error_code KRB5_CALLCONV krb5_mk_safe(krb5_context context, krb5_auth_context auth_context, const krb5_data *userdata, krb5_data *outbuf, krb5_replay_data *outdata) { krb5_error_code retval; krb5_key key; krb5_replay_data replaydata; /* Clear replaydata block */ memset(&replaydata, 0, sizeof(krb5_replay_data)); /* Get key */ if ((key = auth_context->send_subkey) == NULL) key = auth_context->key; /* Get replay info */ if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && (auth_context->rcache == NULL)) return KRB5_RC_REQUIRED; if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && (outdata == NULL)) /* Need a better error */ return KRB5_RC_REQUIRED; if (!auth_context->local_addr) return KRB5_LOCAL_ADDR_REQUIRED; if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) { if ((retval = krb5_us_timeofday(context, &replaydata.timestamp, &replaydata.usec))) return retval; if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) { outdata->timestamp = replaydata.timestamp; outdata->usec = replaydata.usec; } } if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { replaydata.seq = auth_context->local_seq_number++; if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE) outdata->seq = replaydata.seq; } { krb5_address * premote_fulladdr = NULL; krb5_address * plocal_fulladdr; krb5_address remote_fulladdr; krb5_address local_fulladdr; krb5_cksumtype sumtype; CLEANUP_INIT(2); if (auth_context->local_port) { if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr, auth_context->local_port, &local_fulladdr))){ CLEANUP_PUSH(local_fulladdr.contents, free); plocal_fulladdr = &local_fulladdr; } else { goto error; } } else { plocal_fulladdr = auth_context->local_addr; } if (auth_context->remote_addr) { if (auth_context->remote_port) { if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr, auth_context->remote_port, &remote_fulladdr))){ CLEANUP_PUSH(remote_fulladdr.contents, free); premote_fulladdr = &remote_fulladdr; } else { CLEANUP_DONE(); goto error; } } else { premote_fulladdr = auth_context->remote_addr; } } { krb5_enctype enctype = krb5_k_key_enctype(context, key); unsigned int nsumtypes; unsigned int i; krb5_cksumtype *sumtypes; retval = krb5_c_keyed_checksum_types (context, enctype, &nsumtypes, &sumtypes); if (retval) { CLEANUP_DONE (); goto error; } if (nsumtypes == 0) { retval = KRB5_BAD_ENCTYPE; krb5_free_cksumtypes (context, sumtypes); CLEANUP_DONE (); goto error; } for (i = 0; i < nsumtypes; i++) if (auth_context->safe_cksumtype == sumtypes[i]) break; krb5_free_cksumtypes (context, sumtypes); if (i < nsumtypes) sumtype = auth_context->safe_cksumtype; else { switch (enctype) { case ENCTYPE_DES_CBC_MD4: sumtype = CKSUMTYPE_RSA_MD4_DES; break; case ENCTYPE_DES_CBC_MD5: case ENCTYPE_DES_CBC_CRC: sumtype = CKSUMTYPE_RSA_MD5_DES; break; default: retval = krb5int_c_mandatory_cksumtype(context, enctype, &sumtype); if (retval) { CLEANUP_DONE(); goto error; } break; } } } if ((retval = krb5_mk_safe_basic(context, userdata, key, &replaydata, plocal_fulladdr, premote_fulladdr, sumtype, outbuf))) { CLEANUP_DONE(); goto error; } CLEANUP_DONE(); } if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_donot_replay replay; if ((retval = krb5_gen_replay_name(context, auth_context->local_addr, "_safe", &replay.client))) { free(outbuf); goto error; } replay.server = ""; /* XXX */ replay.msghash = NULL; replay.cusec = replaydata.usec; replay.ctime = replaydata.timestamp; if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) { /* should we really error out here? XXX */ free(outbuf); goto error; } free(replay.client); } return 0; error: if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) auth_context->local_seq_number--; return retval; }
/* * krb5_auth_context_size() - Determine the size required to externalize * the krb5_auth_context. */ static krb5_error_code krb5_auth_context_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep) { krb5_error_code kret; krb5_auth_context auth_context; size_t required; krb5_enctype enctype; /* * krb5_auth_context requires at minimum: * krb5_int32 for KV5M_AUTH_CONTEXT * krb5_int32 for auth_context_flags * krb5_int32 for remote_seq_number * krb5_int32 for local_seq_number * krb5_int32 for req_cksumtype * krb5_int32 for safe_cksumtype * krb5_int32 for size of i_vector * krb5_int32 for KV5M_AUTH_CONTEXT */ kret = EINVAL; if ((auth_context = (krb5_auth_context) arg)) { kret = 0; /* Calculate size required by i_vector - ptooey */ if (auth_context->i_vector && auth_context->key) { enctype = krb5_k_key_enctype(kcontext, auth_context->key); kret = krb5_c_block_size(kcontext, enctype, &required); } else { required = 0; } required += sizeof(krb5_int32)*8; /* Calculate size required by remote_addr, if appropriate */ if (!kret && auth_context->remote_addr) { kret = krb5_size_opaque(kcontext, KV5M_ADDRESS, (krb5_pointer) auth_context->remote_addr, &required); if (!kret) required += sizeof(krb5_int32); } /* Calculate size required by remote_port, if appropriate */ if (!kret && auth_context->remote_port) { kret = krb5_size_opaque(kcontext, KV5M_ADDRESS, (krb5_pointer) auth_context->remote_port, &required); if (!kret) required += sizeof(krb5_int32); } /* Calculate size required by local_addr, if appropriate */ if (!kret && auth_context->local_addr) { kret = krb5_size_opaque(kcontext, KV5M_ADDRESS, (krb5_pointer) auth_context->local_addr, &required); if (!kret) required += sizeof(krb5_int32); } /* Calculate size required by local_port, if appropriate */ if (!kret && auth_context->local_port) { kret = krb5_size_opaque(kcontext, KV5M_ADDRESS, (krb5_pointer) auth_context->local_port, &required); if (!kret) required += sizeof(krb5_int32); } /* Calculate size required by key, if appropriate */ if (!kret && auth_context->key) { kret = krb5_size_opaque(kcontext, KV5M_KEYBLOCK, (krb5_pointer) &auth_context->key->keyblock, &required); if (!kret) required += sizeof(krb5_int32); } /* Calculate size required by send_subkey, if appropriate */ if (!kret && auth_context->send_subkey) { kret = krb5_size_opaque(kcontext, KV5M_KEYBLOCK, (krb5_pointer) &auth_context->send_subkey->keyblock, &required); if (!kret) required += sizeof(krb5_int32); } /* Calculate size required by recv_subkey, if appropriate */ if (!kret && auth_context->recv_subkey) { kret = krb5_size_opaque(kcontext, KV5M_KEYBLOCK, (krb5_pointer) &auth_context->recv_subkey->keyblock, &required); if (!kret) required += sizeof(krb5_int32); } /* Calculate size required by authentp, if appropriate */ if (!kret && auth_context->authentp) kret = krb5_size_opaque(kcontext, KV5M_AUTHENTICATOR, (krb5_pointer) auth_context->authentp, &required); } if (!kret) *sizep += required; return(kret); }
/* * krb5_auth_context_externalize() - Externalize the krb5_auth_context. */ static krb5_error_code krb5_auth_context_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain) { krb5_error_code kret; krb5_auth_context auth_context; size_t required; krb5_octet *bp; size_t remain; size_t obuf; krb5_int32 obuf32; krb5_enctype enctype; required = 0; bp = *buffer; remain = *lenremain; kret = EINVAL; if ((auth_context = (krb5_auth_context) arg)) { kret = ENOMEM; if (!krb5_auth_context_size(kcontext, arg, &required) && (required <= remain)) { /* Write fixed portion */ (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain); (void) krb5_ser_pack_int32(auth_context->auth_context_flags, &bp, &remain); (void) krb5_ser_pack_int32(auth_context->remote_seq_number, &bp, &remain); (void) krb5_ser_pack_int32(auth_context->local_seq_number, &bp, &remain); (void) krb5_ser_pack_int32((krb5_int32) auth_context->req_cksumtype, &bp, &remain); (void) krb5_ser_pack_int32((krb5_int32) auth_context->safe_cksumtype, &bp, &remain); kret = 0; /* Now figure out the number of bytes for i_vector and write it */ if (auth_context->i_vector) { enctype = krb5_k_key_enctype(kcontext, auth_context->key); kret = krb5_c_block_size(kcontext, enctype, &obuf); } else { obuf = 0; } /* Convert to signed 32 bit integer */ obuf32 = obuf; if (kret == 0 && obuf != obuf32) kret = EINVAL; if (!kret) (void) krb5_ser_pack_int32(obuf32, &bp, &remain); /* Now copy i_vector */ if (!kret && auth_context->i_vector) (void) krb5_ser_pack_bytes(auth_context->i_vector, obuf, &bp, &remain); /* Now handle remote_addr, if appropriate */ if (!kret && auth_context->remote_addr) { (void) krb5_ser_pack_int32(TOKEN_RADDR, &bp, &remain); kret = krb5_externalize_opaque(kcontext, KV5M_ADDRESS, (krb5_pointer) auth_context->remote_addr, &bp, &remain); } /* Now handle remote_port, if appropriate */ if (!kret && auth_context->remote_port) { (void) krb5_ser_pack_int32(TOKEN_RPORT, &bp, &remain); kret = krb5_externalize_opaque(kcontext, KV5M_ADDRESS, (krb5_pointer) auth_context->remote_addr, &bp, &remain); } /* Now handle local_addr, if appropriate */ if (!kret && auth_context->local_addr) { (void) krb5_ser_pack_int32(TOKEN_LADDR, &bp, &remain); kret = krb5_externalize_opaque(kcontext, KV5M_ADDRESS, (krb5_pointer) auth_context->local_addr, &bp, &remain); } /* Now handle local_port, if appropriate */ if (!kret && auth_context->local_port) { (void) krb5_ser_pack_int32(TOKEN_LPORT, &bp, &remain); kret = krb5_externalize_opaque(kcontext, KV5M_ADDRESS, (krb5_pointer) auth_context->local_addr, &bp, &remain); } /* Now handle keyblock, if appropriate */ if (!kret && auth_context->key) { (void) krb5_ser_pack_int32(TOKEN_KEYBLOCK, &bp, &remain); kret = krb5_externalize_opaque(kcontext, KV5M_KEYBLOCK, (krb5_pointer) &auth_context->key->keyblock, &bp, &remain); } /* Now handle subkey, if appropriate */ if (!kret && auth_context->send_subkey) { (void) krb5_ser_pack_int32(TOKEN_LSKBLOCK, &bp, &remain); kret = krb5_externalize_opaque(kcontext, KV5M_KEYBLOCK, (krb5_pointer) &auth_context-> send_subkey->keyblock, &bp, &remain); } /* Now handle subkey, if appropriate */ if (!kret && auth_context->recv_subkey) { (void) krb5_ser_pack_int32(TOKEN_RSKBLOCK, &bp, &remain); kret = krb5_externalize_opaque(kcontext, KV5M_KEYBLOCK, (krb5_pointer) &auth_context-> recv_subkey->keyblock, &bp, &remain); } /* Now handle authentp, if appropriate */ if (!kret && auth_context->authentp) kret = krb5_externalize_opaque(kcontext, KV5M_AUTHENTICATOR, (krb5_pointer) auth_context->authentp, &bp, &remain); /* * If we were successful, write trailer then update the pointer and * remaining length; */ if (!kret) { /* Write our trailer */ (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain); *buffer = bp; *lenremain = remain; } } } return(kret); }