krb5_error_code KRB5_LIB_FUNCTION krb5_generate_seq_number(krb5_context context, const krb5_keyblock *key, uint32_t *seqno) { krb5_error_code ret; krb5_keyblock *subkey; uint32_t q; u_char *p; int i; ret = krb5_generate_subkey (context, key, &subkey); if (ret) return ret; q = 0; for (p = (u_char *)subkey->keyvalue.data, i = 0; i < subkey->keyvalue.length; ++i, ++p) q = (q << 8) | *p; q &= 0xffffffff; *seqno = q; krb5_free_keyblock (context, subkey); return 0; }
/* * 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; }
static krb5_error_code init_tgs_req (krb5_context context, krb5_ccache ccache, krb5_addresses *addresses, krb5_kdc_flags flags, Ticket *second_ticket, krb5_creds *in_creds, krb5_creds *krbtgt, unsigned nonce, krb5_keyblock **subkey, TGS_REQ *t, krb5_key_usage usage) { krb5_error_code ret = 0; memset(t, 0, sizeof(*t)); t->pvno = 5; t->msg_type = krb_tgs_req; if (in_creds->session.keytype) { ALLOC_SEQ(&t->req_body.etype, 1); if(t->req_body.etype.val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } t->req_body.etype.val[0] = in_creds->session.keytype; } else { ret = krb5_init_etype(context, &t->req_body.etype.len, &t->req_body.etype.val, NULL); } if (ret) goto fail; t->req_body.addresses = addresses; t->req_body.kdc_options = flags.b; ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); if (ret) goto fail; ALLOC(t->req_body.sname, 1); if (t->req_body.sname == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } /* some versions of some code might require that the client be present in TGS-REQs, but this is clearly against the spec */ ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); if (ret) goto fail; /* req_body.till should be NULL if there is no endtime specified, but old MIT code (like DCE secd) doesn't like that */ ALLOC(t->req_body.till, 1); if(t->req_body.till == NULL){ ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } *t->req_body.till = in_creds->times.endtime; t->req_body.nonce = nonce; if(second_ticket){ ALLOC(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } ALLOC_SEQ(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets->val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); if (ret) goto fail; } ALLOC(t->padata, 1); if (t->padata == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } ALLOC_SEQ(t->padata, 1); if (t->padata->val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } { krb5_auth_context ac; krb5_keyblock *key = NULL; ret = krb5_auth_con_init(context, &ac); if(ret) goto fail; if (krb5_config_get_bool_default(context, NULL, FALSE, "realms", krbtgt->server->realm, "tgs_require_subkey", NULL)) { ret = krb5_generate_subkey (context, &krbtgt->session, &key); if (ret) { krb5_auth_con_free (context, ac); goto fail; } ret = krb5_auth_con_setlocalsubkey(context, ac, key); if (ret) { if (key) krb5_free_keyblock (context, key); krb5_auth_con_free (context, ac); goto fail; } } ret = set_auth_data (context, &t->req_body, &in_creds->authdata, key ? key : &krbtgt->session); if (ret) { if (key) krb5_free_keyblock (context, key); krb5_auth_con_free (context, ac); goto fail; } ret = make_pa_tgs_req(context, ac, &t->req_body, t->padata->val, krbtgt, usage); if(ret) { if (key) krb5_free_keyblock (context, key); krb5_auth_con_free(context, ac); goto fail; } *subkey = key; krb5_auth_con_free(context, ac); } fail: if (ret) { t->req_body.addresses = NULL; free_TGS_REQ (t); } return ret; }