/* * Fill in the caller out, realm, and flags output variables. out is filled in * with ctx->previous_request, which the caller should set, and realm is filled * in with the realm of ctx->cur_tgt. */ static krb5_error_code set_caller_request(krb5_context context, krb5_tkt_creds_context ctx) { krb5_error_code code; const krb5_data *req = &ctx->previous_request; const krb5_data *realm = &ctx->cur_tgt->server->data[1]; krb5_data out_copy = empty_data(), realm_copy = empty_data(); code = krb5int_copy_data_contents(context, req, &out_copy); if (code != 0) goto cleanup; code = krb5int_copy_data_contents(context, realm, &realm_copy); if (code != 0) goto cleanup; *ctx->caller_out = out_copy; *ctx->caller_realm = realm_copy; *ctx->caller_flags = KRB5_TKT_CREDS_STEP_FLAG_CONTINUE; return 0; cleanup: krb5_free_data_contents(context, &out_copy); krb5_free_data_contents(context, &realm_copy); return code; }
krb5_error_code krb5int_hmacmd5_checksum(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { krb5_keyusage ms_usage; krb5_error_code ret; krb5_keyblock ks, *keyblock; krb5_crypto_iov *hash_iov = NULL, iov; krb5_data ds = empty_data(), hashval = empty_data(); char t[4]; if (key == NULL || key->keyblock.length > ctp->hash->blocksize) return KRB5_BAD_ENCTYPE; if (ctp->ctype == CKSUMTYPE_HMAC_MD5_ARCFOUR) { /* Compute HMAC(key, "signaturekey\0") to get the signing key ks. */ ret = alloc_data(&ds, ctp->hash->hashsize); if (ret != 0) goto cleanup; iov.flags = KRB5_CRYPTO_TYPE_DATA; iov.data = make_data("signaturekey", 13); ret = krb5int_hmac(ctp->hash, key, &iov, 1, &ds); if (ret) goto cleanup; ks.length = key->keyblock.length; ks.contents = (krb5_octet *) ds.data; keyblock = &ks; } else /* For md5-hmac, just use the key. */ keyblock = &key->keyblock; /* Compute the MD5 value of the input. */ ms_usage = krb5int_arcfour_translate_usage(usage); store_32_le(ms_usage, t); hash_iov = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret); if (hash_iov == NULL) goto cleanup; hash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA; hash_iov[0].data = make_data(t, 4); memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov)); ret = alloc_data(&hashval, ctp->hash->hashsize); if (ret != 0) goto cleanup; ret = ctp->hash->hash(hash_iov, num_data + 1, &hashval); if (ret != 0) goto cleanup; /* Compute HMAC(ks, md5value). */ iov.flags = KRB5_CRYPTO_TYPE_DATA; iov.data = hashval; ret = krb5int_hmac_keyblock(ctp->hash, keyblock, &iov, 1, output); cleanup: zapfree(ds.data, ds.length); zapfree(hashval.data, hashval.length); free(hash_iov); return ret; }
krb5_error_code KRB5_CALLCONV krb5_mk_priv(krb5_context context, krb5_auth_context authcon, const krb5_data *userdata, krb5_data *der_out, krb5_replay_data *rdata_out) { krb5_error_code ret; krb5_key key; krb5_replay_data rdata; krb5_data der_krbpriv = empty_data(); krb5_enc_data enc; krb5_address *local_addr, *remote_addr, lstorage, rstorage; *der_out = empty_data(); memset(&enc, 0, sizeof(enc)); memset(&lstorage, 0, sizeof(lstorage)); memset(&rstorage, 0, sizeof(rstorage)); if (!authcon->local_addr) return KRB5_LOCAL_ADDR_REQUIRED; ret = k5_privsafe_gen_rdata(context, authcon, &rdata, rdata_out); if (ret) goto cleanup; ret = k5_privsafe_gen_addrs(context, authcon, &lstorage, &rstorage, &local_addr, &remote_addr); if (ret) goto cleanup; key = (authcon->send_subkey != NULL) ? authcon->send_subkey : authcon->key; ret = create_krbpriv(context, userdata, key, &rdata, local_addr, remote_addr, &authcon->cstate, &der_krbpriv, &enc); if (ret) goto cleanup; ret = k5_privsafe_check_replay(context, authcon, NULL, &enc, NULL); if (ret) goto cleanup; *der_out = der_krbpriv; der_krbpriv = empty_data(); if ((authcon->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || (authcon->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) authcon->local_seq_number++; cleanup: krb5_free_data_contents(context, &der_krbpriv); zapfree(enc.ciphertext.data, enc.ciphertext.length); free(lstorage.contents); free(rstorage.contents); return ret; }
void ktest_make_sample_sam_challenge_2_body(krb5_sam_challenge_2_body *p) { p->sam_type = 42; p->sam_flags = KRB5_SAM_USE_SAD_AS_KEY; krb5_data_parse(&p->sam_type_name, "type name"); p->sam_track_id = empty_data(); krb5_data_parse(&p->sam_challenge_label, "challenge label"); krb5_data_parse(&p->sam_challenge, "challenge ipse"); krb5_data_parse(&p->sam_response_prompt, "response_prompt ipse"); p->sam_pk_for_sad = empty_data(); p->sam_nonce = 0x543210; p->sam_etype = ENCTYPE_DES_CBC_CRC; }
/* * Set up the request given by ctx->tgs_in_creds, using ctx->cur_tgt. KDC * options for the requests are determined by ctx->cur_tgt->ticket_flags and * extra_options. */ static krb5_error_code make_request(krb5_context context, krb5_tkt_creds_context ctx, int extra_options) { krb5_error_code code; krb5_data request = empty_data(); ctx->kdcopt = extra_options | FLAGS2OPTS(ctx->cur_tgt->ticket_flags); /* XXX This check belongs in gc_via_tgt.c or nowhere. */ if (!krb5_c_valid_enctype(ctx->cur_tgt->keyblock.enctype)) return KRB5_PROG_ETYPE_NOSUPP; code = krb5int_make_tgs_request(context, ctx->cur_tgt, ctx->kdcopt, ctx->cur_tgt->addresses, NULL, ctx->tgs_in_creds, NULL, NULL, &request, &ctx->timestamp, &ctx->nonce, &ctx->subkey); if (code != 0) return code; krb5_free_data_contents(context, &ctx->previous_request); ctx->previous_request = request; return set_caller_request(context, ctx); }
/* Determines if a pin is required. If it is, it will be prompted for. */ static inline krb5_error_code collect_pin(krb5_context context, krb5_prompter_fct prompter, void *prompter_data, const krb5_otp_tokeninfo *ti, krb5_data *out_pin) { krb5_error_code retval; char otppin[1024]; krb5_flags collect; krb5_data pin; /* If no PIN will be collected, don't prompt. */ collect = ti->flags & (KRB5_OTP_FLAG_COLLECT_PIN | KRB5_OTP_FLAG_SEPARATE_PIN); if (collect == 0) { *out_pin = empty_data(); return 0; } /* Collect the PIN. */ retval = doprompt(context, prompter, prompter_data, NULL, _("OTP Token PIN"), otppin, sizeof(otppin)); if (retval != 0) return retval; /* Set the PIN. */ pin = make_data(strdup(otppin), strlen(otppin)); if (pin.data == NULL) return ENOMEM; *out_pin = pin; return 0; }
void ktest_make_sha256_alg(krb5_algorithm_identifier *p) { /* { 2 16 840 1 101 3 4 2 1 } */ krb5_data_parse(&p->algorithm, "\x60\x86\x48\x01\x65\x03\x04\x02\x01"); p->parameters = empty_data(); }
/* * Convert a krb5_principal into the default salt for that principal. */ static krb5_error_code principal2salt_internal(krb5_context context, krb5_const_principal pr, krb5_data *ret, int use_realm) { unsigned int size = 0, offset=0; krb5_int32 i; *ret = empty_data(); if (pr == NULL) return 0; if (use_realm) size += pr->realm.length; for (i = 0; i < pr->length; i++) size += pr->data[i].length; if (alloc_data(ret, size)) return ENOMEM; if (use_realm) { offset = pr->realm.length; if (offset > 0) memcpy(ret->data, pr->realm.data, offset); } for (i = 0; i < pr->length; i++) { if (pr->data[i].length > 0) memcpy(&ret->data[offset], pr->data[i].data, pr->data[i].length); offset += pr->data[i].length; } return 0; }
void ktest_make_sha1_alg(krb5_algorithm_identifier *p) { /* { 1 3 14 3 2 26 } */ krb5_data_parse(&p->algorithm, "\x2b\x0e\x03\x02\x1a"); p->parameters = empty_data(); }
/* * Compute a derived key into the keyblock outkey. This variation on * krb5int_derive_key does not cache the result, as it is only used * directly in situations which are not expected to be repeated with * the same inkey and constant. */ krb5_error_code krb5int_derive_keyblock(const struct krb5_enc_provider *enc, krb5_key inkey, krb5_keyblock *outkey, const krb5_data *in_constant) { krb5_error_code ret; krb5_data rawkey = empty_data(); /* Allocate a buffer for the raw key bytes. */ ret = alloc_data(&rawkey, enc->keybytes); if (ret) goto cleanup; /* Derive pseudo-random data for the key bytes. */ ret = krb5int_derive_random(enc, inkey, &rawkey, in_constant); if (ret) goto cleanup; /* Postprocess the key. */ ret = enc->make_key(&rawkey, outkey); cleanup: zapfree(rawkey.data, enc->keybytes); return ret; }
/* * Decrypt and decode the enc_part of a krb5_cred using the receiving subkey or * the session key of authcon. If neither key is present, ctext->ciphertext is * assumed to be unencrypted plain text (RFC 6448). */ static krb5_error_code decrypt_encpart(krb5_context context, krb5_enc_data *ctext, krb5_auth_context authcon, krb5_cred_enc_part **encpart_out) { krb5_error_code ret; krb5_data plain = empty_data(); krb5_boolean decrypted = FALSE; *encpart_out = NULL; if (authcon->recv_subkey == NULL && authcon->key == NULL) return decode_krb5_enc_cred_part(&ctext->ciphertext, encpart_out); ret = alloc_data(&plain, ctext->ciphertext.length); if (ret) return ret; if (authcon->recv_subkey != NULL) { ret = krb5_k_decrypt(context, authcon->recv_subkey, KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0, ctext, &plain); decrypted = (ret == 0); } if (!decrypted && authcon->key != NULL) { ret = krb5_k_decrypt(context, authcon->key, KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0, ctext, &plain); decrypted = (ret == 0); } if (decrypted) ret = decode_krb5_enc_cred_part(&plain, encpart_out); zapfree(plain.data, plain.length); return ret; }
static krb5_error_code prepare_error_as (struct kdc_request_state *rstate, krb5_kdc_req *request, int error, krb5_pa_data **e_data, krb5_boolean typed_e_data, krb5_principal canon_client, krb5_data **response, const char *status) { krb5_error errpkt; krb5_error_code retval; krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL; kdc_realm_t *kdc_active_realm = rstate->realm_data; errpkt.ctime = request->nonce; errpkt.cusec = 0; retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec); if (retval) return retval; errpkt.error = error; errpkt.server = request->server; errpkt.client = (error == KRB5KDC_ERR_WRONG_REALM) ? canon_client : request->client; errpkt.text = string2data((char *)status); if (e_data != NULL) { if (typed_e_data) retval = encode_krb5_typed_data(e_data, &e_data_asn1); else retval = encode_krb5_padata_sequence(e_data, &e_data_asn1); if (retval) goto cleanup; errpkt.e_data = *e_data_asn1; } else errpkt.e_data = empty_data(); retval = kdc_fast_handle_error(kdc_context, rstate, request, e_data, &errpkt, &fast_edata); if (retval) goto cleanup; if (fast_edata != NULL) errpkt.e_data = *fast_edata; scratch = k5alloc(sizeof(*scratch), &retval); if (scratch == NULL) goto cleanup; if (kdc_fast_hide_client(rstate) && errpkt.client != NULL) errpkt.client = (krb5_principal)krb5_anonymous_principal(); retval = krb5_mk_error(kdc_context, &errpkt, scratch); if (retval) goto cleanup; *response = scratch; scratch = NULL; cleanup: krb5_free_data(kdc_context, fast_edata); krb5_free_data(kdc_context, e_data_asn1); free(scratch); return retval; }
krb5_error_code KRB5_CALLCONV krb5_parse_name_flags(krb5_context context, const char *name, int flags, krb5_principal *principal_out) { krb5_error_code ret; krb5_principal princ = NULL; char *default_realm; krb5_boolean has_realm; krb5_boolean enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE); krb5_boolean require_realm = (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM); krb5_boolean no_realm = (flags & KRB5_PRINCIPAL_PARSE_NO_REALM); krb5_boolean ignore_realm = (flags & KRB5_PRINCIPAL_PARSE_IGNORE_REALM); *principal_out = NULL; ret = allocate_princ(context, name, enterprise, &princ, &has_realm); if (ret) goto cleanup; parse_name_into_princ(name, enterprise, princ); /* * If a realm was not found, then use the default realm, unless * KRB5_PRINCIPAL_PARSE_NO_REALM was specified in which case the * realm will be empty. */ if (!has_realm) { if (require_realm) { ret = KRB5_PARSE_MALFORMED; krb5_set_error_message(context, ret, _("Principal %s is missing required realm"), name); goto cleanup; } if (!no_realm && !ignore_realm) { ret = krb5_get_default_realm(context, &default_realm); if (ret) goto cleanup; princ->realm = string2data(default_realm); } } else if (no_realm) { ret = KRB5_PARSE_MALFORMED; krb5_set_error_message(context, ret, _("Principal %s has realm present"), name); goto cleanup; } else if (ignore_realm) { krb5_free_data_contents(context, &princ->realm); princ->realm = empty_data(); } princ->type = (enterprise) ? KRB5_NT_ENTERPRISE_PRINCIPAL : KRB5_NT_PRINCIPAL; princ->magic = KV5M_PRINCIPAL; *principal_out = princ; princ = NULL; cleanup: krb5_free_principal(context, princ); return ret; }
/* Add realm to ctx->realms_seen so that we can avoid revisiting it later. */ static krb5_error_code remember_realm(krb5_context context, krb5_tkt_creds_context ctx, const krb5_data *realm) { size_t len = 0; krb5_data *new_list; if (ctx->realms_seen != NULL) { for (len = 0; ctx->realms_seen[len].data != NULL; len++); } new_list = realloc(ctx->realms_seen, (len + 2) * sizeof(krb5_data)); if (new_list == NULL) return ENOMEM; ctx->realms_seen = new_list; new_list[len] = empty_data(); new_list[len + 1] = empty_data(); return krb5int_copy_data_contents(context, realm, &new_list[len]); }
krb5_error_code KRB5_CALLCONV krb5_k_decrypt(krb5_context context, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, const krb5_enc_data *input, krb5_data *output) { const struct krb5_keytypes *ktp; krb5_crypto_iov iov[4]; krb5_error_code ret; unsigned int header_len, trailer_len, plain_len; char *scratch = NULL; ktp = find_enctype(key->keyblock.enctype); if (ktp == NULL) return KRB5_BAD_ENCTYPE; if (input->enctype != ENCTYPE_UNKNOWN && ktp->etype != input->enctype) return KRB5_BAD_ENCTYPE; /* Verify the input and output lengths. */ header_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_HEADER); trailer_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_TRAILER); if (input->ciphertext.length < header_len + trailer_len) return KRB5_BAD_MSIZE; plain_len = input->ciphertext.length - header_len - trailer_len; if (output->length < plain_len) return KRB5_BAD_MSIZE; scratch = k5alloc(header_len + trailer_len, &ret); if (scratch == NULL) return ret; iov[0].flags = KRB5_CRYPTO_TYPE_HEADER; iov[0].data = make_data(scratch, header_len); memcpy(iov[0].data.data, input->ciphertext.data, header_len); iov[1].flags = KRB5_CRYPTO_TYPE_DATA; iov[1].data = make_data(output->data, plain_len); memcpy(iov[1].data.data, input->ciphertext.data + header_len, plain_len); /* Use empty padding since tokens don't indicate the padding length. */ iov[2].flags = KRB5_CRYPTO_TYPE_PADDING; iov[2].data = empty_data(); iov[3].flags = KRB5_CRYPTO_TYPE_TRAILER; iov[3].data = make_data(scratch + header_len, trailer_len); memcpy(iov[3].data.data, input->ciphertext.data + header_len + plain_len, trailer_len); ret = ktp->decrypt(ktp, key, usage, ivec, iov, 4); if (ret != 0) zap(output->data, plain_len); else output->length = plain_len; zapfree(scratch, header_len + trailer_len); return ret; }
krb5_error_code KRB5_CALLCONV krb5_tkt_creds_step(krb5_context context, krb5_tkt_creds_context ctx, krb5_data *in, krb5_data *out, krb5_data *realm, unsigned int *flags) { krb5_error_code code; krb5_boolean no_input = (in == NULL || in->length == 0); *out = empty_data(); *realm = empty_data(); *flags = 0; /* We should receive an empty input on the first step only, and should not * get called after completion. */ if (no_input != (ctx->state == STATE_BEGIN) || ctx->state == STATE_COMPLETE) return EINVAL; ctx->caller_out = out; ctx->caller_realm = realm; ctx->caller_flags = flags; if (!no_input) { /* Convert the input token into a credential and store it in ctx. */ code = get_creds_from_tgs_reply(context, ctx, in); if (code != 0) return code; } if (ctx->state == STATE_BEGIN) return begin(context, ctx); else if (ctx->state == STATE_GET_TGT) return step_get_tgt(context, ctx); else if (ctx->state == STATE_GET_TGT_OFFPATH) return step_get_tgt_offpath(context, ctx); else if (ctx->state == STATE_REFERRALS) return step_referrals(context, ctx); else if (ctx->state == STATE_NON_REFERRAL) return step_non_referral(context, ctx); else return EINVAL; }
krb5_error_code krb5int_confounder_verify(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, const krb5_data *input, krb5_boolean *valid) { krb5_error_code ret; unsigned char *plaintext = NULL; krb5_key xorkey = NULL; krb5_data computed = empty_data(); krb5_crypto_iov *hash_iov = NULL, iov; size_t blocksize = ctp->enc->block_size, hashsize = ctp->hash->hashsize; plaintext = k5memdup(input->data, input->length, &ret); if (plaintext == NULL) return ret; ret = mk_xorkey(key, &xorkey); if (ret != 0) goto cleanup; /* Decrypt the input checksum. */ iov.flags = KRB5_CRYPTO_TYPE_DATA; iov.data = make_data(plaintext, input->length); ret = ctp->enc->decrypt(xorkey, NULL, &iov, 1); if (ret != 0) goto cleanup; /* Hash the confounder, then the input data. */ hash_iov = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret); if (hash_iov == NULL) goto cleanup; hash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA; hash_iov[0].data = make_data(plaintext, blocksize); memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov)); ret = alloc_data(&computed, hashsize); if (ret != 0) goto cleanup; ret = ctp->hash->hash(hash_iov, num_data + 1, &computed); if (ret != 0) goto cleanup; /* Compare the decrypted hash to the computed one. */ *valid = (memcmp(plaintext + blocksize, computed.data, hashsize) == 0); cleanup: zapfree(plaintext, input->length); zapfree(computed.data, hashsize); free(hash_iov); krb5_k_free_key(NULL, xorkey); return ret; }
static krb5_error_code derive_random_rfc3961(const struct krb5_enc_provider *enc, krb5_key inkey, krb5_data *outrnd, const krb5_data *in_constant) { size_t blocksize, keybytes, n; krb5_error_code ret; krb5_data block = empty_data(); blocksize = enc->block_size; keybytes = enc->keybytes; if (blocksize == 1) return KRB5_BAD_ENCTYPE; if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes) return KRB5_CRYPTO_INTERNAL; /* Allocate encryption data buffer. */ ret = alloc_data(&block, blocksize); if (ret) return ret; /* Initialize the input block. */ if (in_constant->length == blocksize) { memcpy(block.data, in_constant->data, blocksize); } else { krb5int_nfold(in_constant->length * 8, (unsigned char *) in_constant->data, blocksize * 8, (unsigned char *) block.data); } /* Loop encrypting the blocks until enough key bytes are generated. */ n = 0; while (n < keybytes) { ret = encrypt_block(enc, inkey, &block); if (ret) goto cleanup; if ((keybytes - n) <= blocksize) { memcpy(outrnd->data + n, block.data, (keybytes - n)); break; } memcpy(outrnd->data + n, block.data, blocksize); n += blocksize; } cleanup: zapfree(block.data, blocksize); return ret; }
krb5_error_code krb5int_dk_cmac_encrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { const struct krb5_enc_provider *enc = ktp->enc; krb5_error_code ret; krb5_crypto_iov *header, *trailer, *padding; krb5_data cksum = empty_data(); krb5_key ke = NULL, ki = NULL; /* E(Confounder | Plaintext | Pad) | Checksum */ /* Validate header and trailer lengths, and zero out padding length. */ header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); if (header == NULL || header->data.length < enc->block_size) return KRB5_BAD_MSIZE; trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); if (trailer == NULL || trailer->data.length < enc->block_size) return KRB5_BAD_MSIZE; padding = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_PADDING); if (padding != NULL) padding->data.length = 0; /* Derive the encryption and integrity keys. */ ret = derive_keys(enc, key, usage, &ke, &ki); if (ret != 0) goto cleanup; /* Generate confounder. */ header->data.length = enc->block_size; ret = krb5_c_random_make_octets(NULL, &header->data); if (ret != 0) goto cleanup; /* Checksum the plaintext. */ ret = krb5int_cmac_checksum(enc, ki, data, num_data, &trailer->data); if (ret != 0) goto cleanup; /* Encrypt the plaintext (header | data | padding) */ ret = enc->encrypt(ke, ivec, data, num_data); if (ret != 0) goto cleanup; cleanup: krb5_k_free_key(NULL, ke); krb5_k_free_key(NULL, ki); zapfree(cksum.data, cksum.length); return ret; }
krb5_error_code krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code_out, krb5_data *result_data_out) { krb5_error_code ret; krb5_data result_data, *clear = NULL; krb5_boolean is_error; char *ptr; int result_code; *result_code_out = 0; *result_data_out = empty_data(); ret = get_clear_result(context, auth_context, packet, &clear, &is_error); if (ret) return ret; if (clear->length < 2) { ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } /* Decode and check the result code. */ ptr = clear->data; result_code = (*ptr++ & 0xff); result_code = (result_code << 8) | (*ptr++ & 0xff); if (result_code < KRB5_KPASSWD_SUCCESS || result_code > KRB5_KPASSWD_INITIAL_FLAG_NEEDED) { ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } /* Successful replies must not come from errors. */ if (is_error && result_code == KRB5_KPASSWD_SUCCESS) { ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } result_data = make_data(ptr, clear->data + clear->length - ptr); ret = krb5int_copy_data_contents(context, &result_data, result_data_out); if (ret) goto cleanup; *result_code_out = result_code; cleanup: krb5_free_data(context, clear); return ret; }
krb5_error_code KRB5_CALLCONV krb5_tkt_creds_get(krb5_context context, krb5_tkt_creds_context ctx) { krb5_error_code code; krb5_data request = empty_data(), reply = empty_data(); krb5_data realm = empty_data(); unsigned int flags = 0; int tcp_only = 0, use_master; for (;;) { /* Get the next request and realm. Turn on TCP if necessary. */ code = krb5_tkt_creds_step(context, ctx, &reply, &request, &realm, &flags); if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !tcp_only) { TRACE_TKT_CREDS_RETRY_TCP(context); tcp_only = 1; } else if (code != 0 || !(flags & KRB5_TKT_CREDS_STEP_FLAG_CONTINUE)) break; krb5_free_data_contents(context, &reply); /* Send it to a KDC for the appropriate realm. */ use_master = 0; code = krb5_sendto_kdc(context, &request, &realm, &reply, &use_master, tcp_only); if (code != 0) break; krb5_free_data_contents(context, &request); krb5_free_data_contents(context, &realm); } krb5_free_data_contents(context, &request); krb5_free_data_contents(context, &reply); krb5_free_data_contents(context, &realm); return code; }
/* If state contains a cookie value for pa_type, set *out to the corresponding * data and return true. Otherwise set *out to empty and return false. */ krb5_boolean kdc_fast_search_cookie(struct kdc_request_state *state, krb5_preauthtype pa_type, krb5_data *out) { krb5_pa_data *pa; pa = krb5int_find_pa_data(NULL, state->in_cookie_padata, pa_type); if (pa == NULL) { *out = empty_data(); return FALSE; } else { *out = make_data(pa->contents, pa->length); return TRUE; } }
krb5_error_code krb5int_dk_cmac_decrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { const struct krb5_enc_provider *enc = ktp->enc; krb5_error_code ret; krb5_crypto_iov *header, *trailer; krb5_data cksum = empty_data(); krb5_key ke = NULL, ki = NULL; /* E(Confounder | Plaintext | Pad) | Checksum */ /* Validate header and trailer lengths. */ header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); if (header == NULL || header->data.length != enc->block_size) return KRB5_BAD_MSIZE; trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); if (trailer == NULL || trailer->data.length != enc->block_size) return KRB5_BAD_MSIZE; /* Derive the encryption and integrity keys. */ ret = derive_keys(enc, key, usage, &ke, &ki); if (ret != 0) goto cleanup; /* Decrypt the plaintext (header | data | padding). */ ret = enc->decrypt(ke, ivec, data, num_data); if (ret != 0) goto cleanup; /* Verify the hash. */ ret = alloc_data(&cksum, enc->block_size); if (ret != 0) goto cleanup; ret = krb5int_cmac_checksum(enc, ki, data, num_data, &cksum); if (ret != 0) goto cleanup; if (k5_bcmp(cksum.data, trailer->data.data, enc->block_size) != 0) ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; cleanup: krb5_k_free_key(NULL, ke); krb5_k_free_key(NULL, ki); zapfree(cksum.data, cksum.length); return ret; }
krb5_error_code k5_client_realm_path(krb5_context context, const krb5_data *client, const krb5_data *server, krb5_data **rpath_out) { krb5_error_code retval; char **capvals; size_t i; krb5_data *rpath = NULL, d; retval = rtree_capath_vals(context, client, server, &capvals); if (retval) return retval; /* Count capaths (if any) and allocate space. Leave room for the client * realm, server realm, and terminator. */ for (i = 0; capvals != NULL && capvals[i] != NULL; i++); rpath = calloc(i + 3, sizeof(*rpath)); if (rpath == NULL) return ENOMEM; /* Populate rpath with the client realm, capaths, and server realm. */ retval = krb5int_copy_data_contents(context, client, &rpath[0]); if (retval) goto cleanup; for (i = 0; capvals != NULL && capvals[i] != NULL; i++) { d = make_data(capvals[i], strcspn(capvals[i], "\t ")); retval = krb5int_copy_data_contents(context, &d, &rpath[i + 1]); if (retval) goto cleanup; } retval = krb5int_copy_data_contents(context, server, &rpath[i + 1]); if (retval) goto cleanup; /* Terminate rpath and return it. */ rpath[i + 2] = empty_data(); *rpath_out = rpath; rpath = NULL; cleanup: krb5int_free_data_list(context, rpath); return retval; }
/* Initialize the realm path fields for getting a TGT for * ctx->server->realm. */ static krb5_error_code init_realm_path(krb5_context context, krb5_tkt_creds_context ctx) { krb5_error_code code; krb5_principal *tgt_princ_list = NULL; krb5_data *realm_path; size_t nrealms, i; /* Construct a list of TGT principals from client to server. We will throw * this away after grabbing the remote realms from each principal. */ code = krb5_walk_realm_tree(context, &ctx->client->realm, &ctx->server->realm, &tgt_princ_list, KRB5_REALM_BRANCH_CHAR); if (code != 0) return code; /* Count the number of principals and allocate the realm path. */ for (nrealms = 0; tgt_princ_list[nrealms]; nrealms++); assert(nrealms > 1); realm_path = k5alloc((nrealms + 1) * sizeof(*realm_path), &code); if (realm_path == NULL) goto cleanup; /* Steal the remote realm field from each TGT principal. */ for (i = 0; i < nrealms; i++) { assert(tgt_princ_list[i]->length == 2); realm_path[i] = tgt_princ_list[i]->data[1]; tgt_princ_list[i]->data[1].data = NULL; } realm_path[nrealms] = empty_data(); /* Initialize the realm path fields in ctx. */ krb5int_free_data_list(context, ctx->realm_path); ctx->realm_path = realm_path; ctx->last_realm = realm_path + nrealms - 1; ctx->cur_realm = realm_path; ctx->next_realm = ctx->last_realm; realm_path = NULL; cleanup: krb5_free_realm_tree(context, tgt_princ_list); return 0; }
/* Create a fake error reply. */ static krb5_error_code test_send_error(krb5_context context, void *data, const krb5_data *realm, const krb5_data *message, krb5_data **new_message_out, krb5_data **reply_out) { krb5_error_code ret; krb5_error err; krb5_principal client, server; char *realm_str, *princ_str; int r; realm_str = k5memdup0(realm->data, realm->length, &ret); check(ret); r = asprintf(&princ_str, "invalid@%s", realm_str); assert(r > 0); check(krb5_parse_name(ctx, princ_str, &client)); free(princ_str); r = asprintf(&princ_str, "krbtgt@%s", realm_str); assert(r > 0); check(krb5_parse_name(ctx, princ_str, &server)); free(princ_str); free(realm_str); err.magic = KV5M_ERROR; err.ctime = 1971196337; err.cusec = 0; err.susec = 97008; err.stime = 1458219390; err.error = 6; err.client = client; err.server = server; err.text = string2data("CLIENT_NOT_FOUND"); err.e_data = empty_data(); check(encode_krb5_error(&err, reply_out)); krb5_free_principal(ctx, client); krb5_free_principal(ctx, server); return 0; }
krb5_error_code KRB5_CALLCONV krb5_c_string_to_key_with_params(krb5_context context, krb5_enctype enctype, const krb5_data *string, const krb5_data *salt, const krb5_data *params, krb5_keyblock *key) { krb5_error_code ret; krb5_data empty = empty_data(); const struct krb5_keytypes *ktp; size_t keylength; ktp = find_enctype(enctype); if (ktp == NULL) return KRB5_BAD_ENCTYPE; keylength = ktp->enc->keylength; /* For compatibility with past behavior, treat a null salt as empty. */ if (salt == NULL) salt = ∅ /* Fail gracefully if someone is using the old AFS string-to-key hack. */ if (salt->length == SALT_TYPE_AFS_LENGTH) return EINVAL; key->contents = malloc(keylength); if (key->contents == NULL) return ENOMEM; key->magic = KV5M_KEYBLOCK; key->enctype = enctype; key->length = keylength; ret = (*ktp->str2key)(ktp, string, salt, params, key); if (ret) { zapfree(key->contents, keylength); key->length = 0; key->contents = NULL; } return ret; }
int main( int argc, char *argv[] ) /********************************/ { FILE *in; FILE *out; char buf[MAX_LINE_LEN]; int elt; char *end; char *line; char type[50]; if( argc != 4 ) { printf( "FORMAT: parsectl [input file] [output file] [Ctl data name]\n" ); return( -1 ); } in = fopen( argv[1], "r" ); if( in == NULL ) { printf( "Could not open input file: %s\n", argv[1] ); return( -1 ); } out = fopen( argv[2], "w" ); if( out == NULL ) { printf( "Could not open output file: %s\n", argv[2] ); return( -1 ); } fputs( "/**** DO NOT MODIFY THIS FILE BY HAND. CREATED BY PARSECTL ****/\n\n\n", out ); /* Create Data struct definition */ fputs( "struct {\n", out ); fputs( " int num_ctls;\n", out ); for( elt = 0;; ++elt ) { line = get_line( buf, in ); if( line == NULL ) { break; } end = strpbrk( line, White_space ); if( end == NULL ) { printf( "No control on line %d\n", Line ); goto error; } *end = '\0'; strcpy( type, line ); line = get_line( buf, in ); // skip over data_offset if( line == NULL ) { printf( "No data offset at line %d\n", Line ); goto error; } fputs( " struct {\n", out ); fputs( " ctl_type type;\n", out ); fputs( " int control;\n", out ); fputs( " bool modified;\n", out ); fputs( " unsigned int data_offset;\n", out ); fputs( " union {\n", out ); line = get_line( buf, in ); // skip over data if( line == NULL ) { printf( "No data at line %d\n", Line ); goto error; } if( !empty_data( line ) ) { fprintf( out, " %s d1;\n", my_strlwr( type ) ); } fputs( " ctl_info d2;\n", out ); fputs( " } d3;\n", out ); fprintf( out, " } d%-d;\n", elt ); } fclose( in ); fprintf( out, "} %s = {\n", argv[3] ); fprintf( out, "%d,\n", elt ); in = fopen( argv[1], "r" ); for( ;; ) { line = get_line( buf, in ); if( line == NULL ) { break; } end = strpbrk( line, White_space ); *end = '\0'; ++end; fprintf( out, "{ %s, %s, false,", my_strupr( line ), end ); line = get_line( buf, in ); fprintf( out, " %s", line ); line = get_line( buf, in ); if( !empty_data( line ) ) { fprintf( out, ", %s },\n", line ); } else { fputs( "},\n", out ); } } fputs( "};\n\n", out ); fclose( in ); fclose( out ); return( 0 ); error: fclose( in ); fclose( out ); return( 1 ); }
krb5_error_code KRB5_CALLCONV krb5_mk_priv(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; krb5_data buf = empty_data(); *outbuf = empty_data(); /* Clear replaydata block */ memset(&replaydata, 0, sizeof(krb5_replay_data)); /* Get keyblock */ 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; 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; } } if ((retval = mk_priv_basic(context, userdata, key, &replaydata, plocal_fulladdr, premote_fulladdr, &auth_context->cstate, &buf))) { 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, "_priv", &replay.client))) 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(replay.client); goto error; } free(replay.client); } *outbuf = buf; return 0; error: krb5_free_data_contents(context, &buf); 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_error_code k5_sendto(krb5_context context, const krb5_data *message, const krb5_data *realm, const struct serverlist *servers, k5_transport_strategy strategy, struct sendto_callback_info* callback_info, krb5_data *reply, struct sockaddr *remoteaddr, socklen_t *remoteaddrlen, int *server_used, /* return 0 -> keep going, 1 -> quit */ int (*msg_handler)(krb5_context, const krb5_data *, void *), void *msg_handler_data) { int pass; time_ms delay; krb5_error_code retval; struct conn_state *conns = NULL, *state, **tailptr, *next, *winner; size_t s; struct select_state *sel_state = NULL, *seltemp; char *udpbuf = NULL; krb5_boolean done = FALSE; *reply = empty_data(); /* One for use here, listing all our fds in use, and one for * temporary use in service_fds, for the fds of interest. */ sel_state = malloc(2 * sizeof(*sel_state)); if (sel_state == NULL) { retval = ENOMEM; goto cleanup; } seltemp = &sel_state[1]; cm_init_selstate(sel_state); /* First pass: resolve server hosts, communicate with resulting addresses * of the preferred transport, and wait 1s for an answer from each. */ for (s = 0; s < servers->nservers && !done; s++) { /* Find the current tail pointer. */ for (tailptr = &conns; *tailptr != NULL; tailptr = &(*tailptr)->next); retval = resolve_server(context, realm, servers, s, strategy, message, &udpbuf, &conns); if (retval) goto cleanup; for (state = *tailptr; state != NULL && !done; state = state->next) { /* Contact each new connection, deferring those which use the * non-preferred RFC 4120 transport. */ if (state->defer) continue; if (maybe_send(context, state, message, sel_state, realm, callback_info)) continue; done = service_fds(context, sel_state, 1000, conns, seltemp, realm, msg_handler, msg_handler_data, &winner); } } /* Complete the first pass by contacting servers of the non-preferred RFC * 4120 transport (if given), waiting 1s for an answer from each. */ for (state = conns; state != NULL && !done; state = state->next) { if (!state->defer) continue; if (maybe_send(context, state, message, sel_state, realm, callback_info)) continue; done = service_fds(context, sel_state, 1000, conns, seltemp, realm, msg_handler, msg_handler_data, &winner); } /* Wait for two seconds at the end of the first pass. */ if (!done) { done = service_fds(context, sel_state, 2000, conns, seltemp, realm, msg_handler, msg_handler_data, &winner); } /* Make remaining passes over all of the connections. */ delay = 4000; for (pass = 1; pass < MAX_PASS && !done; pass++) { for (state = conns; state != NULL && !done; state = state->next) { if (maybe_send(context, state, message, sel_state, realm, callback_info)) continue; done = service_fds(context, sel_state, 1000, conns, seltemp, realm, msg_handler, msg_handler_data, &winner); if (sel_state->nfds == 0) break; } /* Wait for the delay backoff at the end of this pass. */ if (!done) { done = service_fds(context, sel_state, delay, conns, seltemp, realm, msg_handler, msg_handler_data, &winner); } if (sel_state->nfds == 0) break; delay *= 2; } if (sel_state->nfds == 0 || !done || winner == NULL) { retval = KRB5_KDC_UNREACH; goto cleanup; } /* Success! */ *reply = make_data(winner->in.buf, winner->in.pos); retval = 0; winner->in.buf = NULL; if (server_used != NULL) *server_used = winner->server_index; if (remoteaddr != NULL && remoteaddrlen != 0 && *remoteaddrlen > 0) (void)getpeername(winner->fd, remoteaddr, remoteaddrlen); TRACE_SENDTO_KDC_RESPONSE(context, reply->length, &winner->addr); cleanup: for (state = conns; state != NULL; state = next) { next = state->next; if (state->fd != INVALID_SOCKET) { if (socktype_for_transport(state->addr.transport) == SOCK_STREAM) TRACE_SENDTO_KDC_TCP_DISCONNECT(context, &state->addr); closesocket(state->fd); free_http_tls_data(context, state); } if (state->state == READING && state->in.buf != udpbuf) free(state->in.buf); if (callback_info) { callback_info->pfn_cleanup(callback_info->data, &state->callback_buffer); } free(state); } if (reply->data != udpbuf) free(udpbuf); free(sel_state); return retval; }