static krb5_error_code encrypt_fast_reply(struct kdc_request_state *state, const krb5_fast_response *response, krb5_data **fx_fast_reply) { krb5_error_code retval = 0; krb5_enc_data encrypted_reply; krb5_data *encoded_response = NULL; kdc_realm_t *kdc_active_realm = state->realm_data; assert(state->armor_key); retval = encode_krb5_fast_response(response, &encoded_response); if (retval== 0) retval = krb5_encrypt_helper(kdc_context, state->armor_key, KRB5_KEYUSAGE_FAST_REP, encoded_response, &encrypted_reply); if (encoded_response) krb5_free_data(kdc_context, encoded_response); encoded_response = NULL; if (retval == 0) { retval = encode_krb5_pa_fx_fast_reply(&encrypted_reply, fx_fast_reply); krb5_free_data_contents(kdc_context, &encrypted_reply.ciphertext); } return retval; }
krb5_error_code krb5_encrypt_tkt_part(krb5_context context, const krb5_keyblock *srv_key, krb5_ticket *dec_ticket) { krb5_data *scratch; krb5_error_code retval; krb5_enc_tkt_part *dec_tkt_part = dec_ticket->enc_part2; /* start by encoding the to-be-encrypted part. */ if ((retval = encode_krb5_enc_tkt_part(dec_tkt_part, &scratch))) { return retval; } #define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \ krb5_free_data(context, scratch); } /* call the encryption routine */ retval = krb5_encrypt_helper(context, srv_key, KRB5_KEYUSAGE_KDC_REP_TICKET, scratch, &dec_ticket->enc_part); cleanup_scratch(); return(retval); }
static krb5_error_code return_pkinit_kx(krb5_context context, krb5_kdc_req *request, krb5_kdc_rep *reply, krb5_keyblock *encrypting_key, krb5_pa_data **out_padata) { krb5_error_code ret = 0; krb5_keyblock *session = reply->ticket->enc_part2->session; krb5_keyblock *new_session = NULL; krb5_pa_data *pa = NULL; krb5_enc_data enc; krb5_data *scratch = NULL; *out_padata = NULL; enc.ciphertext.data = NULL; if (!krb5_principal_compare(context, request->client, krb5_anonymous_principal())) return 0; /* * The KDC contribution key needs to be a fresh key of an enctype supported * by the client and server. The existing session key meets these * requirements so we use it. */ ret = krb5_c_fx_cf2_simple(context, session, "PKINIT", encrypting_key, "KEYEXCHANGE", &new_session); if (ret) goto cleanup; ret = encode_krb5_encryption_key( session, &scratch); if (ret) goto cleanup; ret = krb5_encrypt_helper(context, encrypting_key, KRB5_KEYUSAGE_PA_PKINIT_KX, scratch, &enc); if (ret) goto cleanup; memset(scratch->data, 0, scratch->length); krb5_free_data(context, scratch); scratch = NULL; ret = encode_krb5_enc_data(&enc, &scratch); if (ret) goto cleanup; pa = malloc(sizeof(krb5_pa_data)); if (pa == NULL) { ret = ENOMEM; goto cleanup; } pa->pa_type = KRB5_PADATA_PKINIT_KX; pa->length = scratch->length; pa->contents = (krb5_octet *) scratch->data; *out_padata = pa; scratch->data = NULL; memset(session->contents, 0, session->length); krb5_free_keyblock_contents(context, session); *session = *new_session; new_session->contents = NULL; cleanup: krb5_free_data_contents(context, &enc.ciphertext); krb5_free_keyblock(context, new_session); krb5_free_data(context, scratch); return ret; }
/* * This routine is the "obtain" function for the ENC_TIMESTAMP * preauthentication type. It take the current time and encrypts it * in the user's key. */ static krb5_error_code obtain_enc_ts_padata(krb5_context context, krb5_pa_data *in_padata, krb5_etype_info etype_info, krb5_keyblock *def_enc_key, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request, krb5_pa_data **out_padata) { krb5_pa_enc_ts pa_enc; krb5_error_code retval; krb5_data * scratch; krb5_enc_data enc_data; krb5_pa_data * pa; retval = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec); if (retval) return retval; if ((retval = encode_krb5_pa_enc_ts(&pa_enc, &scratch)) != 0) return retval; enc_data.ciphertext.data = 0; if ((retval = krb5_encrypt_helper(context, def_enc_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, scratch, &enc_data))) goto cleanup; krb5_free_data(context, scratch); scratch = 0; if ((retval = encode_krb5_enc_data(&enc_data, &scratch)) != 0) goto cleanup; if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) { retval = ENOMEM; goto cleanup; } pa->magic = KV5M_PA_DATA; pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP; pa->length = scratch->length; pa->contents = (krb5_octet *) scratch->data; *out_padata = pa; free(scratch); scratch = 0; retval = 0; cleanup: if (scratch) krb5_free_data(context, scratch); if (enc_data.ciphertext.data) free(enc_data.ciphertext.data); return retval; }
static krb5_error_code ec_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply, krb5_keyblock *encrypting_key, krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq) { krb5_error_code retval = 0; krb5_keyblock *challenge_key = (krb5_keyblock *)modreq; krb5_pa_enc_ts ts; krb5_data *plain = NULL; krb5_enc_data enc; krb5_data *encoded = NULL; krb5_pa_data *pa = NULL; if (challenge_key == NULL) return 0; enc.ciphertext.data = NULL; /* In case of error pass through */ retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec); if (retval == 0) retval = encode_krb5_pa_enc_ts(&ts, &plain); if (retval == 0) retval = krb5_encrypt_helper(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, plain, &enc); if (retval == 0) retval = encode_krb5_enc_data(&enc, &encoded); if (retval == 0) { pa = calloc(1, sizeof(krb5_pa_data)); if (pa == NULL) retval = ENOMEM; } if (retval == 0) { pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; pa->contents = (unsigned char *) encoded->data; pa->length = encoded->length; encoded->data = NULL; *send_pa = pa; pa = NULL; } if (challenge_key) krb5_free_keyblock(context, challenge_key); if (encoded) krb5_free_data(context, encoded); if (plain) krb5_free_data(context, plain); if (enc.ciphertext.data) krb5_free_data_contents(context, &enc.ciphertext); return retval; }
/* Takes the nonce from the challenge and encrypts it into the request. */ static krb5_error_code encrypt_nonce(krb5_context ctx, krb5_keyblock *key, const krb5_pa_otp_challenge *chl, krb5_pa_otp_req *req) { krb5_error_code retval; krb5_enc_data encdata; krb5_data *er; /* Encode the nonce. */ retval = encode_krb5_pa_otp_enc_req(&chl->nonce, &er); if (retval != 0) return retval; /* Do the encryption. */ retval = krb5_encrypt_helper(ctx, key, KRB5_KEYUSAGE_PA_OTP_REQUEST, er, &encdata); krb5_free_data(ctx, er); if (retval != 0) return retval; req->enc_data = encdata; return 0; }
/* Construct an AP-REQ message for a TGS request. */ static krb5_error_code tgs_construct_ap_req(krb5_context context, krb5_data *checksum_data, krb5_creds *tgt, krb5_keyblock *subkey, krb5_data **ap_req_asn1_out) { krb5_cksumtype cksumtype; krb5_error_code ret; krb5_checksum checksum; krb5_authenticator authent; krb5_ap_req ap_req; krb5_data *authent_asn1 = NULL; krb5_ticket *ticket = NULL; krb5_enc_data authent_enc; *ap_req_asn1_out = NULL; memset(&checksum, 0, sizeof(checksum)); memset(&ap_req, 0, sizeof(ap_req)); memset(&authent_enc, 0, sizeof(authent_enc)); /* Determine the authenticator checksum type. */ switch (tgt->keyblock.enctype) { case ENCTYPE_DES_CBC_CRC: case ENCTYPE_DES_CBC_MD4: case ENCTYPE_DES_CBC_MD5: case ENCTYPE_ARCFOUR_HMAC: case ENCTYPE_ARCFOUR_HMAC_EXP: cksumtype = context->kdc_req_sumtype; break; default: ret = krb5int_c_mandatory_cksumtype(context, tgt->keyblock.enctype, &cksumtype); if (ret) goto cleanup; } /* Generate checksum. */ ret = krb5_c_make_checksum(context, cksumtype, &tgt->keyblock, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, checksum_data, &checksum); if (ret) goto cleanup; /* Construct, encode, and encrypt an authenticator. */ authent.subkey = subkey; authent.seq_number = 0; authent.checksum = &checksum; authent.client = tgt->client; authent.authorization_data = tgt->authdata; ret = krb5_us_timeofday(context, &authent.ctime, &authent.cusec); if (ret) goto cleanup; ret = encode_krb5_authenticator(&authent, &authent_asn1); if (ret) goto cleanup; ret = krb5_encrypt_helper(context, &tgt->keyblock, KRB5_KEYUSAGE_TGS_REQ_AUTH, authent_asn1, &authent_enc); if (ret) goto cleanup; ret = decode_krb5_ticket(&tgt->ticket, &ticket); if (ret) goto cleanup; /* Encode the AP-REQ. */ ap_req.authenticator = authent_enc; ap_req.ticket = ticket; ret = encode_krb5_ap_req(&ap_req, ap_req_asn1_out); cleanup: free(checksum.contents); krb5_free_ticket(context, ticket); krb5_free_data_contents(context, &authent_enc.ciphertext); if (authent_asn1 != NULL) zapfree(authent_asn1->data, authent_asn1->length); free(authent_asn1); return ret; }
/* * Construct a TGS request and return its ASN.1 encoding as well as the * timestamp, nonce, and subkey used. The pacb_fn callback allows the caller * to amend the request padata after the nonce and subkey are determined. */ krb5_error_code k5_make_tgs_req(krb5_context context, struct krb5int_fast_request_state *fast_state, krb5_creds *tgt, krb5_flags kdcoptions, krb5_address *const *addrs, krb5_pa_data **in_padata, krb5_creds *desired, k5_pacb_fn pacb_fn, void *pacb_data, krb5_data *req_asn1_out, krb5_timestamp *timestamp_out, krb5_int32 *nonce_out, krb5_keyblock **subkey_out) { krb5_error_code ret; krb5_kdc_req req; krb5_data *authdata_asn1 = NULL, *req_body_asn1 = NULL; krb5_data *ap_req_asn1 = NULL, *tgs_req_asn1 = NULL; krb5_ticket *sec_ticket = NULL; krb5_ticket *sec_ticket_arr[2]; krb5_timestamp time_now; krb5_pa_data **padata = NULL, *pa; krb5_keyblock *subkey = NULL; krb5_enc_data authdata_enc; krb5_enctype enctypes[2], *defenctypes = NULL; size_t count, i; *req_asn1_out = empty_data(); *timestamp_out = 0; *nonce_out = 0; *subkey_out = NULL; memset(&req, 0, sizeof(req)); memset(&authdata_enc, 0, sizeof(authdata_enc)); /* tgt's client principal must match the desired client principal. */ if (!krb5_principal_compare(context, tgt->client, desired->client)) return KRB5_PRINC_NOMATCH; /* tgt must be an actual credential, not a template. */ if (!tgt->ticket.length) return KRB5_NO_TKT_SUPPLIED; req.kdc_options = kdcoptions; req.server = desired->server; req.from = desired->times.starttime; req.till = desired->times.endtime ? desired->times.endtime : tgt->times.endtime; req.rtime = desired->times.renew_till; ret = krb5_timeofday(context, &time_now); if (ret) return ret; *nonce_out = req.nonce = (krb5_int32)time_now; *timestamp_out = time_now; req.addresses = (krb5_address **)addrs; /* Generate subkey. */ ret = krb5_generate_subkey(context, &tgt->keyblock, &subkey); if (ret) return ret; TRACE_SEND_TGS_SUBKEY(context, subkey); ret = krb5int_fast_tgs_armor(context, fast_state, subkey, &tgt->keyblock, NULL, NULL); if (ret) goto cleanup; if (desired->authdata != NULL) { ret = encode_krb5_authdata(desired->authdata, &authdata_asn1); if (ret) goto cleanup; ret = krb5_encrypt_helper(context, subkey, KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY, authdata_asn1, &authdata_enc); if (ret) goto cleanup; req.authorization_data = authdata_enc; } if (desired->keyblock.enctype != ENCTYPE_NULL) { if (!krb5_c_valid_enctype(desired->keyblock.enctype)) { ret = KRB5_PROG_ETYPE_NOSUPP; goto cleanup; } enctypes[0] = desired->keyblock.enctype; enctypes[1] = ENCTYPE_NULL; req.ktype = enctypes; req.nktypes = 1; } else { /* Get the default TGS enctypes. */ ret = krb5_get_tgs_ktypes(context, desired->server, &defenctypes); if (ret) goto cleanup; for (count = 0; defenctypes[count]; count++); req.ktype = defenctypes; req.nktypes = count; } TRACE_SEND_TGS_ETYPES(context, req.ktype); if (kdcoptions & (KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)) { if (desired->second_ticket.length == 0) { ret = KRB5_NO_2ND_TKT; goto cleanup; } ret = decode_krb5_ticket(&desired->second_ticket, &sec_ticket); if (ret) goto cleanup; sec_ticket_arr[0] = sec_ticket; sec_ticket_arr[1] = NULL; req.second_ticket = sec_ticket_arr; } /* Encode the request body. */ ret = krb5int_fast_prep_req_body(context, fast_state, &req, &req_body_asn1); if (ret) goto cleanup; ret = tgs_construct_ap_req(context, req_body_asn1, tgt, subkey, &ap_req_asn1); if (ret) goto cleanup; for (count = 0; in_padata != NULL && in_padata[count] != NULL; count++); /* Construct a padata array for the request, beginning with the ap-req. */ padata = k5calloc(count + 2, sizeof(krb5_pa_data *), &ret); if (padata == NULL) goto cleanup; padata[0] = k5alloc(sizeof(krb5_pa_data), &ret); if (padata[0] == NULL) goto cleanup; padata[0]->pa_type = KRB5_PADATA_AP_REQ; padata[0]->contents = k5memdup(ap_req_asn1->data, ap_req_asn1->length, &ret); if (padata[0] == NULL) goto cleanup; padata[0]->length = ap_req_asn1->length; /* Append copies of any other supplied padata. */ for (i = 0; in_padata != NULL && in_padata[i] != NULL; i++) { pa = k5alloc(sizeof(krb5_pa_data), &ret); if (pa == NULL) goto cleanup; pa->pa_type = in_padata[i]->pa_type; pa->length = in_padata[i]->length; pa->contents = k5memdup(in_padata[i]->contents, in_padata[i]->length, &ret); if (pa->contents == NULL) goto cleanup; padata[i + 1] = pa; } req.padata = padata; if (pacb_fn != NULL) { ret = (*pacb_fn)(context, subkey, &req, pacb_data); if (ret) goto cleanup; } /* Encode the TGS-REQ. Discard the krb5_data container. */ ret = krb5int_fast_prep_req(context, fast_state, &req, ap_req_asn1, encode_krb5_tgs_req, &tgs_req_asn1); if (ret) goto cleanup; *req_asn1_out = *tgs_req_asn1; free(tgs_req_asn1); tgs_req_asn1 = NULL; *subkey_out = subkey; subkey = NULL; cleanup: krb5_free_data(context, authdata_asn1); krb5_free_data(context, req_body_asn1); krb5_free_data(context, ap_req_asn1); krb5_free_pa_data(context, req.padata); krb5_free_ticket(context, sec_ticket); krb5_free_data_contents(context, &authdata_enc.ciphertext); krb5_free_keyblock(context, subkey); free(defenctypes); return ret; }
krb5_error_code krb5int_fast_prep_req(krb5_context context, struct krb5int_fast_request_state *state, krb5_kdc_req *request, const krb5_data *to_be_checksummed, kdc_req_encoder_proc encoder, krb5_data **encoded_request) { krb5_error_code retval = 0; krb5_pa_data *pa_array[2]; krb5_pa_data pa[2]; krb5_fast_req fast_req; krb5_fast_armored_req *armored_req = NULL; krb5_data *encoded_fast_req = NULL; krb5_data *encoded_armored_req = NULL; krb5_data *local_encoded_result = NULL; krb5_data random_data; char random_buf[4]; assert(state != NULL); assert(state->fast_outer_request.padata == NULL); memset(pa_array, 0, sizeof pa_array); if (state->armor_key == NULL) { return encoder(request, encoded_request); } TRACE_FAST_ENCODE(context); /* Fill in a fresh random nonce for each inner request*/ random_data.length = 4; random_data.data = (char *)random_buf; retval = krb5_c_random_make_octets(context, &random_data); if (retval == 0) { request->nonce = 0x7fffffff & load_32_n(random_buf); state->nonce = request->nonce; } fast_req.req_body = request; if (fast_req.req_body->padata == NULL) { fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *)); if (fast_req.req_body->padata == NULL) retval = ENOMEM; } fast_req.fast_options = state->fast_options; if (retval == 0) retval = encode_krb5_fast_req(&fast_req, &encoded_fast_req); if (retval == 0) { armored_req = calloc(1, sizeof(krb5_fast_armored_req)); if (armored_req == NULL) retval = ENOMEM; } if (retval == 0) armored_req->armor = state->armor; if (retval ==0) retval = krb5_c_make_checksum(context, 0, state->armor_key, KRB5_KEYUSAGE_FAST_REQ_CHKSUM, to_be_checksummed, &armored_req->req_checksum); if (retval == 0) retval = krb5_encrypt_helper(context, state->armor_key, KRB5_KEYUSAGE_FAST_ENC, encoded_fast_req, &armored_req->enc_part); if (retval == 0) retval = encode_krb5_pa_fx_fast_request(armored_req, &encoded_armored_req); if (retval==0) { pa[0].pa_type = KRB5_PADATA_FX_FAST; pa[0].contents = (unsigned char *) encoded_armored_req->data; pa[0].length = encoded_armored_req->length; pa_array[0] = &pa[0]; } state->fast_outer_request.padata = pa_array; if(retval == 0) retval = encoder(&state->fast_outer_request, &local_encoded_result); if (retval == 0) { *encoded_request = local_encoded_result; local_encoded_result = NULL; } if (encoded_armored_req) krb5_free_data(context, encoded_armored_req); if (armored_req) { armored_req->armor = NULL; /*owned by state*/ krb5_free_fast_armored_req(context, armored_req); } if (encoded_fast_req) krb5_free_data(context, encoded_fast_req); if (local_encoded_result) krb5_free_data(context, local_encoded_result); state->fast_outer_request.padata = NULL; return retval; }
/* due to argument promotion rules, we need to use the DECLARG/OLDDECLARG stuff... */ krb5_error_code krb5_encode_kdc_rep(krb5_context context, krb5_msgtype type, const krb5_enc_kdc_rep_part *encpart, int using_subkey, const krb5_keyblock *client_key, krb5_kdc_rep *dec_rep, krb5_data **enc_rep) { krb5_data *scratch; krb5_error_code retval; krb5_enc_kdc_rep_part tmp_encpart; krb5_keyusage usage; if (!krb5_c_valid_enctype(dec_rep->enc_part.enctype)) return KRB5_PROG_ETYPE_NOSUPP; switch (type) { case KRB5_AS_REP: usage = KRB5_KEYUSAGE_AS_REP_ENCPART; break; case KRB5_TGS_REP: if (using_subkey) usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY; else usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY; break; default: return KRB5_BADMSGTYPE; } /* * We don't want to modify encpart, but we need to be able to pass * in the message type to the encoder, so it can set the ASN.1 * type correct. * * Although note that it may be doing nothing with the message * type, to be compatible with old versions of Kerberos that always * encode this as a TGS_REP regardly of what it really should be; * also note that the reason why we are passing it in a structure * instead of as an argument to encode_krb5_enc_kdc_rep_part (the * way we should) is for compatibility with the ISODE version of * this fuction. Ah, compatibility.... */ tmp_encpart = *encpart; tmp_encpart.msg_type = type; retval = encode_krb5_enc_kdc_rep_part(&tmp_encpart, &scratch); if (retval) { return retval; } memset(&tmp_encpart, 0, sizeof(tmp_encpart)); #define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \ krb5_free_data(context, scratch); } retval = krb5_encrypt_helper(context, client_key, usage, scratch, &dec_rep->enc_part); #define cleanup_encpart() { \ (void) memset(dec_rep->enc_part.ciphertext.data, 0, \ dec_rep->enc_part.ciphertext.length); \ free(dec_rep->enc_part.ciphertext.data); \ dec_rep->enc_part.ciphertext.length = 0; \ dec_rep->enc_part.ciphertext.data = 0;} cleanup_scratch(); if (retval) return(retval); /* now it's ready to be encoded for the wire! */ switch (type) { case KRB5_AS_REP: retval = encode_krb5_as_rep(dec_rep, enc_rep); break; case KRB5_TGS_REP: retval = encode_krb5_tgs_rep(dec_rep, enc_rep); break; } if (retval) cleanup_encpart(); return retval; }
/* * Solaris Kerberos * Same as krb5_send_tgs plus an extra arg to return the FQDN * of the KDC sent the request. */ krb5_error_code krb5_send_tgs2(krb5_context context, krb5_flags kdcoptions, const krb5_ticket_times *timestruct, const krb5_enctype *ktypes, krb5_const_principal sname, krb5_address *const *addrs, krb5_authdata *const *authorization_data, krb5_pa_data *const *padata, const krb5_data *second_ticket, krb5_creds *in_cred, krb5_response *rep, char **hostname_used) { krb5_error_code retval; krb5_kdc_req tgsreq; krb5_data *scratch, scratch2; krb5_ticket *sec_ticket = 0; krb5_ticket *sec_ticket_arr[2]; krb5_timestamp time_now; krb5_pa_data **combined_padata; krb5_pa_data ap_req_padata; int tcp_only = 0, use_master; /* * in_creds MUST be a valid credential NOT just a partially filled in * place holder for us to get credentials for the caller. */ if (!in_cred->ticket.length) return(KRB5_NO_TKT_SUPPLIED); memset((char *)&tgsreq, 0, sizeof(tgsreq)); tgsreq.kdc_options = kdcoptions; tgsreq.server = (krb5_principal) sname; tgsreq.from = timestruct->starttime; tgsreq.till = timestruct->endtime ? timestruct->endtime : in_cred->times.endtime; tgsreq.rtime = timestruct->renew_till; if ((retval = krb5_timeofday(context, &time_now))) return(retval); /* XXX we know they are the same size... */ rep->expected_nonce = tgsreq.nonce = (krb5_int32) time_now; rep->request_time = time_now; tgsreq.addresses = (krb5_address **) addrs; if (authorization_data) { /* need to encrypt it in the request */ if ((retval = encode_krb5_authdata(authorization_data, &scratch))) return(retval); if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock, KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY, scratch, &tgsreq.authorization_data))) { krb5_xfree(tgsreq.authorization_data.ciphertext.data); krb5_free_data(context, scratch); return retval; } krb5_free_data(context, scratch); } /* Get the encryption types list */ if (ktypes) { /* Check passed ktypes and make sure they're valid. */ for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) { if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes])) return KRB5_PROG_ETYPE_NOSUPP; } tgsreq.ktype = (krb5_enctype *)ktypes; } else { /* Get the default ktypes */ /* Solaris Kerberos */ if ((retval = krb5_get_tgs_ktypes(context, sname, &(tgsreq.ktype)))) goto send_tgs_error_2; for(tgsreq.nktypes = 0; tgsreq.ktype[tgsreq.nktypes]; tgsreq.nktypes++); } if (second_ticket) { if ((retval = decode_krb5_ticket(second_ticket, &sec_ticket))) goto send_tgs_error_1; sec_ticket_arr[0] = sec_ticket; sec_ticket_arr[1] = 0; tgsreq.second_ticket = sec_ticket_arr; } else tgsreq.second_ticket = 0; /* encode the body; then checksum it */ if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch))) goto send_tgs_error_2; /* * Get an ap_req. */ if ((retval = krb5_send_tgs_basic(context, scratch, in_cred, &scratch2))) { krb5_free_data(context, scratch); goto send_tgs_error_2; } krb5_free_data(context, scratch); ap_req_padata.pa_type = KRB5_PADATA_AP_REQ; ap_req_padata.length = scratch2.length; ap_req_padata.contents = (krb5_octet *)scratch2.data; /* combine in any other supplied padata */ if (padata) { krb5_pa_data * const * counter; register unsigned int i = 0; for (counter = padata; *counter; counter++, i++); combined_padata = malloc((i+2) * sizeof(*combined_padata)); if (!combined_padata) { krb5_xfree(ap_req_padata.contents); retval = ENOMEM; goto send_tgs_error_2; } combined_padata[0] = &ap_req_padata; for (i = 1, counter = padata; *counter; counter++, i++) combined_padata[i] = (krb5_pa_data *) *counter; combined_padata[i] = 0; } else { combined_padata = (krb5_pa_data **)malloc(2*sizeof(*combined_padata)); if (!combined_padata) { krb5_xfree(ap_req_padata.contents); retval = ENOMEM; goto send_tgs_error_2; } combined_padata[0] = &ap_req_padata; combined_padata[1] = 0; } tgsreq.padata = combined_padata; /* the TGS_REQ is assembled in tgsreq, so encode it */ if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch))) { krb5_xfree(ap_req_padata.contents); krb5_xfree(combined_padata); goto send_tgs_error_2; } krb5_xfree(ap_req_padata.contents); krb5_xfree(combined_padata); /* now send request & get response from KDC */ send_again: use_master = 0; retval = krb5_sendto_kdc2(context, scratch, krb5_princ_realm(context, sname), &rep->response, &use_master, tcp_only, hostname_used); if (retval == 0) { if (krb5_is_krb_error(&rep->response)) { if (!tcp_only) { krb5_error *err_reply; retval = decode_krb5_error(&rep->response, &err_reply); /* Solaris Kerberos */ if (retval == 0) { if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG) { tcp_only = 1; krb5_free_error(context, err_reply); free(rep->response.data); rep->response.data = 0; goto send_again; } krb5_free_error(context, err_reply); } } } else if (krb5_is_tgs_rep(&rep->response)) rep->message_type = KRB5_TGS_REP; else /* XXX: assume it's an error */ rep->message_type = KRB5_ERROR; } krb5_free_data(context, scratch); send_tgs_error_2:; if (sec_ticket) krb5_free_ticket(context, sec_ticket); send_tgs_error_1:; if (ktypes == NULL) krb5_xfree(tgsreq.ktype); if (tgsreq.authorization_data.ciphertext.data) { memset(tgsreq.authorization_data.ciphertext.data, 0, tgsreq.authorization_data.ciphertext.length); krb5_xfree(tgsreq.authorization_data.ciphertext.data); } return retval; }
static krb5_error_code encts_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *padata, krb5_prompter_fct prompter, void *prompter_data, krb5_clpreauth_get_as_key_fn gak_fct, void *gak_data, krb5_data *salt, krb5_data *s2kparams, krb5_keyblock *as_key, krb5_pa_data ***out_padata) { krb5_error_code ret; krb5_pa_enc_ts pa_enc; krb5_data *ts = NULL, *enc_ts = NULL; krb5_enc_data enc_data; krb5_pa_data **pa = NULL; krb5_enctype etype = cb->get_etype(context, rock); enc_data.ciphertext = empty_data(); if (as_key->length == 0) { #ifdef DEBUG fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__, salt->length); if ((int) salt->length > 0) fprintf (stderr, " '%.*s'", salt->length, salt->data); fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n", etype, request->ktype[0]); #endif ret = (*gak_fct)(context, request->client, etype, prompter, prompter_data, salt, s2kparams, as_key, gak_data); if (ret) goto cleanup; TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key); } /* now get the time of day, and encrypt it accordingly */ ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec); if (ret) goto cleanup; ret = encode_krb5_pa_enc_ts(&pa_enc, &ts); if (ret) goto cleanup; ret = krb5_encrypt_helper(context, as_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, ts, &enc_data); if (ret) goto cleanup; TRACE_PREAUTH_ENC_TS(context, pa_enc.patimestamp, pa_enc.pausec, ts, &enc_data.ciphertext); ret = encode_krb5_enc_data(&enc_data, &enc_ts); if (ret) goto cleanup; pa = k5alloc(2 * sizeof(krb5_pa_data *), &ret); if (pa == NULL) goto cleanup; pa[0] = k5alloc(sizeof(krb5_pa_data), &ret); if (pa[0] == NULL) goto cleanup; pa[0]->magic = KV5M_PA_DATA; pa[0]->pa_type = KRB5_PADATA_ENC_TIMESTAMP; pa[0]->length = enc_ts->length; pa[0]->contents = (krb5_octet *) enc_ts->data; enc_ts->data = NULL; pa[1] = NULL; *out_padata = pa; pa = NULL; cleanup: krb5_free_data(context, ts); krb5_free_data(context, enc_ts); free(enc_data.ciphertext.data); free(pa); return ret; }
static krb5_error_code ec_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *padata, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***out_padata) { krb5_error_code retval = 0; krb5_keyblock *challenge_key = NULL, *armor_key, *as_key; armor_key = cb->fast_armor(context, rock); if (armor_key == NULL) return ENOENT; retval = cb->get_as_key(context, rock, &as_key); if (retval == 0 && padata->length) { krb5_enc_data *enc = NULL; krb5_data scratch; scratch.length = padata->length; scratch.data = (char *) padata->contents; retval = krb5_c_fx_cf2_simple(context,armor_key, "kdcchallengearmor", as_key, "challengelongterm", &challenge_key); if (retval == 0) retval = decode_krb5_enc_data(&scratch, &enc); scratch.data = NULL; if (retval == 0) { scratch.data = malloc(enc->ciphertext.length); scratch.length = enc->ciphertext.length; if (scratch.data == NULL) retval = ENOMEM; } if (retval == 0) retval = krb5_c_decrypt(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, NULL, enc, &scratch); /* * Per draft 11 of the preauth framework, the client MAY but is not * required to actually check the timestamp from the KDC other than to * confirm it decrypts. This code does not perform that check. */ if (scratch.data) krb5_free_data_contents(context, &scratch); /* If we had a callback to assert that the KDC is verified, we would * call it here. */ if (enc) krb5_free_enc_data(context, enc); } else if (retval == 0) { /*No padata; we send*/ krb5_enc_data enc; krb5_pa_data **pa = NULL; krb5_data *encoded_ts = NULL; krb5_pa_enc_ts ts; enc.ciphertext.data = NULL; /* Use the timestamp from the preauth-required error if possible. * This time should always be secured by the FAST channel. */ retval = cb->get_preauth_time(context, rock, FALSE, &ts.patimestamp, &ts.pausec); if (retval == 0) retval = encode_krb5_pa_enc_ts(&ts, &encoded_ts); if (retval == 0) retval = krb5_c_fx_cf2_simple(context, armor_key, "clientchallengearmor", as_key, "challengelongterm", &challenge_key); if (retval == 0) retval = krb5_encrypt_helper(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, encoded_ts, &enc); if (encoded_ts) krb5_free_data(context, encoded_ts); encoded_ts = NULL; if (retval == 0) { retval = encode_krb5_enc_data(&enc, &encoded_ts); krb5_free_data_contents(context, &enc.ciphertext); } if (retval == 0) { pa = calloc(2, sizeof(krb5_pa_data *)); if (pa == NULL) retval = ENOMEM; } if (retval == 0) { pa[0] = calloc(1, sizeof(krb5_pa_data)); if (pa[0] == NULL) retval = ENOMEM; } if (retval == 0) { pa[0]->length = encoded_ts->length; pa[0]->contents = (unsigned char *) encoded_ts->data; pa[0]->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; encoded_ts->data = NULL; *out_padata = pa; pa = NULL; } free(pa); krb5_free_data(context, encoded_ts); } if (challenge_key) krb5_free_keyblock(context, challenge_key); return retval; }
static krb5_error_code encts_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *padata, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***out_padata) { krb5_error_code ret; krb5_pa_enc_ts pa_enc; krb5_data *ts = NULL, *enc_ts = NULL; krb5_enc_data enc_data; krb5_pa_data **pa = NULL; krb5_keyblock *as_key; enc_data.ciphertext = empty_data(); ret = cb->get_as_key(context, rock, &as_key); if (ret) goto cleanup; TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key); /* * Try and use the timestamp of the preauth request, even if it's * unauthenticated. We could be fooled into making a preauth response for * a future time, but that has no security consequences other than the * KDC's audit logs. If kdc_timesync is not configured, then this will * just use local time. */ ret = cb->get_preauth_time(context, rock, TRUE, &pa_enc.patimestamp, &pa_enc.pausec); if (ret) goto cleanup; ret = encode_krb5_pa_enc_ts(&pa_enc, &ts); if (ret) goto cleanup; ret = krb5_encrypt_helper(context, as_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, ts, &enc_data); if (ret) goto cleanup; TRACE_PREAUTH_ENC_TS(context, pa_enc.patimestamp, pa_enc.pausec, ts, &enc_data.ciphertext); ret = encode_krb5_enc_data(&enc_data, &enc_ts); if (ret) goto cleanup; pa = k5alloc(2 * sizeof(krb5_pa_data *), &ret); if (pa == NULL) goto cleanup; pa[0] = k5alloc(sizeof(krb5_pa_data), &ret); if (pa[0] == NULL) goto cleanup; pa[0]->magic = KV5M_PA_DATA; pa[0]->pa_type = KRB5_PADATA_ENC_TIMESTAMP; pa[0]->length = enc_ts->length; pa[0]->contents = (krb5_octet *) enc_ts->data; enc_ts->data = NULL; pa[1] = NULL; *out_padata = pa; pa = NULL; cleanup: krb5_free_data(context, ts); krb5_free_data(context, enc_ts); free(enc_data.ciphertext.data); free(pa); return ret; }
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; }
/* Sends a request to the TGS and waits for a response. options is used for the options in the KRB_TGS_REQ. timestruct values are used for from, till, rtime " " " enctype is used for enctype " " ", and to encrypt the authorization data, sname is used for sname " " " addrs, if non-NULL, is used for addresses " " " authorization_dat, if non-NULL, is used for authorization_dat " " " second_ticket, if required by options, is used for the 2nd ticket in the req. in_cred is used for the ticket & session key in the KRB_AP_REQ header " " " (the KDC realm is extracted from in_cred->server's realm) The response is placed into *rep. rep->response.data is set to point at allocated storage which should be freed by the caller when finished. returns system errors */ static krb5_error_code krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cred, krb5_data *outbuf) { krb5_error_code retval; krb5_checksum checksum; krb5_authenticator authent; krb5_ap_req request; krb5_data * scratch; krb5_data * toutbuf; /* Generate checksum */ if ((retval = krb5_c_make_checksum(context, context->kdc_req_sumtype, &in_cred->keyblock, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, in_data, &checksum))) { free(checksum.contents); return(retval); } /* gen authenticator */ authent.subkey = 0; authent.seq_number = 0; authent.checksum = &checksum; authent.client = in_cred->client; authent.authorization_data = in_cred->authdata; if ((retval = krb5_us_timeofday(context, &authent.ctime, &authent.cusec))) { free(checksum.contents); return(retval); } /* encode the authenticator */ if ((retval = encode_krb5_authenticator(&authent, &scratch))) { free(checksum.contents); return(retval); } free(checksum.contents); request.authenticator.ciphertext.data = 0; request.authenticator.kvno = 0; request.ap_options = 0; request.ticket = 0; if ((retval = decode_krb5_ticket(&(in_cred)->ticket, &request.ticket))) /* Cleanup scratch and scratch data */ goto cleanup_data; /* call the encryption routine */ if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock, KRB5_KEYUSAGE_TGS_REQ_AUTH, scratch, &request.authenticator))) goto cleanup_ticket; retval = encode_krb5_ap_req(&request, &toutbuf); /* Solaris Kerberos */ if (retval == 0) { *outbuf = *toutbuf; krb5_xfree(toutbuf); } memset(request.authenticator.ciphertext.data, 0, request.authenticator.ciphertext.length); free(request.authenticator.ciphertext.data); cleanup_ticket: krb5_free_ticket(context, request.ticket); cleanup_data: memset(scratch->data, 0, scratch->length); free(scratch->data); free(scratch); return retval; }
static krb5_error_code encts_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *padata, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***out_padata) { krb5_error_code ret; krb5_pa_enc_ts pa_enc; krb5_data *ts = NULL, *enc_ts = NULL; krb5_enc_data enc_data; krb5_pa_data **pa = NULL; krb5_keyblock *as_key; enc_data.ciphertext = empty_data(); ret = cb->get_as_key(context, rock, &as_key); if (ret) goto cleanup; TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key); /* now get the time of day, and encrypt it accordingly */ ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec); if (ret) goto cleanup; ret = encode_krb5_pa_enc_ts(&pa_enc, &ts); if (ret) goto cleanup; ret = krb5_encrypt_helper(context, as_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, ts, &enc_data); if (ret) goto cleanup; TRACE_PREAUTH_ENC_TS(context, pa_enc.patimestamp, pa_enc.pausec, ts, &enc_data.ciphertext); ret = encode_krb5_enc_data(&enc_data, &enc_ts); if (ret) goto cleanup; pa = k5alloc(2 * sizeof(krb5_pa_data *), &ret); if (pa == NULL) goto cleanup; pa[0] = k5alloc(sizeof(krb5_pa_data), &ret); if (pa[0] == NULL) goto cleanup; pa[0]->magic = KV5M_PA_DATA; pa[0]->pa_type = KRB5_PADATA_ENC_TIMESTAMP; pa[0]->length = enc_ts->length; pa[0]->contents = (krb5_octet *) enc_ts->data; enc_ts->data = NULL; pa[1] = NULL; *out_padata = pa; pa = NULL; cleanup: krb5_free_data(context, ts); krb5_free_data(context, enc_ts); free(enc_data.ciphertext.data); free(pa); return ret; }
krb5_error_code krb5int_fast_prep_req(krb5_context context, struct krb5int_fast_request_state *state, krb5_kdc_req *request, const krb5_data *to_be_checksummed, kdc_req_encoder_proc encoder, krb5_data **encoded_request) { krb5_error_code retval = 0; krb5_pa_data *pa_array[2], **pa_tgs_array = NULL; krb5_pa_data pa[2]; krb5_fast_req fast_req; krb5_pa_data *tgs = NULL; krb5_fast_armored_req *armored_req = NULL; krb5_data *encoded_fast_req = NULL; krb5_data *encoded_armored_req = NULL; krb5_data *local_encoded_result = NULL; int i, j; assert(state != NULL); assert(state->fast_outer_request.padata == NULL); memset(pa_array, 0, sizeof(pa_array)); if (state->armor_key == NULL) { return encoder(request, encoded_request); } TRACE_FAST_ENCODE(context); state->nonce = request->nonce; fast_req.req_body = request; if (fast_req.req_body->padata == NULL) { fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *)); if (fast_req.req_body->padata == NULL) retval = ENOMEM; } fast_req.fast_options = state->fast_options; if (retval == 0 && (tgs = krb5int_find_pa_data(context, fast_req.req_body->padata, KRB5_PADATA_AP_REQ)) != NULL) { krb5_pa_data **paptr = &fast_req.req_body->padata[0]; for (i = 0, j = 0; paptr[j] != NULL; j++) { if (paptr[j]->pa_type == KRB5_PADATA_AP_REQ) paptr[j] = NULL; else paptr[i++] = paptr[j]; } paptr[i] = NULL; } if (retval == 0) retval = encode_krb5_fast_req(&fast_req, &encoded_fast_req); if (retval == 0) { armored_req = calloc(1, sizeof(krb5_fast_armored_req)); if (armored_req == NULL) retval = ENOMEM; } if (retval == 0) armored_req->armor = state->armor; if (retval ==0) retval = krb5_c_make_checksum(context, 0, state->armor_key, KRB5_KEYUSAGE_FAST_REQ_CHKSUM, to_be_checksummed, &armored_req->req_checksum); if (retval == 0) retval = krb5_encrypt_helper(context, state->armor_key, KRB5_KEYUSAGE_FAST_ENC, encoded_fast_req, &armored_req->enc_part); if (retval == 0) retval = encode_krb5_pa_fx_fast_request(armored_req, &encoded_armored_req); if (retval == 0) { pa[0].pa_type = KRB5_PADATA_FX_FAST; pa[0].contents = (unsigned char *) encoded_armored_req->data; pa[0].length = encoded_armored_req->length; if (tgs) { retval = make_tgs_outer_padata(tgs, pa, request->padata, &pa_tgs_array); state->fast_outer_request.padata = pa_tgs_array; } else { pa_array[0] = &pa[0]; state->fast_outer_request.padata = pa_array; } } if (retval == 0) retval = encoder(&state->fast_outer_request, &local_encoded_result); if (retval == 0) { *encoded_request = local_encoded_result; local_encoded_result = NULL; } if (encoded_armored_req) krb5_free_data(context, encoded_armored_req); if (armored_req) { armored_req->armor = NULL; /*owned by state*/ krb5_free_fast_armored_req(context, armored_req); } if (encoded_fast_req) krb5_free_data(context, encoded_fast_req); if (local_encoded_result) krb5_free_data(context, local_encoded_result); if (tgs) { free(tgs->contents); free(tgs); } state->fast_outer_request.padata = NULL; free(pa_tgs_array); return retval; }
/*ARGSUSED*/ static krb5_error_code pa_enc_timestamp(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata, krb5_pa_data **out_padata, krb5_data *salt, krb5_data *s2kparams, krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter, void *prompter_data, krb5_gic_get_as_key_fct gak_fct, void *gak_data) { krb5_error_code ret; krb5_pa_enc_ts pa_enc; krb5_data *tmp; krb5_enc_data enc_data; krb5_pa_data *pa; if (as_key->length == 0) { #ifdef DEBUG if (salt != NULL && salt->data != NULL) { fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__, salt->length); if (salt->length > 0) fprintf (stderr, " '%*s'", salt->length, salt->data); fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n", *etype, request->ktype[0]); } #endif if ((ret = ((*gak_fct)(context, request->client, *etype ? *etype : request->ktype[0], prompter, prompter_data, salt, s2kparams, as_key, gak_data)))) return(ret); } /* now get the time of day, and encrypt it accordingly */ if ((ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec))) return(ret); if ((ret = encode_krb5_pa_enc_ts(&pa_enc, &tmp))) return(ret); #ifdef DEBUG fprintf (stderr, "key type %d bytes %02x %02x ...\n", as_key->enctype, as_key->contents[0], as_key->contents[1]); #endif ret = krb5_encrypt_helper(context, as_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS, tmp, &enc_data); #ifdef DEBUG fprintf (stderr, "enc data { type=%d kvno=%d data=%02x %02x ... }\n", enc_data.enctype, enc_data.kvno, 0xff & enc_data.ciphertext.data[0], 0xff & enc_data.ciphertext.data[1]); #endif krb5_free_data(context, tmp); if (ret) { krb5_xfree(enc_data.ciphertext.data); return(ret); } ret = encode_krb5_enc_data(&enc_data, &tmp); krb5_xfree(enc_data.ciphertext.data); if (ret) return(ret); if ((pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) { krb5_free_data(context, tmp); return(ENOMEM); } pa->magic = KV5M_PA_DATA; pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP; pa->length = tmp->length; pa->contents = (krb5_octet *) tmp->data; *out_padata = pa; krb5_xfree(tmp); return(0); }