From 4bc18b8d9dc28ab51e1eb52891ed3f72cd86fdda Mon Sep 17 00:00:00 2001 From: Theodore Tso Date: Wed, 8 Nov 1995 08:03:31 +0000 Subject: [PATCH] * kdc_util.c (): Added new helper functions dbentry_has_key_for_enctype(), dbentry_supports_enctype(), and select_session_keytype(). * kdc_preauth.c: Added support for the ENC_TIMESTAMP preauthentication scheme. * do_tgs_req.c (process_tgs_req): Fixed the keytype/enctype selection criteria for the server key, and the ticket session key. * do_as_req.c (process_as_req): Added calls to the kdc preauthentication verification routines. Fixed the keytype/enctype selection criteria for the client key, the server key, and the ticket session key. * main.c (finish_realm): Make sure all parts of the realm structure are freed properly. (main): Free the kcontext krb5_context. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@7058 dc483132-0cff-0310-8789-dd5450dbe970 --- src/kdc/ChangeLog | 22 +++++ src/kdc/do_as_req.c | 137 +++++++++------------------- src/kdc/do_tgs_req.c | 176 ++++++++++++++++++----------------- src/kdc/kdc_preauth.c | 207 ++++++++++++++++++++++++++++++++++++++---- src/kdc/kdc_util.c | 88 ++++++++++++++++++ src/kdc/kdc_util.h | 16 ++++ src/kdc/main.c | 16 +++- 7 files changed, 467 insertions(+), 195 deletions(-) diff --git a/src/kdc/ChangeLog b/src/kdc/ChangeLog index 741224227..dbb44172b 100644 --- a/src/kdc/ChangeLog +++ b/src/kdc/ChangeLog @@ -1,3 +1,25 @@ +Wed Nov 8 02:57:15 1995 Theodore Y. Ts'o + + * kdc_util.c (): Added new helper functions + dbentry_has_key_for_enctype(), dbentry_supports_enctype(), + and select_session_keytype(). + + * kdc_preauth.c: Added support for the ENC_TIMESTAMP + preauthentication scheme. + + * do_tgs_req.c (process_tgs_req): Fixed the keytype/enctype + selection criteria for the server key, and the ticket + session key. + + * do_as_req.c (process_as_req): Added calls to the kdc + preauthentication verification routines. Fixed the + keytype/enctype selection criteria for the client key, the + server key, and the ticket session key. + + * main.c (finish_realm): Make sure all parts of the realm + structure are freed properly. + (main): Free the kcontext krb5_context. + Fri Oct 6 00:07:49 1995 Theodore Y. Ts'o * kdc_preauth.c (get_preauth_hint_list): Fix missing indirection diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c index eef36e763..ad9b10c22 100644 --- a/src/kdc/do_as_req.c +++ b/src/kdc/do_as_req.c @@ -46,49 +46,6 @@ static krb5_error_code prepare_error_as PROTOTYPE((krb5_kdc_req *, int, krb5_data *, krb5_data **)); -/* - * This routine is called to verify the preauthentication information - * for a V5 request. Client contains information about the principal - * from the database. Padata contains pre-auth info received from - * the network. - * - * Returns 0 if the pre-authentication is valid, non-zero to indicate - * an error code of some sort. - */ - -static krb5_error_code -check_padata (client, src_addr, padata, pa_id, flags) - krb5_db_entry *client; - krb5_address **src_addr; - krb5_pa_data **padata; - int *pa_id; /* Unique id which can be used for replay - of padata. */ - int *flags; -{ - krb5_error_code retval; - krb5_keyblock tmpkey; - int i; - - /* Extract a client key from master key */ - retval = 0; - for (i = 0; i < client->n_key_data; i++) { - if ((retval = krb5_dbekd_decrypt_key_data(kdc_context, - &master_encblock, - &client->key_data[i], - &tmpkey, NULL))) { - krb5_klog_syslog(LOG_ERR,"AS_REQ: Unable to extract client key: %s", - error_message(retval)); - return retval; - } - retval = krb5_verify_padata(kdc_context, *padata, client->princ, - src_addr, &tmpkey, pa_id, flags); - memset((char *)tmpkey.contents, 0, tmpkey.length); - krb5_xfree(tmpkey.contents); - if (!retval) - break; - } - return retval; -} /*ARGSUSED*/ krb5_error_code @@ -205,33 +162,18 @@ krb5_data **response; /* filled in with a response packet */ goto errout; } - for (i = 0; i < request->nktypes; i++) { - if (!valid_enctype(request->ktype[i])) - continue; - - if (request->ktype[i] == ENCTYPE_DES_CBC_MD5 && - !isflagset(server.attributes, KRB5_KDB_SUPPORT_DESMD5)) - continue; - - /* - * Find the server key of the appropriate type. If we could specify - * a kvno, it would be supplied here. - */ - if (!krb5_dbe_find_enctype(kdc_context, &server, request->ktype[i], - -1, /* Ignore salttype */ - -1, /* Get highest kvno */ - &server_key)) - goto got_a_key; + /* + * Select the keytype for the ticket session key. + */ + if ((useenctype = select_session_keytype(kdc_context, &server, + request->nktypes, + request->ktype)) == 0) { + /* unsupported ktype */ + status = "BAD_ENCRYPTION_TYPE"; + errcode = KRB5KDC_ERR_ETYPE_NOSUPP; + goto errout; } - - /* unsupported ktype */ - status = "BAD_ENCRYPTION_TYPE"; - errcode = KRB5KDC_ERR_ETYPE_NOSUPP; - goto errout; - -got_a_key:; - useenctype = request->ktype[i]; - krb5_use_enctype(kdc_context, &eblock, request->ktype[i]); + krb5_use_enctype(kdc_context, &eblock, useenctype); if ((errcode = krb5_random_key(kdc_context, &eblock, krb5_enctype_array[useenctype]->random_sequence, @@ -318,8 +260,7 @@ got_a_key:; * Check the preauthentication if it is there. */ if (request->padata) { - errcode = check_padata(&client,request->addresses, - request->padata, &pa_id, &pa_flags); + errcode = check_padata(kdc_context, &client, request, &enc_tkt_reply); if (errcode) { #ifdef KRBCONF_KDC_MODIFIES_KDB /* @@ -342,13 +283,6 @@ got_a_key:; #endif goto errout; } - setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH); - /* - * If pa_type is one in which additional hardware authentication - * was performed set TKT_FLG_HW_AUTH too. - */ - if (pa_flags & KRB5_PREAUTH_FLAGS_HARDWARE) - setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH); } /* @@ -365,16 +299,31 @@ got_a_key:; ticket_reply.enc_part2 = &enc_tkt_reply; + /* + * Find the server key + */ + if ((errcode = krb5_dbe_find_enctype(kdc_context, &server, + -1, /* ignore keytype */ + -1, /* Ignore salttype */ + 0, /* Get highest kvno */ + &server_key))) { + status = "FINDING_SERVER_KEY"; + goto errout; + } + /* convert server.key into a real key (it may be encrypted in the database) */ if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock, - server_key, - &encrypting_key, NULL))) { + server_key, &encrypting_key, + NULL))) { status = "DECRYPT_SERVER_KEY"; goto errout; } - errcode = krb5_encrypt_tkt_part(kdc_context, &eblock, &encrypting_key, - &ticket_reply); + if ((encrypting_key.enctype == ENCTYPE_DES_CBC_CRC) && + (isflagset(server.attributes, KRB5_KDB_SUPPORT_DESMD5))) + encrypting_key.enctype = ENCTYPE_DES_CBC_MD5; + + errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key, &ticket_reply); memset((char *)encrypting_key.contents, 0, encrypting_key.length); krb5_xfree(encrypting_key.contents); if (errcode) { @@ -385,19 +334,16 @@ got_a_key:; /* * Find the appropriate client key. We search in the order specified - * by the key/salt list. + * by request keytype list. */ client_key = (krb5_key_data *) NULL; - for (i=0; irealm_nkstypes; i++) { - krb5_key_salt_tuple *kslist; - - kslist = (krb5_key_salt_tuple *) kdc_active_realm->realm_kstypes; - if (!krb5_dbe_find_enctype(kdc_context, - &client, - kslist[i].ks_enctype, - kslist[i].ks_salttype, - -1, - &client_key)) + for (i = 0; i < request->nktypes; i++) { + useenctype = request->ktype[i]; + if (!valid_enctype(useenctype)) + continue; + + if (!krb5_dbe_find_enctype(kdc_context, &client, useenctype, -1, + 0, &client_key)) break; } if (!(client_key)) { @@ -486,11 +432,12 @@ got_a_key:; /* convert client.key_data into a real key */ if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock, - client_key, - &encrypting_key, NULL))) { + client_key, &encrypting_key, + NULL))) { status = "DECRYPT_CLIENT_KEY"; goto errout; } + encrypting_key.enctype = useenctype; errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart, &eblock, &encrypting_key, &reply, response); diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c index feb72ef84..33aa25a3e 100644 --- a/src/kdc/do_tgs_req.c +++ b/src/kdc/do_tgs_req.c @@ -63,7 +63,6 @@ krb5_data **response; /* filled in with a response packet */ { krb5_keyblock * subkey; krb5_encrypt_block eblock; - krb5_enctype second_ticket_ktype = ENCTYPE_UNKNOWN; krb5_kdc_req *request = 0; krb5_db_entry server; krb5_kdc_rep reply; @@ -80,6 +79,7 @@ krb5_data **response; /* filled in with a response packet */ krb5_keyblock *session_key = 0; krb5_timestamp until, rtime; krb5_keyblock encrypting_key; + krb5_key_data *server_key; char *cname = 0, *sname = 0, *tmp = 0, *fromstring = 0; krb5_last_req_entry *nolrarray[2], nolrentry; /* krb5_address *noaddrarray[1]; */ @@ -87,7 +87,6 @@ krb5_data **response; /* filled in with a response packet */ int errcode, errcode2; register int i; int firstpass = 1; - int ok_key_data = 0; const char *status = 0; retval = decode_krb5_tgs_req(pkt, &request); @@ -181,7 +180,7 @@ tgt_again: goto cleanup; } - if ((retval = krb5_timeofday(kdc_context, &kdc_time))) { + if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) { status = "TIME_OF_DAY"; goto cleanup; } @@ -195,48 +194,72 @@ tgt_again: } /* - * If we are using user-to-user authentication, then the resulting - * ticket has to use the same encryption system as was used to - * encrypt the ticket, since that's the same encryption system - * that's used for the ticket session key --- and that's what we - * use to encrypt the ticket! + * We pick the session keytype here.... + * + * Some special care needs to be taken in the user-to-user + * case, since we don't know what keytypes the application server + * which is doing user-to-user authentication can support. We + * know that it at least must be able to support the encryption + * type of the session key in the TGT, since otherwise it won't be + * able to decrypt the U2U ticket! So we use that in preference + * to anything else. */ - if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) - second_ticket_ktype = request->second_ticket[st_idx]->enc_part.enctype; - - for (i = 0; i < request->nktypes; i++) { - krb5_enctype ok_enctype; - - if (!valid_enctype(request->ktype[i])) - continue; - - if (second_ticket_ktype != ENCTYPE_UNKNOWN && - second_ticket_ktype != request->ktype[i]) - continue; - - if (request->ktype[i] == ENCTYPE_DES_CBC_MD5 && - !isflagset(server.attributes, KRB5_KDB_SUPPORT_DESMD5)) - continue; + useenctype = 0; + if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) { + krb5_keyblock * st_sealing_key; + krb5_kvno st_srv_kvno; + krb5_enctype etype; - ok_enctype = request->ktype[i]; + /* + * Get the key for the second ticket, and decrypt it. + */ + if ((errcode = kdc_get_server_key(request->second_ticket[st_idx], + &st_sealing_key, + &st_srv_kvno))) { + status = "2ND_TKT_SERVER"; + goto cleanup; + } + errcode = krb5_decrypt_tkt_part(kdc_context, st_sealing_key, + request->second_ticket[st_idx]); + krb5_free_keyblock(kdc_context, st_sealing_key); + if (errcode) { + status = "2ND_TKT_DECRYPT"; + goto cleanup; + } + + etype = request->second_ticket[st_idx]->enc_part2->session->enctype; + if (!valid_enctype(etype)) { + status = "BAD_ETYPE_IN_2ND_TKT"; + errcode = KRB5KDC_ERR_ETYPE_NOSUPP; + goto cleanup; + } + + for (i = 0; i < request->nktypes; i++) { + if (request->ktype[i] == etype) { + useenctype = etype; + break; + } + } + } - for (ok_key_data = 0; ok_key_data < server.n_key_data; ok_key_data++) - if (server.key_data[ok_key_data].key_data_type[0] == ok_enctype) - goto got_a_key; + /* + * Select the keytype for the ticket session key. + */ + if ((useenctype == 0) && + (useenctype = select_session_keytype(kdc_context, &server, + request->nktypes, + request->ktype)) == 0) { + /* unsupported ktype */ + status = "BAD_ENCRYPTION_TYPE"; + errcode = KRB5KDC_ERR_ETYPE_NOSUPP; + goto cleanup; } - /* unsupported ktype */ - errcode = KRB5KDC_ERR_ETYPE_NOSUPP; - status = "BAD_ENCRYPTION_TYPE"; - goto cleanup; - -got_a_key:; - useenctype = request->ktype[i]; krb5_use_enctype(kdc_context, &eblock, useenctype); - retval = krb5_random_key(kdc_context, &eblock, + errcode = krb5_random_key(kdc_context, &eblock, krb5_enctype_array[useenctype]->random_sequence, &session_key); - if (retval) { + if (errcode) { /* random key failed */ status = "RANDOM_KEY_FAILED"; goto cleanup; @@ -399,7 +422,7 @@ got_a_key:; goto cleanup; } /* do any necessary key pre-processing */ - if ((retval = krb5_process_key(kdc_context, &eblock, + if ((errcode = krb5_process_key(kdc_context, &eblock, header_ticket->enc_part2->session))) { status = "AUTH_PROCESS_KEY"; free(scratch.data); @@ -407,7 +430,7 @@ got_a_key:; } /* call the encryption routine */ - if ((retval = krb5_decrypt(kdc_context, (krb5_pointer) request->authorization_data.ciphertext.data, + if ((errcode = krb5_decrypt(kdc_context, (krb5_pointer) request->authorization_data.ciphertext.data, (krb5_pointer) scratch.data, scratch.length, &eblock, 0))) { status = "AUTH_ENCRYPT_FAIL"; @@ -415,20 +438,20 @@ got_a_key:; free(scratch.data); goto cleanup; } - if ((retval = krb5_finish_key(kdc_context, &eblock))) { + if ((errcode = krb5_finish_key(kdc_context, &eblock))) { status = "AUTH_FINISH_KEY"; free(scratch.data); goto cleanup; } /* scratch now has the authorization data, so we decode it */ - retval = decode_krb5_authdata(&scratch, &(request->unenc_authdata)); + errcode = decode_krb5_authdata(&scratch, &(request->unenc_authdata)); free(scratch.data); - if (retval) { + if (errcode) { status = "AUTH_DECODE"; goto cleanup; } - if ((retval = + if ((errcode = concat_authorization_data(request->unenc_authdata, header_ticket->enc_part2->authorization_data, &enc_tkt_reply.authorization_data))) { @@ -470,7 +493,7 @@ got_a_key:; enc_tkt_transited.tr_contents.data = 0; enc_tkt_transited.tr_contents.length = 0; enc_tkt_reply.transited = enc_tkt_transited; - if ((retval = + if ((errcode = add_to_transited(&header_ticket->enc_part2->transited.tr_contents, &enc_tkt_reply.transited.tr_contents, header_ticket->server, @@ -491,32 +514,13 @@ got_a_key:; * the second ticket. */ if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) { - krb5_keyblock *st_sealing_key; - krb5_kvno st_srv_kvno; - - if ((retval = kdc_get_server_key(request->second_ticket[st_idx], - &st_sealing_key, - &st_srv_kvno))) { - status = "2ND_TKT_SERVER"; - goto cleanup; - } - - /* decrypt the ticket */ - retval = krb5_decrypt_tkt_part(kdc_context, st_sealing_key, - request->second_ticket[st_idx]); - krb5_free_keyblock(kdc_context, st_sealing_key); - if (retval) { - status = "2ND_TKT_DECRYPT"; - goto cleanup; - } - /* * Make sure the client for the second ticket matches * requested server. */ if (!krb5_principal_compare(kdc_context, request->server, request->second_ticket[st_idx]->enc_part2->client)) { - if ((retval = krb5_unparse_name(kdc_context, + if ((errcode = krb5_unparse_name(kdc_context, request->second_ticket[st_idx]->enc_part2->client, &tmp))) tmp = 0; @@ -530,7 +534,7 @@ got_a_key:; ticket_reply.enc_part.enctype = request->second_ticket[st_idx]->enc_part2->session->enctype; krb5_use_enctype(kdc_context, &eblock, ticket_reply.enc_part.enctype); - if ((retval = krb5_encrypt_tkt_part(kdc_context, &eblock, + if ((errcode = krb5_encrypt_tkt_part(kdc_context, request->second_ticket[st_idx]->enc_part2->session, &ticket_reply))) { status = "2ND_TKT_ENCRYPT"; @@ -538,25 +542,35 @@ got_a_key:; } st_idx++; } else { + /* + * Find the server key + */ + if ((errcode = krb5_dbe_find_enctype(kdc_context, &server, + -1, /* ignore keytype */ + -1, /* Ignore salttype */ + 0, /* Get highest kvno */ + &server_key))) { + status = "FINDING_SERVER_KEY"; + goto cleanup; + } /* convert server.key into a real key (it may be encrypted - in the database) */ - if ((retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock, - &server.key_data[ok_key_data], - &encrypting_key, NULL))) { - status = "CONV_KEY"; + * in the database) */ + if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, + &master_encblock, + server_key, &encrypting_key, + NULL))) { + status = "DECRYPT_SERVER_KEY"; goto cleanup; } - - ticket_reply.enc_part.kvno = server.key_data[ok_key_data].key_data_kvno; - ticket_reply.enc_part.enctype = useenctype; - krb5_use_enctype(kdc_context, &eblock, ticket_reply.enc_part.enctype); - retval = krb5_encrypt_tkt_part(kdc_context, &eblock, &encrypting_key, - &ticket_reply); - + if ((encrypting_key.enctype == ENCTYPE_DES_CBC_CRC) && + (isflagset(server.attributes, KRB5_KDB_SUPPORT_DESMD5))) + encrypting_key.enctype = ENCTYPE_DES_CBC_MD5; + ticket_reply.enc_part.kvno = server_key->key_data_kvno; + errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key, + &ticket_reply); memset((char *)encrypting_key.contents, 0, encrypting_key.length); krb5_xfree(encrypting_key.contents); - - if (retval) { + if (errcode) { status = "TKT_ENCRYPT"; goto cleanup; } @@ -598,11 +612,11 @@ got_a_key:; header_ticket->enc_part2->session->enctype; krb5_use_enctype(kdc_context, &eblock, reply.enc_part.enctype); - retval = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart, + errcode = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart, &eblock, subkey ? subkey : header_ticket->enc_part2->session, &reply, response); - if (retval) { + if (errcode) { status = "ENCODE_KDC_REP"; } else { status = "ISSUE"; diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index dab3d7913..5670625cf 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -29,13 +29,12 @@ #include typedef krb5_error_code (verify_proc) - KRB5_PROTOTYPE((krb5_context, krb5_principal client, - krb5_address **src_addr, - krb5_data *data)); + KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client, + krb5_kdc_req *request, + krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data)); typedef krb5_error_code (edata_proc) - KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client, - krb5_pa_data *data)); + KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client, krb5_pa_data *data)); typedef struct _krb5_preauth_systems { int type; @@ -44,30 +43,81 @@ typedef struct _krb5_preauth_systems { verify_proc *verify; } krb5_preauth_systems; +static verify_proc verify_enc_timestamp; + /* * Preauth property flags */ -#define PA_ENCRYPT 0x00000001 -#define PA_HARDWARE 0x00000002 +#define PA_HARDWARE 0x00000001 +#define PA_REQUIRED 0x00000002 +#define PA_SUFFICIENT 0x00000004 static krb5_preauth_systems preauth_systems[] = { { - KRB5_PADATA_ENC_UNIX_TIME, - PA_ENCRYPT, + KRB5_PADATA_ENC_TIMESTAMP, 0, - 0, - }, - { - KRB5_PADATA_ENC_SANDIA_SECURID, - PA_ENCRYPT | PA_HARDWARE, - 0, - 0, + 0, + verify_enc_timestamp, }, { -1,} }; #define MAX_PREAUTH_SYSTEMS (sizeof(preauth_systems)/sizeof(preauth_systems[0])) +static krb5_error_code +find_pa_system(type, preauth) + int type; + krb5_preauth_systems **preauth; +{ + krb5_preauth_systems *ap = preauth_systems; + + while ((ap->type != -1) && (ap->type != type)) + ap++; + if (ap->type == -1) + return(KRB5_PREAUTH_BAD_TYPE); + *preauth = ap; + return 0; +} + +krb5_error_code +krb5_decrypt_data(context, key, ivec, enc_data, data) + krb5_context context; + krb5_keyblock * key; + krb5_pointer ivec; + krb5_enc_data * enc_data; + krb5_data * data; +{ + krb5_error_code retval; + krb5_encrypt_block eblock; + + krb5_use_enctype(context, &eblock, key->enctype); + data->length = enc_data->ciphertext.length; + if (!(data->data = malloc(data->length))) + return ENOMEM; + + if ((retval = krb5_process_key(context, &eblock, key)) != 0) + goto cleanup; + + if ((retval = krb5_decrypt(context, + (krb5_pointer) enc_data->ciphertext.data, + (krb5_pointer) data->data, + enc_data->ciphertext.length, &eblock, ivec))) { + krb5_finish_key(context, &eblock); + goto cleanup; + } + (void) krb5_finish_key(context, &eblock); + + return 0; + +cleanup: + if (data->data) { + free(data->data); + data->data = 0; + } + return retval; +} + + const char *missing_required_preauth(client, server, enc_tkt_reply) krb5_db_entry *client, *server; krb5_enc_tkt_part *enc_tkt_reply; @@ -142,5 +192,128 @@ errout: return; } +/* + * This routine is called to verify the preauthentication information + * for a V5 request. + * + * Returns 0 if the pre-authentication is valid, non-zero to indicate + * an error code of some sort. + */ + +krb5_error_code +check_padata (context, client, request, enc_tkt_reply) + krb5_context context; + krb5_db_entry * client; + krb5_kdc_req * request; + krb5_enc_tkt_part * enc_tkt_reply; +{ + krb5_error_code retval; + krb5_pa_data **padata; + krb5_preauth_systems *pa_sys; + + if (request->padata == 0) + return 0; + + for (padata = request->padata; *padata; padata++) { + if (find_pa_system((*padata)->pa_type, &pa_sys)) + continue; + if (pa_sys->verify == 0) + continue; + retval = pa_sys->verify(context, client, request, + enc_tkt_reply, *padata); + if (retval) { + if (pa_sys->flags & PA_REQUIRED) + break; + } else { + if (pa_sys->flags & PA_SUFFICIENT) + break; + } + } + return retval; +} + +static krb5_error_code +verify_enc_timestamp(context, client, request, enc_tkt_reply, pa) + krb5_context context; + krb5_db_entry * client; + krb5_kdc_req * request; + krb5_enc_tkt_part * enc_tkt_reply; + krb5_pa_data * pa; +{ + krb5_pa_enc_ts * pa_enc = 0; + krb5_error_code retval; + krb5_data scratch; + krb5_data enc_ts_data; + krb5_enc_data *enc_data = 0; + krb5_keyblock key; + krb5_key_data * client_key; + krb5_int32 start; + krb5_timestamp timenow; + + enc_ts_data.data = 0; + scratch.data = pa->contents; + scratch.length = pa->length; + + if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0) + goto cleanup; + + start = 0; + while (1) { + if ((retval = krb5_dbe_search_enctype(context, client, + &start, enc_data->enctype, + -1, 0, &client_key))) + goto cleanup; + + if ((retval = krb5_dbekd_decrypt_key_data(context, &master_encblock, + client_key, &key, NULL))) + goto cleanup; + key.enctype = enc_data->enctype; + + retval = krb5_decrypt_data(context, key, 0, enc_data, &enc_ts_data); + memset((char *)key.contents, 0, key.length); + krb5_xfree(key.contents); + + if (retval == 0) + break; + } + + if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0) + goto cleanup; + + if ((retval = krb5_timeofday(context, &timenow)) != 0) + goto cleanup; + + if (labs(timenow - pa_enc->patimestamp) > context->clockskew) { + retval = KRB5KRB_AP_ERR_SKEW; + goto cleanup; + } + + setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH); + + retval = 0; + +cleanup: + if (enc_data) { + if (enc_data->ciphertext.data) + krb5_xfree(enc_data->ciphertext.data); + free(enc_data); + } + if (enc_ts_data.data) + krb5_xfree(enc_ts_data.data); + if (pa_enc) + krb5_xfree(pa_enc); + return retval; +} + - +#if 0 + + setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH); + /* + * If pa_type is one in which additional hardware authentication + * was performed set TKT_FLG_HW_AUTH too. + */ + if (pa_flags & KRB5_PREAUTH_FLAGS_HARDWARE) + setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH); + +#endif diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index 32f398354..49573bf95 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -1229,3 +1229,91 @@ const char **status; return 0; } + +/* + * This function returns 1 if the dbentry has a key for a specified + * keytype, and 0 if not. + */ +int +dbentry_has_key_for_enctype(context, client, enctype) + krb5_context context; + krb5_db_entry * client; + krb5_enctype enctype; +{ + krb5_error_code retval; + krb5_key_data *datap; + + retval = krb5_dbe_find_enctype(context, client, enctype, + -1, 0, &datap); + if (retval) + return 0; + else + return 1; +} + +/* + * This function returns 1 if the entity referenced by this + * structure can support the a particular encryption system, and 0 if + * not. + * + * XXX eventually this information should be looked up in the + * database. Since it isn't, we use some hueristics and attribute + * options bits for now. + */ +int +dbentry_supports_enctype(context, client, enctype) + krb5_context context; + krb5_db_entry * client; + krb5_enctype enctype; +{ + /* + * If it's DES_CBC_MD5, there's a bit in the attribute mask which + * checks to see if we support it. + * + * In theory everything's supposed to support DES_CBC_MD5, but + * that's not the reality.... + */ + if (enctype == ENCTYPE_DES_CBC_MD5) + return isflagset(client->attributes, KRB5_KDB_SUPPORT_DESMD5); + + /* + * XXX we assume everything can understand DES_CBC_CRC + */ + if (enctype == ENCTYPE_DES_CBC_CRC) + return 1; + + /* + * If we have a key for the encryption system, we assume it's + * supported. + */ + return dbentry_has_key_for_enctype(context, client, enctype); +} + +/* + * This function returns the keytype which should be selected for the + * session key. It is based on the ordered list which the user + * requested, and what the KDC and the application server can support. + */ +krb5_enctype +select_session_keytype(context, server, nktypes, ktype) + krb5_context context; + krb5_db_entry * server; + int nktypes; + krb5_enctype *ktype; +{ + int i; + + for (i = 0; i < nktypes; i++) { + if (!valid_enctype(ktype[i])) + continue; + + if (dbentry_supports_enctype(context, server, ktype[i])) + return (ktype[i]); + } + return 0; +} + + + + + diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index e28113169..f1b742506 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -73,6 +73,22 @@ int validate_tgs_request PROTOTYPE((krb5_kdc_req *, krb5_db_entry, int fetch_asn1_field PROTOTYPE((unsigned char *, unsigned int, unsigned int, krb5_data *)); +int +dbentry_has_key_for_enctype PROTOTYPE((krb5_context context, + krb5_db_entry *client, + krb5_enctype enctype)); + +int +dbentry_supports_enctype PROTOTYPE((krb5_context context, + krb5_db_entry *client, + krb5_enctype enctype)); + +krb5_enctype +select_session_keytype PROTOTYPE((krb5_context context, + krb5_db_entry *server, + int nktypes, + krb5_enctype *ktypes)); + /* do_as_req.c */ krb5_error_code process_as_req PROTOTYPE((krb5_kdc_req *, const krb5_fulladdr *, diff --git a/src/kdc/main.c b/src/kdc/main.c index fa4572c8c..b698a0fa3 100644 --- a/src/kdc/main.c +++ b/src/kdc/main.c @@ -254,11 +254,22 @@ finish_realm(rdp) free(rdp->realm_mpname); if (rdp->realm_stash) free(rdp->realm_stash); + if (rdp->realm_ports) + free(rdp->realm_ports); + if (rdp->realm_kstypes) + free(rdp->realm_kstypes); if (rdp->realm_context) { if (rdp->realm_mprinc) krb5_free_principal(rdp->realm_context, rdp->realm_mprinc); - if (rdp->realm_mkey.length && rdp->realm_mkey.contents) - krb5_free_keyblock(rdp->realm_context, &rdp->realm_mkey); + if (rdp->realm_mkey.length && rdp->realm_mkey.contents) { + memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length); + free(rdp->realm_mkey.contents); + } + if (rdp->realm_tgskey.length && rdp->realm_tgskey.contents) { + memset(rdp->realm_tgskey.contents, 0, rdp->realm_tgskey.length); + free(rdp->realm_tgskey.contents); + } + krb5_finish_key(rdp->realm_context, &rdp->realm_encblock); krb5_db_fini(rdp->realm_context); if (rdp->realm_tgsprinc) krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc); @@ -872,6 +883,7 @@ char *argv[]; krb5_klog_syslog(LOG_INFO, "shutting down"); krb5_klog_close(kdc_context); finish_realms(argv[0]); + krb5_free_context(kcontext); return errout; } -- 2.26.2