static OM_uint32 importKerberosKey(OM_uint32 *minor, unsigned char **pBuf, size_t *pRemain, krb5_cksumtype *checksumType, krb5_enctype *pEncryptionType, krb5_keyblock *pKey) { unsigned char *p = *pBuf; size_t remain = *pRemain; OM_uint32 encryptionType; OM_uint32 length; krb5_context krbContext; krb5_keyblock key; krb5_error_code code; GSSEAP_KRB_INIT(&krbContext); KRB_KEY_INIT(pKey); if (remain < 12) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } *checksumType = load_uint32_be(&p[0]); encryptionType = load_uint32_be(&p[4]); length = load_uint32_be(&p[8]); if ((length != 0) != (encryptionType != ENCTYPE_NULL)) { *minor = GSSEAP_BAD_CONTEXT_TOKEN; return GSS_S_DEFECTIVE_TOKEN; } if (remain - 12 < length) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } if (encryptionType != ENCTYPE_NULL) { KRB_KEY_INIT(&key); KRB_KEY_TYPE(&key) = encryptionType; KRB_KEY_LENGTH(&key) = length; KRB_KEY_DATA(&key) = &p[12]; code = krb5_copy_keyblock_contents(krbContext, &key, pKey); if (code != 0) { *minor = code; return GSS_S_FAILURE; } } *pBuf += 12 + length; *pRemain -= 12 + length; *pEncryptionType = encryptionType; *minor = 0; return GSS_S_COMPLETE; }
/* Decrypt the ticket in req using the key in ent. */ static krb5_error_code try_one_entry(krb5_context context, const krb5_ap_req *req, krb5_keytab_entry *ent, krb5_keyblock *keyblock_out) { krb5_error_code ret; krb5_principal tmp = NULL; /* Try decrypting the ticket with this entry's key. */ ret = krb5_decrypt_tkt_part(context, &ent->key, req->ticket); if (ret) return ret; /* Make a copy of the principal for the ticket server field. */ ret = krb5_copy_principal(context, ent->principal, &tmp); if (ret) return ret; /* Make a copy of the decrypting key if requested by the caller. */ if (keyblock_out != NULL) { ret = krb5_copy_keyblock_contents(context, &ent->key, keyblock_out); if (ret) { krb5_free_principal(context, tmp); return ret; } } /* Make req->ticket->server indicate the actual server principal. */ krb5_free_principal(context, req->ticket->server); req->ticket->server = tmp; return 0; }
static krb5_error_code set_as_key(krb5_context context, krb5_clpreauth_rock rock, const krb5_keyblock *keyblock) { krb5_free_keyblock_contents(context, rock->as_key); return krb5_copy_keyblock_contents(context, keyblock, rock->as_key); }
krb5_error_code KRB5_CALLCONV krb5_mkt_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor) { krb5_mkt_cursor mkt_cursor = (krb5_mkt_cursor)*cursor; krb5_error_code err = 0; err = KTLOCK(id); if (err) return err; if (mkt_cursor == NULL) { KTUNLOCK(id); return KRB5_KT_END; } entry->magic = mkt_cursor->entry->magic; entry->timestamp = mkt_cursor->entry->timestamp; entry->vno = mkt_cursor->entry->vno; entry->key = mkt_cursor->entry->key; err = krb5_copy_keyblock_contents(context, &(mkt_cursor->entry->key), &(entry->key)); if (!err) err = krb5_copy_principal(context, mkt_cursor->entry->principal, &(entry->principal)); if (!err) *cursor = (krb5_kt_cursor *)mkt_cursor->next; KTUNLOCK(id); return(err); }
krb5_error_code KRB5_CALLCONV krb5_copy_creds(krb5_context context, const krb5_creds *incred, krb5_creds **outcred) { krb5_creds *tempcred; krb5_error_code retval; krb5_data *scratch; if (!(tempcred = (krb5_creds *)malloc(sizeof(*tempcred)))) return ENOMEM; *tempcred = *incred; retval = krb5_copy_principal(context, incred->client, &tempcred->client); if (retval) goto cleanlast; retval = krb5_copy_principal(context, incred->server, &tempcred->server); if (retval) goto cleanclient; retval = krb5_copy_keyblock_contents(context, &incred->keyblock, &tempcred->keyblock); if (retval) goto cleanserver; retval = krb5_copy_addresses(context, incred->addresses, &tempcred->addresses); if (retval) goto cleanblock; retval = krb5_copy_data(context, &incred->ticket, &scratch); if (retval) goto cleanaddrs; tempcred->ticket = *scratch; krb5_xfree(scratch); retval = krb5_copy_data(context, &incred->second_ticket, &scratch); if (retval) goto cleanticket; tempcred->second_ticket = *scratch; krb5_xfree(scratch); retval = krb5_copy_authdata(context, incred->authdata,&tempcred->authdata); if (retval) goto clearticket; *outcred = tempcred; return 0; clearticket: memset(tempcred->ticket.data,0,tempcred->ticket.length); cleanticket: free(tempcred->ticket.data); cleanaddrs: krb5_free_addresses(context, tempcred->addresses); cleanblock: krb5_xfree(tempcred->keyblock.contents); cleanserver: krb5_free_principal(context, tempcred->server); cleanclient: krb5_free_principal(context, tempcred->client); cleanlast: krb5_xfree(tempcred); return retval; }
/* * Copy contents of input credentials structure to supplied * destination, allocating storage for indirect fields as needed. On * success, the output is a deep copy of the input. On error, the * output structure is garbage and its contents should be ignored. */ krb5_error_code k5_copy_creds_contents(krb5_context context, const krb5_creds *incred, krb5_creds *tempcred) { krb5_error_code retval; krb5_data *scratch; *tempcred = *incred; retval = krb5_copy_principal(context, incred->client, &tempcred->client); if (retval) goto cleanlast; retval = krb5_copy_principal(context, incred->server, &tempcred->server); if (retval) goto cleanclient; retval = krb5_copy_keyblock_contents(context, &incred->keyblock, &tempcred->keyblock); if (retval) goto cleanserver; retval = krb5_copy_addresses(context, incred->addresses, &tempcred->addresses); if (retval) goto cleanblock; retval = krb5_copy_data(context, &incred->ticket, &scratch); if (retval) goto cleanaddrs; tempcred->ticket = *scratch; free(scratch); retval = krb5_copy_data(context, &incred->second_ticket, &scratch); if (retval) goto clearticket; tempcred->second_ticket = *scratch; free(scratch); retval = krb5_copy_authdata(context, incred->authdata,&tempcred->authdata); if (retval) goto clearsecondticket; return 0; clearsecondticket: memset(tempcred->second_ticket.data,0,tempcred->second_ticket.length); free(tempcred->second_ticket.data); clearticket: memset(tempcred->ticket.data,0,tempcred->ticket.length); free(tempcred->ticket.data); cleanaddrs: krb5_free_addresses(context, tempcred->addresses); cleanblock: free(tempcred->keyblock.contents); cleanserver: krb5_free_principal(context, tempcred->server); cleanclient: krb5_free_principal(context, tempcred->client); cleanlast: /* Do not free tempcred - we did not allocate it - its contents are garbage - but we should not free it */ return retval; }
static krb5_error_code AES_SHA1_string_to_key(krb5_context context, krb5_enctype enctype, krb5_data password, krb5_salt salt, krb5_data opaque, krb5_keyblock *key) { krb5_error_code ret; uint32_t iter; struct _krb5_encryption_type *et; struct _krb5_key_data kd; if (opaque.length == 0) iter = _krb5_AES_SHA1_string_to_default_iterator; else if (opaque.length == 4) { unsigned long v; _krb5_get_int(opaque.data, &v, 4); iter = ((uint32_t)v); } else return KRB5_PROG_KEYTYPE_NOSUPP; /* XXX */ et = _krb5_find_enctype(enctype); if (et == NULL) return KRB5_PROG_KEYTYPE_NOSUPP; kd.schedule = NULL; ALLOC(kd.key, 1); if (kd.key == NULL) return krb5_enomem(context); kd.key->keytype = enctype; ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size); if (ret) { krb5_set_error_message (context, ret, N_("malloc: out of memory", "")); return ret; } ret = PKCS5_PBKDF2_HMAC(password.data, password.length, salt.saltvalue.data, salt.saltvalue.length, iter, EVP_sha1(), et->keytype->size, kd.key->keyvalue.data); if (ret != 1) { _krb5_free_key_data(context, &kd, et); krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, "Error calculating s2k"); return KRB5_PROG_KEYTYPE_NOSUPP; } ret = _krb5_derive_key(context, et, &kd, "kerberos", strlen("kerberos")); if (ret == 0) ret = krb5_copy_keyblock_contents(context, kd.key, key); _krb5_free_key_data(context, &kd, et); return ret; }
krb5_error_code KRB5_CALLCONV krb5_mkt_add(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) { krb5_error_code err = 0; krb5_mkt_cursor cursor; err = KTLOCK(id); if (err) return err; cursor = (krb5_mkt_cursor)malloc(sizeof(krb5_mkt_link)); if (cursor == NULL) { err = ENOMEM; goto done; } cursor->entry = (krb5_keytab_entry *)malloc(sizeof(krb5_keytab_entry)); if (cursor->entry == NULL) { free(cursor); err = ENOMEM; goto done; } cursor->entry->magic = entry->magic; cursor->entry->timestamp = entry->timestamp; cursor->entry->vno = entry->vno; err = krb5_copy_keyblock_contents(context, &(entry->key), &(cursor->entry->key)); if (err) { free(cursor->entry); free(cursor); goto done; } err = krb5_copy_principal(context, entry->principal, &(cursor->entry->principal)); if (err) { krb5_free_keyblock_contents(context, &(cursor->entry->key)); free(cursor->entry); free(cursor); goto done; } if (KTLINK(id) == NULL) { cursor->next = NULL; KTLINK(id) = cursor; } else { cursor->next = KTLINK(id); KTLINK(id) = cursor; } done: KTUNLOCK(id); return err; }
void ZSetSession(krb5_keyblock *keyblock) { krb5_error_code result; if (__Zephyr_keyblock) { krb5_free_keyblock_contents(Z_krb5_ctx, __Zephyr_keyblock); result = krb5_copy_keyblock_contents(Z_krb5_ctx, keyblock, __Zephyr_keyblock); } else { result = krb5_copy_keyblock(Z_krb5_ctx, keyblock, &__Zephyr_keyblock); } if (result) /*XXX we're out of memory? */ return; }
krb5_error_code KRB5_LIB_FUNCTION krb5_copy_creds_contents (krb5_context context, const krb5_creds *incred, krb5_creds *c) { krb5_error_code ret; memset(c, 0, sizeof(*c)); ret = krb5_copy_principal (context, incred->client, &c->client); if (ret) goto fail; ret = krb5_copy_principal (context, incred->server, &c->server); if (ret) goto fail; ret = krb5_copy_keyblock_contents (context, &incred->session, &c->session); if (ret) goto fail; c->times = incred->times; ret = krb5_data_copy (&c->ticket, incred->ticket.data, incred->ticket.length); if (ret) goto fail; ret = krb5_data_copy (&c->second_ticket, incred->second_ticket.data, incred->second_ticket.length); if (ret) goto fail; ret = copy_AuthorizationData(&incred->authdata, &c->authdata); if (ret) goto fail; ret = krb5_copy_addresses (context, &incred->addresses, &c->addresses); if (ret) goto fail; c->flags = incred->flags; return 0; fail: krb5_free_cred_contents (context, c); return ret; }
krb5_error_code _hdb_keytab2hdb_entry(krb5_context context, const krb5_keytab_entry *ktentry, hdb_entry_ex *entry) { entry->entry.kvno = ktentry->vno; entry->entry.created_by.time = ktentry->timestamp; entry->entry.keys.val = calloc(1, sizeof(entry->entry.keys.val[0])); if (entry->entry.keys.val == NULL) return ENOMEM; entry->entry.keys.len = 1; entry->entry.keys.val[0].mkvno = NULL; entry->entry.keys.val[0].salt = NULL; return krb5_copy_keyblock_contents(context, &ktentry->keyblock, &entry->entry.keys.val[0].key); }
krb5_error_code krb5int_fast_reply_key(krb5_context context, krb5_keyblock *strengthen_key, krb5_keyblock *existing_key, krb5_keyblock *out_key) { krb5_keyblock *key = NULL; krb5_error_code retval = 0; krb5_free_keyblock_contents(context, out_key); if (strengthen_key) { retval = krb5_c_fx_cf2_simple(context, strengthen_key, "strengthenkey", existing_key, "replykey", &key); if (retval == 0) { *out_key = *key; free(key); } } else { retval = krb5_copy_keyblock_contents(context, existing_key, out_key); } return retval; }
kadm5_ret_t _kadm5_set_keys3(kadm5_server_context *context, hdb_entry *ent, int n_keys, krb5_keyblock *keyblocks) { krb5_error_code ret; int i; unsigned len; Key *keys; len = n_keys; keys = malloc (len * sizeof(*keys)); if (keys == NULL) return ENOMEM; _kadm5_init_keys (keys, len); for(i = 0; i < n_keys; i++) { keys[i].mkvno = NULL; ret = krb5_copy_keyblock_contents (context->context, &keyblocks[i], &keys[i].key); if(ret) goto out; keys[i].salt = NULL; } _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); ent->keys.len = len; ent->keys.val = keys; hdb_entry_set_pw_change_time(context->context, ent, 0); hdb_entry_clear_password(context->context, ent); return 0; out: _kadm5_free_keys (context->context, len, keys); return ret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_kt_copy_entry_contents(krb5_context context, const krb5_keytab_entry *in, krb5_keytab_entry *out) { krb5_error_code ret; memset(out, 0, sizeof(*out)); out->vno = in->vno; ret = krb5_copy_principal (context, in->principal, &out->principal); if (ret) goto fail; ret = krb5_copy_keyblock_contents (context, &in->keyblock, &out->keyblock); if (ret) goto fail; out->timestamp = in->timestamp; return 0; fail: krb5_kt_free_entry (context, out); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_copy_keyblock (krb5_context context, const krb5_keyblock *inblock, krb5_keyblock **to) { krb5_error_code ret; krb5_keyblock *k; *to = NULL; k = calloc (1, sizeof(*k)); if (k == NULL) { krb5_heim_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } ret = krb5_copy_keyblock_contents (context, inblock, k); if (ret) { free(k); return ret; } *to = k; return 0; }
static krb5_error_code otp_return_padata(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_out, krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq) { krb5_keyblock *armor_key = NULL; if (padata->length == 0) return 0; /* Get the armor key. */ armor_key = cb->fast_armor(context, rock); if (!armor_key) { com_err("otp", ENOENT, "No armor key found when returning padata"); return ENOENT; } /* Replace the reply key with the FAST armor key. */ krb5_free_keyblock_contents(context, encrypting_key); return krb5_copy_keyblock_contents(context, armor_key, encrypting_key); }
static mit_krb5_error_code krb5_kt_copy_entry_contents(mit_krb5_context context, const mit_krb5_keytab_entry *in, mit_krb5_keytab_entry *out) { krb5_error_code ret; LOG_ENTRY(); memset(out, 0, sizeof(*out)); out->vno = in->vno; ret = krb5_copy_principal (context, in->principal, &out->principal); if (ret) goto fail; ret = krb5_copy_keyblock_contents (context, &in->key, &out->key); if (ret) goto fail; out->timestamp = in->timestamp; return 0; fail: krb5_kt_free_entry (context, out); return ret; }
static krb5_error_code pkinit_server_return_padata(krb5_context context, krb5_pa_data * padata, struct _krb5_db_entry_new * client, krb5_data *req_pkt, krb5_kdc_req * request, krb5_kdc_rep * reply, struct _krb5_key_data * client_key, krb5_keyblock * encrypting_key, krb5_pa_data ** send_pa, preauth_get_entry_data_proc server_get_entry_data, void *pa_plugin_context, void **pa_request_context) { krb5_error_code retval = 0; krb5_data scratch = {0, 0, NULL}; krb5_pa_pk_as_req *reqp = NULL; krb5_pa_pk_as_req_draft9 *reqp9 = NULL; int i = 0; unsigned char *subjectPublicKey = NULL; unsigned char *dh_pubkey = NULL, *server_key = NULL; unsigned int subjectPublicKey_len = 0; unsigned int server_key_len = 0, dh_pubkey_len = 0; krb5_kdc_dh_key_info dhkey_info; krb5_data *encoded_dhkey_info = NULL; krb5_pa_pk_as_rep *rep = NULL; krb5_pa_pk_as_rep_draft9 *rep9 = NULL; krb5_data *out_data = NULL; krb5_enctype enctype = -1; krb5_reply_key_pack *key_pack = NULL; krb5_reply_key_pack_draft9 *key_pack9 = NULL; krb5_data *encoded_key_pack = NULL; unsigned int num_types; krb5_cksumtype *cksum_types = NULL; pkinit_kdc_context plgctx; pkinit_kdc_req_context reqctx; int fixed_keypack = 0; *send_pa = NULL; if (padata == NULL || padata->length <= 0 || padata->contents == NULL) return 0; if (pa_request_context == NULL || *pa_request_context == NULL) { pkiDebug("missing request context \n"); return EINVAL; } plgctx = pkinit_find_realm_context(context, pa_plugin_context, request->server); if (plgctx == NULL) { pkiDebug("Unable to locate correct realm context\n"); return ENOENT; } pkiDebug("pkinit_return_padata: entered!\n"); reqctx = (pkinit_kdc_req_context)*pa_request_context; if (encrypting_key->contents) { free(encrypting_key->contents); encrypting_key->length = 0; encrypting_key->contents = NULL; } for(i = 0; i < request->nktypes; i++) { enctype = request->ktype[i]; if (!krb5_c_valid_enctype(enctype)) continue; else { pkiDebug("KDC picked etype = %d\n", enctype); break; } } if (i == request->nktypes) { retval = KRB5KDC_ERR_ETYPE_NOSUPP; goto cleanup; } switch((int)reqctx->pa_type) { case KRB5_PADATA_PK_AS_REQ: init_krb5_pa_pk_as_rep(&rep); if (rep == NULL) { retval = ENOMEM; goto cleanup; } /* let's assume it's RSA. we'll reset it to DH if needed */ rep->choice = choice_pa_pk_as_rep_encKeyPack; break; case KRB5_PADATA_PK_AS_REP_OLD: case KRB5_PADATA_PK_AS_REQ_OLD: init_krb5_pa_pk_as_rep_draft9(&rep9); if (rep9 == NULL) { retval = ENOMEM; goto cleanup; } rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack; break; default: retval = KRB5KDC_ERR_PREAUTH_FAILED; goto cleanup; } if (reqctx->rcv_auth_pack != NULL && reqctx->rcv_auth_pack->clientPublicValue != NULL) { subjectPublicKey = reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.data; subjectPublicKey_len = reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.length; rep->choice = choice_pa_pk_as_rep_dhInfo; } else if (reqctx->rcv_auth_pack9 != NULL && reqctx->rcv_auth_pack9->clientPublicValue != NULL) { subjectPublicKey = reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.data; subjectPublicKey_len = reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.length; rep9->choice = choice_pa_pk_as_rep_draft9_dhSignedData; } /* if this DH, then process finish computing DH key */ if (rep != NULL && (rep->choice == choice_pa_pk_as_rep_dhInfo || rep->choice == choice_pa_pk_as_rep_draft9_dhSignedData)) { pkiDebug("received DH key delivery AS REQ\n"); retval = server_process_dh(context, plgctx->cryptoctx, reqctx->cryptoctx, plgctx->idctx, subjectPublicKey, subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len, &server_key, &server_key_len); if (retval) { pkiDebug("failed to process/create dh paramters\n"); goto cleanup; } } if ((rep9 != NULL && rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) || (rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) { retval = pkinit_octetstring2key(context, enctype, server_key, server_key_len, encrypting_key); if (retval) { pkiDebug("pkinit_octetstring2key failed: %s\n", error_message(retval)); goto cleanup; } dhkey_info.subjectPublicKey.length = dh_pubkey_len; dhkey_info.subjectPublicKey.data = dh_pubkey; dhkey_info.nonce = request->nonce; dhkey_info.dhKeyExpiration = 0; retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info, &encoded_dhkey_info); if (retval) { pkiDebug("encode_krb5_kdc_dh_key_info failed\n"); goto cleanup; } #ifdef DEBUG_ASN1 print_buffer_bin((unsigned char *)encoded_dhkey_info->data, encoded_dhkey_info->length, "/tmp/kdc_dh_key_info"); #endif switch ((int)padata->pa_type) { case KRB5_PADATA_PK_AS_REQ: retval = cms_signeddata_create(context, plgctx->cryptoctx, reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_SERVER, 1, (unsigned char *)encoded_dhkey_info->data, encoded_dhkey_info->length, &rep->u.dh_Info.dhSignedData.data, &rep->u.dh_Info.dhSignedData.length); if (retval) { pkiDebug("failed to create pkcs7 signed data\n"); goto cleanup; } break; case KRB5_PADATA_PK_AS_REP_OLD: case KRB5_PADATA_PK_AS_REQ_OLD: retval = cms_signeddata_create(context, plgctx->cryptoctx, reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9, 1, (unsigned char *)encoded_dhkey_info->data, encoded_dhkey_info->length, &rep9->u.dhSignedData.data, &rep9->u.dhSignedData.length); if (retval) { pkiDebug("failed to create pkcs7 signed data\n"); goto cleanup; } break; } } else { pkiDebug("received RSA key delivery AS REQ\n"); retval = krb5_c_make_random_key(context, enctype, encrypting_key); if (retval) { pkiDebug("unable to make a session key\n"); goto cleanup; } /* check if PA_TYPE of 132 is present which means the client is * requesting that a checksum is send back instead of the nonce */ for (i = 0; request->padata[i] != NULL; i++) { pkiDebug("%s: Checking pa_type 0x%08x\n", __FUNCTION__, request->padata[i]->pa_type); if (request->padata[i]->pa_type == 132) fixed_keypack = 1; } pkiDebug("%s: return checksum instead of nonce = %d\n", __FUNCTION__, fixed_keypack); /* if this is an RFC reply or draft9 client requested a checksum * in the reply instead of the nonce, create an RFC-style keypack */ if ((int)padata->pa_type == KRB5_PADATA_PK_AS_REQ || fixed_keypack) { init_krb5_reply_key_pack(&key_pack); if (key_pack == NULL) { retval = ENOMEM; goto cleanup; } /* retrieve checksums for a given enctype of the reply key */ retval = krb5_c_keyed_checksum_types(context, encrypting_key->enctype, &num_types, &cksum_types); if (retval) goto cleanup; /* pick the first of acceptable enctypes for the checksum */ retval = krb5_c_make_checksum(context, cksum_types[0], encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, req_pkt, &key_pack->asChecksum); if (retval) { pkiDebug("unable to calculate AS REQ checksum\n"); goto cleanup; } #ifdef DEBUG_CKSUM pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length); print_buffer(req_pkt->data, req_pkt->length); pkiDebug("checksum size = %d\n", key_pack->asChecksum.length); print_buffer(key_pack->asChecksum.contents, key_pack->asChecksum.length); pkiDebug("encrypting key (%d)\n", encrypting_key->length); print_buffer(encrypting_key->contents, encrypting_key->length); #endif krb5_copy_keyblock_contents(context, encrypting_key, &key_pack->replyKey); retval = k5int_encode_krb5_reply_key_pack(key_pack, &encoded_key_pack); if (retval) { pkiDebug("failed to encode reply_key_pack\n"); goto cleanup; } } switch ((int)padata->pa_type) { case KRB5_PADATA_PK_AS_REQ: rep->choice = choice_pa_pk_as_rep_encKeyPack; retval = cms_envelopeddata_create(context, plgctx->cryptoctx, reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1, (unsigned char *)encoded_key_pack->data, encoded_key_pack->length, &rep->u.encKeyPack.data, &rep->u.encKeyPack.length); break; case KRB5_PADATA_PK_AS_REP_OLD: case KRB5_PADATA_PK_AS_REQ_OLD: /* if the request is from the broken draft9 client that * expects back a nonce, create it now */ if (!fixed_keypack) { init_krb5_reply_key_pack_draft9(&key_pack9); if (key_pack9 == NULL) { retval = ENOMEM; goto cleanup; } key_pack9->nonce = reqctx->rcv_auth_pack9->pkAuthenticator.nonce; krb5_copy_keyblock_contents(context, encrypting_key, &key_pack9->replyKey); retval = k5int_encode_krb5_reply_key_pack_draft9(key_pack9, &encoded_key_pack); if (retval) { pkiDebug("failed to encode reply_key_pack\n"); goto cleanup; } } rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack; retval = cms_envelopeddata_create(context, plgctx->cryptoctx, reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1, (unsigned char *)encoded_key_pack->data, encoded_key_pack->length, &rep9->u.encKeyPack.data, &rep9->u.encKeyPack.length); break; } if (retval) { pkiDebug("failed to create pkcs7 enveloped data: %s\n", error_message(retval)); goto cleanup; } #ifdef DEBUG_ASN1 print_buffer_bin((unsigned char *)encoded_key_pack->data, encoded_key_pack->length, "/tmp/kdc_key_pack"); switch ((int)padata->pa_type) { case KRB5_PADATA_PK_AS_REQ: print_buffer_bin(rep->u.encKeyPack.data, rep->u.encKeyPack.length, "/tmp/kdc_enc_key_pack"); break; case KRB5_PADATA_PK_AS_REP_OLD: case KRB5_PADATA_PK_AS_REQ_OLD: print_buffer_bin(rep9->u.encKeyPack.data, rep9->u.encKeyPack.length, "/tmp/kdc_enc_key_pack"); break; } #endif } switch ((int)padata->pa_type) { case KRB5_PADATA_PK_AS_REQ: retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data); break; case KRB5_PADATA_PK_AS_REP_OLD: case KRB5_PADATA_PK_AS_REQ_OLD: retval = k5int_encode_krb5_pa_pk_as_rep_draft9(rep9, &out_data); break; } if (retval) { pkiDebug("failed to encode AS_REP\n"); goto cleanup; } #ifdef DEBUG_ASN1 if (out_data != NULL) print_buffer_bin((unsigned char *)out_data->data, out_data->length, "/tmp/kdc_as_rep"); #endif *send_pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data)); if (*send_pa == NULL) { retval = ENOMEM; free(out_data->data); free(out_data); out_data = NULL; goto cleanup; } (*send_pa)->magic = KV5M_PA_DATA; switch ((int)padata->pa_type) { case KRB5_PADATA_PK_AS_REQ: (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP; break; case KRB5_PADATA_PK_AS_REQ_OLD: case KRB5_PADATA_PK_AS_REP_OLD: (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP_OLD; break; } (*send_pa)->length = out_data->length; (*send_pa)->contents = (krb5_octet *) out_data->data; cleanup: pkinit_fini_kdc_req_context(context, reqctx); if (scratch.data != NULL) free(scratch.data); if (out_data != NULL) free(out_data); if (encoded_dhkey_info != NULL) krb5_free_data(context, encoded_dhkey_info); if (encoded_key_pack != NULL) krb5_free_data(context, encoded_key_pack); if (dh_pubkey != NULL) free(dh_pubkey); if (server_key != NULL) free(server_key); if (cksum_types != NULL) free(cksum_types); switch ((int)padata->pa_type) { case KRB5_PADATA_PK_AS_REQ: free_krb5_pa_pk_as_req(&reqp); free_krb5_pa_pk_as_rep(&rep); free_krb5_reply_key_pack(&key_pack); break; case KRB5_PADATA_PK_AS_REP_OLD: case KRB5_PADATA_PK_AS_REQ_OLD: free_krb5_pa_pk_as_req_draft9(&reqp9); free_krb5_pa_pk_as_rep_draft9(&rep9); if (!fixed_keypack) free_krb5_reply_key_pack_draft9(&key_pack9); else free_krb5_reply_key_pack(&key_pack); break; } if (retval) pkiDebug("pkinit_verify_padata failure"); return retval; }
krb5_error_code KRB5_CALLCONV krb5_mkt_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal principal, krb5_kvno kvno, krb5_enctype enctype, krb5_keytab_entry *out_entry) { krb5_mkt_cursor cursor; krb5_keytab_entry *entry, *match = NULL; krb5_error_code err = 0; int found_wrong_kvno = 0; krb5_boolean similar = 0; err = KTLOCK(id); if (err) return err; for (cursor = KTLINK(id); cursor && cursor->entry; cursor = cursor->next) { entry = cursor->entry; /* if the principal isn't the one requested, continue to the next. */ if (!krb5_principal_compare(context, principal, entry->principal)) continue; /* if the enctype is not ignored and doesn't match, and continue to the next */ if (enctype != IGNORE_ENCTYPE) { if ((err = krb5_c_enctype_compare(context, enctype, entry->key.enctype, &similar))) { /* we can't determine the enctype of the entry */ continue; } if (!similar) continue; } if (kvno == IGNORE_VNO) { if (match == NULL) match = entry; else if (entry->vno > match->vno) match = entry; } else { if (entry->vno == kvno) { match = entry; break; } else { found_wrong_kvno++; } } } /* if we found an entry that matches, ... */ if (match) { out_entry->magic = match->magic; out_entry->timestamp = match->timestamp; out_entry->vno = match->vno; out_entry->key = match->key; err = krb5_copy_keyblock_contents(context, &(match->key), &(out_entry->key)); /* * Coerce the enctype of the output keyblock in case we * got an inexact match on the enctype. */ if(enctype != IGNORE_ENCTYPE) out_entry->key.enctype = enctype; if(!err) { err = krb5_copy_principal(context, match->principal, &(out_entry->principal)); } } else { if (!err) err = found_wrong_kvno ? KRB5_KT_KVNONOTFOUND : KRB5_KT_NOTFOUND; } KTUNLOCK(id); return(err); }
static krb5_error_code tgs_make_reply(krb5_context context, krb5_kdc_configuration *config, KDC_REQ_BODY *b, krb5_const_principal tgt_name, const EncTicketPart *tgt, const EncryptionKey *serverkey, const krb5_keyblock *sessionkey, krb5_kvno kvno, AuthorizationData *auth_data, hdb_entry_ex *server, const char *server_name, hdb_entry_ex *client, krb5_principal client_principal, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, KRB5SignedPathPrincipals *spp, const krb5_data *rspac, const char **e_text, krb5_data *reply) { KDC_REP rep; EncKDCRepPart ek; EncTicketPart et; KDCOptions f = b->kdc_options; krb5_error_code ret; memset(&rep, 0, sizeof(rep)); memset(&et, 0, sizeof(et)); memset(&ek, 0, sizeof(ek)); rep.pvno = 5; rep.msg_type = krb_tgs_rep; et.authtime = tgt->authtime; _kdc_fix_time(&b->till); et.endtime = min(tgt->endtime, *b->till); ALLOC(et.starttime); *et.starttime = kdc_time; ret = check_tgs_flags(context, config, b, tgt, &et); if(ret) goto out; /* We should check the transited encoding if: 1) the request doesn't ask not to be checked 2) globally enforcing a check 3) principal requires checking 4) we allow non-check per-principal, but principal isn't marked as allowing this 5) we don't globally allow this */ #define GLOBAL_FORCE_TRANSITED_CHECK \ (config->trpolicy == TRPOLICY_ALWAYS_CHECK) #define GLOBAL_ALLOW_PER_PRINCIPAL \ (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL) #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \ (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST) /* these will consult the database in future release */ #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0 ret = fix_transited_encoding(context, config, !f.disable_transited_check || GLOBAL_FORCE_TRANSITED_CHECK || PRINCIPAL_FORCE_TRANSITED_CHECK(server) || !((GLOBAL_ALLOW_PER_PRINCIPAL && PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) || GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK), &tgt->transited, &et, *krb5_princ_realm(context, client_principal), *krb5_princ_realm(context, server->entry.principal), *krb5_princ_realm(context, krbtgt->entry.principal)); if(ret) goto out; copy_Realm(krb5_princ_realm(context, server->entry.principal), &rep.ticket.realm); _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal); copy_Realm(&tgt_name->realm, &rep.crealm); /* if (f.request_anonymous) _kdc_make_anonymous_principalname (&rep.cname); else */ copy_PrincipalName(&tgt_name->name, &rep.cname); rep.ticket.tkt_vno = 5; ek.caddr = et.caddr; if(et.caddr == NULL) et.caddr = tgt->caddr; { time_t life; life = et.endtime - *et.starttime; if(client && client->entry.max_life) life = min(life, *client->entry.max_life); if(server->entry.max_life) life = min(life, *server->entry.max_life); et.endtime = *et.starttime + life; } if(f.renewable_ok && tgt->flags.renewable && et.renew_till == NULL && et.endtime < *b->till){ et.flags.renewable = 1; ALLOC(et.renew_till); *et.renew_till = *b->till; } if(et.renew_till){ time_t renew; renew = *et.renew_till - et.authtime; if(client && client->entry.max_renew) renew = min(renew, *client->entry.max_renew); if(server->entry.max_renew) renew = min(renew, *server->entry.max_renew); *et.renew_till = et.authtime + renew; } if(et.renew_till){ *et.renew_till = min(*et.renew_till, *tgt->renew_till); *et.starttime = min(*et.starttime, *et.renew_till); et.endtime = min(et.endtime, *et.renew_till); } *et.starttime = min(*et.starttime, et.endtime); if(*et.starttime == et.endtime){ ret = KRB5KDC_ERR_NEVER_VALID; goto out; } if(et.renew_till && et.endtime == *et.renew_till){ free(et.renew_till); et.renew_till = NULL; et.flags.renewable = 0; } et.flags.pre_authent = tgt->flags.pre_authent; et.flags.hw_authent = tgt->flags.hw_authent; et.flags.anonymous = tgt->flags.anonymous; et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate; if (auth_data) { /* XXX Check enc-authorization-data */ et.authorization_data = calloc(1, sizeof(*et.authorization_data)); if (et.authorization_data == NULL) { ret = ENOMEM; goto out; } ret = copy_AuthorizationData(auth_data, et.authorization_data); if (ret) goto out; /* Filter out type KRB5SignedPath */ ret = find_KRB5SignedPath(context, et.authorization_data, NULL); if (ret == 0) { if (et.authorization_data->len == 1) { free_AuthorizationData(et.authorization_data); free(et.authorization_data); et.authorization_data = NULL; } else { AuthorizationData *ad = et.authorization_data; free_AuthorizationDataElement(&ad->val[ad->len - 1]); ad->len--; } } } if(rspac->length) { /* * No not need to filter out the any PAC from the * auth_data since its signed by the KDC. */ ret = _kdc_tkt_add_if_relevant_ad(context, &et, KRB5_AUTHDATA_WIN2K_PAC, rspac); if (ret) goto out; } ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key); if (ret) goto out; et.crealm = tgt->crealm; et.cname = tgt_name->name; ek.key = et.key; /* MIT must have at least one last_req */ ek.last_req.len = 1; ek.last_req.val = calloc(1, sizeof(*ek.last_req.val)); if (ek.last_req.val == NULL) { ret = ENOMEM; goto out; } ek.nonce = b->nonce; ek.flags = et.flags; ek.authtime = et.authtime; ek.starttime = et.starttime; ek.endtime = et.endtime; ek.renew_till = et.renew_till; ek.srealm = rep.ticket.realm; ek.sname = rep.ticket.sname; _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, et.endtime, et.renew_till); /* Don't sign cross realm tickets, they can't be checked anyway */ { char *r = get_krbtgt_realm(&ek.sname); if (r == NULL || strcmp(r, ek.srealm) == 0) { ret = _kdc_add_KRB5SignedPath(context, config, krbtgt, krbtgt_etype, NULL, spp, &et); if (ret) goto out; } } /* It is somewhat unclear where the etype in the following encryption should come from. What we have is a session key in the passed tgt, and a list of preferred etypes *for the new ticket*. Should we pick the best possible etype, given the keytype in the tgt, or should we look at the etype list here as well? What if the tgt session key is DES3 and we want a ticket with a (say) CAST session key. Should the DES3 etype be added to the etype list, even if we don't want a session key with DES3? */ ret = _kdc_encode_reply(context, config, &rep, &et, &ek, et.key.keytype, kvno, serverkey, 0, &tgt->key, e_text, reply); out: free_TGS_REP(&rep); free_TransitedEncoding(&et.transited); if(et.starttime) free(et.starttime); if(et.renew_till) free(et.renew_till); if(et.authorization_data) { free_AuthorizationData(et.authorization_data); free(et.authorization_data); } free_LastReq(&ek.last_req); memset(et.key.keyvalue.data, 0, et.key.keyvalue.length); free_EncryptionKey(&et.key); return ret; }
krb5_error_code _kdc_pk_mk_pa_reply(krb5_context context, krb5_kdc_configuration *config, pk_client_params *cp, const hdb_entry_ex *client, krb5_enctype sessionetype, const KDC_REQ *req, const krb5_data *req_buffer, krb5_keyblock *reply_key, krb5_keyblock *sessionkey, METHOD_DATA *md) { krb5_error_code ret; void *buf = NULL; size_t len = 0, size = 0; krb5_enctype enctype; int pa_type; hx509_cert kdc_cert = NULL; size_t i; if (!config->enable_pkinit) { krb5_clear_error_message(context); return 0; } if (req->req_body.etype.len > 0) { for (i = 0; i < req->req_body.etype.len; i++) if (krb5_enctype_valid(context, req->req_body.etype.val[i]) == 0) break; if (req->req_body.etype.len <= i) { ret = KRB5KRB_ERR_GENERIC; krb5_set_error_message(context, ret, "No valid enctype available from client"); goto out; } enctype = req->req_body.etype.val[i]; } else enctype = ETYPE_DES3_CBC_SHA1; if (cp->type == PKINIT_27) { PA_PK_AS_REP rep; const char *type, *other = ""; memset(&rep, 0, sizeof(rep)); pa_type = KRB5_PADATA_PK_AS_REP; if (cp->keyex == USE_RSA) { ContentInfo info; type = "enckey"; rep.element = choice_PA_PK_AS_REP_encKeyPack; ret = krb5_generate_random_keyblock(context, enctype, &cp->reply_key); if (ret) { free_PA_PK_AS_REP(&rep); goto out; } ret = pk_mk_pa_reply_enckey(context, config, cp, req, req_buffer, &cp->reply_key, &info, &kdc_cert); if (ret) { free_PA_PK_AS_REP(&rep); goto out; } ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data, rep.u.encKeyPack.length, &info, &size, ret); free_ContentInfo(&info); if (ret) { krb5_set_error_message(context, ret, "encoding of Key ContentInfo " "failed %d", ret); free_PA_PK_AS_REP(&rep); goto out; } if (rep.u.encKeyPack.length != size) krb5_abortx(context, "Internal ASN.1 encoder error"); ret = krb5_generate_random_keyblock(context, sessionetype, sessionkey); if (ret) { free_PA_PK_AS_REP(&rep); goto out; } } else { ContentInfo info; switch (cp->keyex) { case USE_DH: type = "dh"; break; case USE_ECDH: type = "ecdh"; break; default: krb5_abortx(context, "unknown keyex"); break; } if (cp->dh_group_name) other = cp->dh_group_name; rep.element = choice_PA_PK_AS_REP_dhInfo; ret = generate_dh_keyblock(context, cp, enctype); if (ret) return ret; ret = pk_mk_pa_reply_dh(context, config, cp, &info, &kdc_cert); if (ret) { free_PA_PK_AS_REP(&rep); krb5_set_error_message(context, ret, "create pa-reply-dh " "failed %d", ret); goto out; } ASN1_MALLOC_ENCODE(ContentInfo, rep.u.dhInfo.dhSignedData.data, rep.u.dhInfo.dhSignedData.length, &info, &size, ret); free_ContentInfo(&info); if (ret) { krb5_set_error_message(context, ret, "encoding of Key ContentInfo " "failed %d", ret); free_PA_PK_AS_REP(&rep); goto out; } if (rep.u.encKeyPack.length != size) krb5_abortx(context, "Internal ASN.1 encoder error"); /* generate the session key using the method from RFC6112 */ { krb5_keyblock kdc_contribution_key; krb5_crypto reply_crypto; krb5_crypto kdccont_crypto; krb5_data p1 = { strlen("PKINIT"), "PKINIT"}; krb5_data p2 = { strlen("KEYEXCHANGE"), "KEYEXCHANGE"}; void *kckdata; size_t kcklen; EncryptedData kx; void *kxdata; size_t kxlen; ret = krb5_generate_random_keyblock(context, sessionetype, &kdc_contribution_key); if (ret) { free_PA_PK_AS_REP(&rep); goto out; } ret = krb5_crypto_init(context, &cp->reply_key, enctype, &reply_crypto); if (ret) { krb5_free_keyblock_contents(context, &kdc_contribution_key); free_PA_PK_AS_REP(&rep); goto out; } ret = krb5_crypto_init(context, &kdc_contribution_key, sessionetype, &kdccont_crypto); if (ret) { krb5_crypto_destroy(context, reply_crypto); krb5_free_keyblock_contents(context, &kdc_contribution_key); free_PA_PK_AS_REP(&rep); goto out; } /* KRB-FX-CF2 */ ret = krb5_crypto_fx_cf2(context, kdccont_crypto, reply_crypto, &p1, &p2, sessionetype, sessionkey); krb5_crypto_destroy(context, kdccont_crypto); if (ret) { krb5_crypto_destroy(context, reply_crypto); krb5_free_keyblock_contents(context, &kdc_contribution_key); free_PA_PK_AS_REP(&rep); goto out; } ASN1_MALLOC_ENCODE(EncryptionKey, kckdata, kcklen, &kdc_contribution_key, &size, ret); krb5_free_keyblock_contents(context, &kdc_contribution_key); if (ret) { krb5_set_error_message(context, ret, "encoding of PKINIT-KX Key failed %d", ret); krb5_crypto_destroy(context, reply_crypto); free_PA_PK_AS_REP(&rep); goto out; } if (kcklen != size) krb5_abortx(context, "Internal ASN.1 encoder error"); ret = krb5_encrypt_EncryptedData(context, reply_crypto, KRB5_KU_PA_PKINIT_KX, kckdata, kcklen, 0, &kx); krb5_crypto_destroy(context, reply_crypto); free(kckdata); if (ret) { free_PA_PK_AS_REP(&rep); goto out; } ASN1_MALLOC_ENCODE(EncryptedData, kxdata, kxlen, &kx, &size, ret); free_EncryptedData(&kx); if (ret) { krb5_set_error_message(context, ret, "encoding of PKINIT-KX failed %d", ret); free_PA_PK_AS_REP(&rep); goto out; } if (kxlen != size) krb5_abortx(context, "Internal ASN.1 encoder error"); /* Add PA-PKINIT-KX */ ret = krb5_padata_add(context, md, KRB5_PADATA_PKINIT_KX, kxdata, kxlen); if (ret) { krb5_set_error_message(context, ret, "Failed adding PKINIT-KX %d", ret); free(buf); goto out; } } } #define use_btmm_with_enckey 0 if (use_btmm_with_enckey && rep.element == choice_PA_PK_AS_REP_encKeyPack) { PA_PK_AS_REP_BTMM btmm; heim_any any; any.data = rep.u.encKeyPack.data; any.length = rep.u.encKeyPack.length; btmm.dhSignedData = NULL; btmm.encKeyPack = &any; ASN1_MALLOC_ENCODE(PA_PK_AS_REP_BTMM, buf, len, &btmm, &size, ret); } else { ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret); } free_PA_PK_AS_REP(&rep); if (ret) { krb5_set_error_message(context, ret, "encode PA-PK-AS-REP failed %d", ret); goto out; } if (len != size) krb5_abortx(context, "Internal ASN.1 encoder error"); kdc_log(context, config, 0, "PK-INIT using %s %s", type, other); } else if (cp->type == PKINIT_WIN2K) { PA_PK_AS_REP_Win2k rep; ContentInfo info; if (cp->keyex != USE_RSA) { ret = KRB5KRB_ERR_GENERIC; krb5_set_error_message(context, ret, "Windows PK-INIT doesn't support DH"); goto out; } memset(&rep, 0, sizeof(rep)); pa_type = KRB5_PADATA_PK_AS_REP_19; rep.element = choice_PA_PK_AS_REP_Win2k_encKeyPack; ret = krb5_generate_random_keyblock(context, enctype, &cp->reply_key); if (ret) { free_PA_PK_AS_REP_Win2k(&rep); goto out; } ret = pk_mk_pa_reply_enckey(context, config, cp, req, req_buffer, &cp->reply_key, &info, &kdc_cert); if (ret) { free_PA_PK_AS_REP_Win2k(&rep); goto out; } ASN1_MALLOC_ENCODE(ContentInfo, rep.u.encKeyPack.data, rep.u.encKeyPack.length, &info, &size, ret); free_ContentInfo(&info); if (ret) { krb5_set_error_message(context, ret, "encoding of Key ContentInfo " "failed %d", ret); free_PA_PK_AS_REP_Win2k(&rep); goto out; } if (rep.u.encKeyPack.length != size) krb5_abortx(context, "Internal ASN.1 encoder error"); ASN1_MALLOC_ENCODE(PA_PK_AS_REP_Win2k, buf, len, &rep, &size, ret); free_PA_PK_AS_REP_Win2k(&rep); if (ret) { krb5_set_error_message(context, ret, "encode PA-PK-AS-REP-Win2k failed %d", ret); goto out; } if (len != size) krb5_abortx(context, "Internal ASN.1 encoder error"); ret = krb5_generate_random_keyblock(context, sessionetype, sessionkey); if (ret) { free(buf); goto out; } } else krb5_abortx(context, "PK-INIT internal error"); ret = krb5_padata_add(context, md, pa_type, buf, len); if (ret) { krb5_set_error_message(context, ret, "Failed adding PA-PK-AS-REP %d", ret); free(buf); goto out; } if (config->pkinit_kdc_ocsp_file) { if (ocsp.expire == 0 && ocsp.next_update > kdc_time) { struct stat sb; int fd; krb5_data_free(&ocsp.data); ocsp.expire = 0; ocsp.next_update = kdc_time + 60 * 5; fd = open(config->pkinit_kdc_ocsp_file, O_RDONLY); if (fd < 0) { kdc_log(context, config, 0, "PK-INIT failed to open ocsp data file %d", errno); goto out_ocsp; } ret = fstat(fd, &sb); if (ret) { ret = errno; close(fd); kdc_log(context, config, 0, "PK-INIT failed to stat ocsp data %d", ret); goto out_ocsp; } ret = krb5_data_alloc(&ocsp.data, sb.st_size); if (ret) { close(fd); kdc_log(context, config, 0, "PK-INIT failed to stat ocsp data %d", ret); goto out_ocsp; } ocsp.data.length = sb.st_size; ret = read(fd, ocsp.data.data, sb.st_size); close(fd); if (ret != sb.st_size) { kdc_log(context, config, 0, "PK-INIT failed to read ocsp data %d", errno); goto out_ocsp; } ret = hx509_ocsp_verify(context->hx509ctx, kdc_time, kdc_cert, 0, ocsp.data.data, ocsp.data.length, &ocsp.expire); if (ret) { kdc_log(context, config, 0, "PK-INIT failed to verify ocsp data %d", ret); krb5_data_free(&ocsp.data); ocsp.expire = 0; } else if (ocsp.expire > 180) { ocsp.expire -= 180; /* refetch the ocsp before it expire */ ocsp.next_update = ocsp.expire; } else { ocsp.next_update = kdc_time; } out_ocsp: ret = 0; } if (ocsp.expire != 0 && ocsp.expire > kdc_time) { ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PK_OCSP_RESPONSE, ocsp.data.data, ocsp.data.length); if (ret) { krb5_set_error_message(context, ret, "Failed adding OCSP response %d", ret); goto out; } } } out: if (kdc_cert) hx509_cert_free(kdc_cert); if (ret == 0) ret = krb5_copy_keyblock_contents(context, &cp->reply_key, reply_key); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_string_to_key_derived(krb5_context context, const void *str, size_t len, krb5_enctype etype, krb5_keyblock *key) { struct _krb5_encryption_type *et = _krb5_find_enctype(etype); krb5_error_code ret; struct _krb5_key_data kd; size_t keylen; u_char *tmp; if(et == NULL) { krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, N_("encryption type %d not supported", ""), etype); return KRB5_PROG_ETYPE_NOSUPP; } keylen = et->keytype->bits / 8; ALLOC(kd.key, 1); if(kd.key == NULL) { krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size); if(ret) { free(kd.key); return ret; } kd.key->keytype = etype; tmp = malloc (keylen); if(tmp == NULL) { krb5_free_keyblock(context, kd.key); krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } ret = _krb5_n_fold(str, len, tmp, keylen); if (ret) { free(tmp); krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", "")); return ret; } kd.schedule = NULL; _krb5_DES3_random_to_key(context, kd.key, tmp, keylen); memset(tmp, 0, keylen); free(tmp); ret = _krb5_derive_key(context, et, &kd, "kerberos", /* XXX well known constant */ strlen("kerberos")); if (ret) { _krb5_free_key_data(context, &kd, et); return ret; } ret = krb5_copy_keyblock_contents(context, kd.key, key); _krb5_free_key_data(context, &kd, et); return ret; }
/* * Populate the credentials structure corresponding to the ticket we are * printing. */ static int populate_creds(krb5_context context, krb5_principal service_principal, krb5_principal client_principal, krb5_keyblock *session_key, void *tr_in, void *er_in, krb5_creds *creds) { krb5_error_code code; #if USING_HEIMDAL Ticket *ticket_reply; EncTicketPart *enc_tkt_reply; size_t dummy; #else krb5_ticket *ticket_reply; krb5_enc_tkt_part *enc_tkt_reply; krb5_data *temp = NULL; #endif /* Requisite aliasing for Heimdal/MIT support. */ ticket_reply = tr_in; enc_tkt_reply = er_in; code = krb5_copy_principal(context, service_principal, &creds->server); if (code != 0) goto cleanup; code = krb5_copy_principal(context, client_principal, &creds->client); if (code != 0) goto cleanup; code = krb5_copy_keyblock_contents(context, session_key, &deref_session_key(creds)); if (code != 0) goto cleanup; #if USING_HEIMDAL creds->times.authtime = enc_tkt_reply->authtime; creds->times.starttime = *(enc_tkt_reply->starttime); creds->times.endtime = enc_tkt_reply->endtime; creds->times.renew_till = 0; /* *(enc_tkt_reply->renew_till) */ creds->flags.b = enc_tkt_reply->flags; #else creds->times = enc_tkt_reply->times; creds->ticket_flags = enc_tkt_reply->flags; #endif #if USING_HEIMDAL ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, ticket_reply, &dummy, code); if (code != 0 || dummy != creds->ticket.length) goto cleanup; #else code = encode_krb5_ticket(ticket_reply, &temp); if (code != 0) goto cleanup; creds->ticket = *temp; #endif cleanup: #if USING_HEIMDAL /* nothing */ #else free(temp); #endif return code; }
static krb5_error_code client_process(krb5_context kcontext, void *plugin_context, void *request_context, krb5_get_init_creds_opt *opt, preauth_get_client_data_proc client_get_data_proc, struct _krb5_preauth_client_rock *rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *pa_data, krb5_prompter_fct prompter, void *prompter_data, preauth_get_as_key_proc gak_fct, void *gak_data, krb5_data *salt, krb5_data *s2kparams, krb5_keyblock *as_key, krb5_pa_data **out_pa_data) { krb5_pa_data *send_pa; krb5_int32 nnonce, enctype; krb5_keyblock *kb; krb5_error_code status; int *pctx; #ifdef DEBUG fprintf(stderr, "%d bytes of preauthentication data (type %d)\n", pa_data->length, pa_data->pa_type); #endif pctx = plugin_context; if (pctx) { (*pctx)++; } if (pa_data->length == 0) { /* Create preauth data. */ send_pa = malloc(sizeof(krb5_pa_data)); if (send_pa == NULL) return ENOMEM; send_pa->pa_type = KRB5_PADATA_WPSE_REQ; send_pa->length = 4; send_pa->contents = malloc(4); if (send_pa->contents == NULL) { free(send_pa); return ENOMEM; } /* Store the preauth data. */ nnonce = htonl(request->nonce); memcpy(send_pa->contents, &nnonce, 4); *out_pa_data = send_pa; } else { /* A reply from the KDC. Conventionally this would be * indicated by a different preauthentication type, but this * mechanism/implementation doesn't do that. */ if (pa_data->length > 4) { memcpy(&enctype, pa_data->contents, 4); kb = NULL; status = krb5_init_keyblock(kcontext, ntohl(enctype), pa_data->length - 4, &kb); if (status != 0) return status; memcpy(kb->contents, pa_data->contents + 4, pa_data->length - 4); #ifdef DEBUG fprintf(stderr, "Recovered key type=%d, length=%d.\n", kb->enctype, kb->length); #endif status = krb5_copy_keyblock_contents(kcontext, kb, as_key); krb5_free_keyblock(kcontext, kb); return status; } return KRB5KRB_ERR_GENERIC; } return 0; }
/* Create the response for a client. */ static krb5_error_code server_return(krb5_context kcontext, krb5_pa_data *padata, struct _krb5_db_entry_new *client, krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply, struct _krb5_key_data *client_key, krb5_keyblock *encrypting_key, krb5_pa_data **send_pa, preauth_get_entry_data_proc server_get_entry_data, void *pa_module_context, void **pa_request_context) { /* This module does a couple of dumb things. It tags its reply with * the same type as the initial challenge (expecting the client to sort * out whether there's anything useful in there). Oh, and it replaces * the AS reply key with one which is sent in the clear. */ krb5_keyblock *kb; krb5_int32 enctype; int i; *send_pa = NULL; /* We'll want a key with the first supported enctype. */ for (i = 0; i < request->nktypes; i++) { kb = NULL; if (krb5_init_keyblock(kcontext, request->ktype[i], 0, &kb) == 0) { break; } } if (i >= request->nktypes) { /* No matching cipher type found. */ return 0; } /* Randomize a key and save it for the client. */ if (krb5_c_make_random_key(kcontext, request->ktype[i], kb) != 0) { krb5_free_keyblock(kcontext, kb); return 0; } #ifdef DEBUG fprintf(stderr, "Generated random key, type=%d, length=%d.\n", kb->enctype, kb->length); #endif *send_pa = malloc(sizeof(krb5_pa_data)); if (*send_pa == NULL) { krb5_free_keyblock(kcontext, kb); return ENOMEM; } (*send_pa)->pa_type = KRB5_PADATA_WPSE_REQ; (*send_pa)->length = 4 + kb->length; (*send_pa)->contents = malloc(4 + kb->length); if ((*send_pa)->contents == NULL) { free(*send_pa); *send_pa = NULL; krb5_free_keyblock(kcontext, kb); return ENOMEM; } /* Store the preauth data. */ enctype = htonl(kb->enctype); memcpy((*send_pa)->contents, &enctype, 4); memcpy((*send_pa)->contents + 4, kb->contents, kb->length); krb5_free_keyblock_contents(kcontext, encrypting_key); krb5_copy_keyblock_contents(kcontext, kb, encrypting_key); /* Clean up. */ krb5_free_keyblock(kcontext, kb); return 0; }
static krb5_error_code krb5_rd_cred_basic(krb5_context context, krb5_data *pcreddata, krb5_key pkey, krb5_replay_data *replaydata, krb5_creds ***pppcreds) { krb5_error_code retval = 0; krb5_cred * pcred = NULL; krb5_int32 ncreds = 0; krb5_int32 i = 0; krb5_cred_enc_part encpart; /* decode cred message */ if ((retval = decode_krb5_cred(pcreddata, &pcred))) return retval; memset(&encpart, 0, sizeof(encpart)); if ((retval = decrypt_credencdata(context, pcred, pkey, &encpart))) goto cleanup_cred; replaydata->timestamp = encpart.timestamp; replaydata->usec = encpart.usec; replaydata->seq = encpart.nonce; /* * Allocate the list of creds. The memory is allocated so that * krb5_free_tgt_creds can be used to free the list. */ for (ncreds = 0; pcred->tickets[ncreds]; ncreds++); if ((*pppcreds = (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) * (ncreds + 1)))) == NULL) { retval = ENOMEM; goto cleanup_cred; } (*pppcreds)[0] = NULL; /* * For each credential, create a strcture in the list of * credentials and copy the information. */ while (i < ncreds) { krb5_cred_info * pinfo; krb5_creds * pcur; krb5_data * pdata; if ((pcur = (krb5_creds *)calloc(1, sizeof(krb5_creds))) == NULL) { retval = ENOMEM; goto cleanup; } (*pppcreds)[i] = pcur; (*pppcreds)[i+1] = 0; pinfo = encpart.ticket_info[i++]; if ((retval = krb5_copy_principal(context, pinfo->client, &pcur->client))) goto cleanup; if ((retval = krb5_copy_principal(context, pinfo->server, &pcur->server))) goto cleanup; if ((retval = krb5_copy_keyblock_contents(context, pinfo->session, &pcur->keyblock))) goto cleanup; if ((retval = krb5_copy_addresses(context, pinfo->caddrs, &pcur->addresses))) goto cleanup; if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata))) goto cleanup; pcur->ticket = *pdata; free(pdata); pcur->is_skey = FALSE; pcur->magic = KV5M_CREDS; pcur->times = pinfo->times; pcur->ticket_flags = pinfo->flags; pcur->authdata = NULL; /* not used */ memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket)); } /* * NULL terminate the list */ (*pppcreds)[i] = NULL; cleanup: if (retval) { krb5_free_tgt_creds(context, *pppcreds); *pppcreds = NULL; } cleanup_cred: krb5_free_cred(context, pcred); krb5_free_cred_enc_part(context, &encpart); return retval; }
static krb5_error_code KRB5_CALLCONV hdb_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal principal, krb5_kvno kvno, krb5_enctype enctype, krb5_keytab_entry *entry) { hdb_entry_ex ent; krb5_error_code ret; struct hdb_data *d = id->data; const char *dbname = d->dbname; const char *mkey = d->mkey; char *fdbname = NULL, *fmkey = NULL; HDB *db; int i; memset(&ent, 0, sizeof(ent)); if (dbname == NULL) { ret = find_db(context, &fdbname, &fmkey, principal); if (ret) return ret; dbname = fdbname; mkey = fmkey; } ret = hdb_create (context, &db, dbname); if (ret) goto out2; ret = hdb_set_master_keyfile (context, db, mkey); if (ret) { (*db->hdb_destroy)(context, db); goto out2; } ret = (*db->hdb_open)(context, db, O_RDONLY, 0); if (ret) { (*db->hdb_destroy)(context, db); goto out2; } ret = (*db->hdb_fetch_kvno)(context, db, principal, HDB_F_DECRYPT|HDB_F_KVNO_SPECIFIED| HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, kvno, &ent); if(ret == HDB_ERR_NOENTRY) { ret = KRB5_KT_NOTFOUND; goto out; }else if(ret) goto out; if(kvno && ent.entry.kvno != kvno) { hdb_free_entry(context, &ent); ret = KRB5_KT_NOTFOUND; goto out; } if(enctype == 0) if(ent.entry.keys.len > 0) enctype = ent.entry.keys.val[0].key.keytype; ret = KRB5_KT_NOTFOUND; for(i = 0; i < ent.entry.keys.len; i++) { if(ent.entry.keys.val[i].key.keytype == enctype) { krb5_copy_principal(context, principal, &entry->principal); entry->vno = ent.entry.kvno; krb5_copy_keyblock_contents(context, &ent.entry.keys.val[i].key, &entry->keyblock); ret = 0; break; } } hdb_free_entry(context, &ent); out: (*db->hdb_close)(context, db); (*db->hdb_destroy)(context, db); out2: free(fdbname); free(fmkey); return ret; }
kadm5_ret_t _kadm5_set_keys_randomly (kadm5_server_context *context, hdb_entry *ent, krb5_keyblock **new_keys, int *n_keys) { krb5_keyblock *kblock = NULL; kadm5_ret_t ret = 0; int i, des_keyblock; size_t num_keys; Key *keys; ret = hdb_generate_key_set(context->context, ent->principal, &keys, &num_keys, 1); if (ret) return ret; kblock = malloc(num_keys * sizeof(kblock[0])); if (kblock == NULL) { ret = ENOMEM; _kadm5_free_keys (context->context, num_keys, keys); return ret; } memset(kblock, 0, num_keys * sizeof(kblock[0])); des_keyblock = -1; for (i = 0; i < num_keys; i++) { /* * To make sure all des keys are the the same we generate only * the first one and then copy key to all other des keys. */ if (des_keyblock != -1 && is_des_key_p(keys[i].key.keytype)) { ret = krb5_copy_keyblock_contents (context->context, &kblock[des_keyblock], &kblock[i]); if (ret) goto out; kblock[i].keytype = keys[i].key.keytype; } else { ret = krb5_generate_random_keyblock (context->context, keys[i].key.keytype, &kblock[i]); if (ret) goto out; if (is_des_key_p(keys[i].key.keytype)) des_keyblock = i; } ret = krb5_copy_keyblock_contents (context->context, &kblock[i], &keys[i].key); if (ret) goto out; } out: if(ret) { for (i = 0; i < num_keys; ++i) krb5_free_keyblock_contents (context->context, &kblock[i]); free(kblock); _kadm5_free_keys (context->context, num_keys, keys); return ret; } _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); ent->keys.val = keys; ent->keys.len = num_keys; *new_keys = kblock; *n_keys = num_keys; hdb_entry_set_pw_change_time(context->context, ent, 0); hdb_entry_clear_password(context->context, ent); return 0; }
static int KRB5_CALLCONV hdb_next_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor) { struct hdb_cursor *c = cursor->data; krb5_error_code ret; memset(entry, 0, sizeof(*entry)); if (c->first) { c->first = FALSE; ret = (c->db->hdb_firstkey)(context, c->db, HDB_F_DECRYPT| HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, &c->hdb_entry); if (ret == HDB_ERR_NOENTRY) return KRB5_KT_END; else if (ret) return ret; if (c->hdb_entry.entry.keys.len == 0) hdb_free_entry(context, &c->hdb_entry); else c->next = FALSE; } while (c->next) { ret = (c->db->hdb_nextkey)(context, c->db, HDB_F_DECRYPT| HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, &c->hdb_entry); if (ret == HDB_ERR_NOENTRY) return KRB5_KT_END; else if (ret) return ret; /* If no keys on this entry, try again */ if (c->hdb_entry.entry.keys.len == 0) hdb_free_entry(context, &c->hdb_entry); else c->next = FALSE; } /* * Return next enc type (keytabs are one slot per key, while * hdb is one record per principal. */ ret = krb5_copy_principal(context, c->hdb_entry.entry.principal, &entry->principal); if (ret) return ret; entry->vno = c->hdb_entry.entry.kvno; ret = krb5_copy_keyblock_contents(context, &c->hdb_entry.entry.keys.val[c->key_idx].key, &entry->keyblock); if (ret) { krb5_free_principal(context, entry->principal); memset(entry, 0, sizeof(*entry)); return ret; } c->key_idx++; /* * Once we get to the end of the list, signal that we want the * next entry */ if (c->key_idx == c->hdb_entry.entry.keys.len) { hdb_free_entry(context, &c->hdb_entry); c->next = TRUE; c->key_idx = 0; } return 0; }
static krb5_error_code kdcrep2creds(krb5_context context, krb5_kdc_rep *pkdcrep, krb5_address *const *address, krb5_data *psectkt, krb5_creds **ppcreds) { krb5_error_code retval; krb5_data *pdata; if ((*ppcreds = (krb5_creds *)calloc(1,sizeof(krb5_creds))) == NULL) { return ENOMEM; } if ((retval = krb5_copy_principal(context, pkdcrep->client, &(*ppcreds)->client))) goto cleanup; if ((retval = krb5_copy_principal(context, pkdcrep->enc_part2->server, &(*ppcreds)->server))) goto cleanup; if ((retval = krb5_copy_keyblock_contents(context, pkdcrep->enc_part2->session, &(*ppcreds)->keyblock))) goto cleanup; TRACE_TGS_REPLY(context, (*ppcreds)->client, (*ppcreds)->server, &(*ppcreds)->keyblock); if ((retval = krb5_copy_data(context, psectkt, &pdata))) goto cleanup_keyblock; (*ppcreds)->second_ticket = *pdata; free(pdata); (*ppcreds)->ticket_flags = pkdcrep->enc_part2->flags; (*ppcreds)->times = pkdcrep->enc_part2->times; (*ppcreds)->magic = KV5M_CREDS; (*ppcreds)->authdata = NULL; /* not used */ (*ppcreds)->is_skey = psectkt->length != 0; if (pkdcrep->enc_part2->caddrs) { if ((retval = krb5_copy_addresses(context, pkdcrep->enc_part2->caddrs, &(*ppcreds)->addresses))) goto cleanup_keyblock; } else { /* no addresses in the list means we got what we had */ if ((retval = krb5_copy_addresses(context, address, &(*ppcreds)->addresses))) goto cleanup_keyblock; } if ((retval = encode_krb5_ticket(pkdcrep->ticket, &pdata))) goto cleanup_keyblock; (*ppcreds)->ticket = *pdata; free(pdata); return 0; cleanup_keyblock: krb5_free_keyblock_contents(context, &(*ppcreds)->keyblock); cleanup: free (*ppcreds); *ppcreds = NULL; return retval; }