diff options
-rw-r--r-- | src/include/krb5/kdcpreauth_plugin.h | 29 | ||||
-rw-r--r-- | src/kdc/do_as_req.c | 5 | ||||
-rw-r--r-- | src/kdc/kdc_preauth.c | 22 | ||||
-rw-r--r-- | src/kdc/kdc_util.h | 1 | ||||
-rw-r--r-- | src/plugins/preauth/otp/main.c | 51 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_srv.c | 41 | ||||
-rw-r--r-- | src/plugins/preauth/spake/spake_kdc.c | 24 |
7 files changed, 92 insertions, 81 deletions
diff --git a/src/include/krb5/kdcpreauth_plugin.h b/src/include/krb5/kdcpreauth_plugin.h index b0daae1..f40e368 100644 --- a/src/include/krb5/kdcpreauth_plugin.h +++ b/src/include/krb5/kdcpreauth_plugin.h @@ -182,12 +182,12 @@ typedef struct krb5_kdcpreauth_callbacks_st { /* End of version 2 kdcpreauth callbacks. */ /* - * Get the decrypted client long-term key chosen according to the request - * enctype list, or NULL if no matching key was found. The returned - * pointer is an alias and should not be freed. If invoked from - * return_padata, the result will be the same as the encrypting_key - * parameter if it is not NULL, and will therefore reflect the modified - * reply key if a return_padata handler has replaced the reply key. + * Get the current reply key. Initially the reply key is the decrypted + * client long-term key chosen according to the request enctype list, or + * NULL if no matching key was found. The value may be changed by the + * replace_reply_key callback or a return_padata method modifying + * encrypting_key. The returned pointer is an alias and should not be + * freed. */ const krb5_keyblock *(*client_keyblock)(krb5_context context, krb5_kdcpreauth_rock rock); @@ -257,6 +257,20 @@ typedef struct krb5_kdcpreauth_callbacks_st { /* End of version 5 kdcpreauth callbacks. */ + /* + * Replace the reply key with key. If is_strengthen is true, key must be a + * derivative of the client long-term key. This callback may be invoked + * from the verify or return_padata methods. If it is invoked from the + * verify method, the new key will appear as the encrypting_key input to + * return_padata. + */ + krb5_error_code (*replace_reply_key)(krb5_context context, + krb5_kdcpreauth_rock rock, + const krb5_keyblock *key, + krb5_boolean is_strengthen); + + /* End of version 6 kdcpreauth callbacks. */ + } *krb5_kdcpreauth_callbacks; /* Optional: preauth plugin initialization function. */ @@ -350,7 +364,8 @@ typedef void /* * Optional: generate preauthentication response data to send to the client as * part of the AS-REP. If it needs to override the key which is used to - * encrypt the response, it can do so. + * encrypt the response, it can do so by modifying encrypting_key, but it is + * preferrable to use the replace_reply_key callback. */ typedef krb5_error_code (*krb5_kdcpreauth_return_fn)(krb5_context context, diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c index 5e966de..34723fa 100644 --- a/src/kdc/do_as_req.c +++ b/src/kdc/do_as_req.c @@ -743,10 +743,9 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, state->status = "DECRYPT_CLIENT_KEY"; goto errout; } - if (state->client_key != NULL) { + if (state->client_key != NULL) state->rock.client_key = state->client_key; - state->rock.client_keyblock = &state->client_keyblock; - } + state->rock.client_keyblock = &state->client_keyblock; errcode = kdc_fast_read_cookie(kdc_context, state->rstate, state->request, state->local_tgt, &state->local_tgt_key); diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 8d83274..e132390 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -449,6 +449,8 @@ have_client_keys(krb5_context context, krb5_kdcpreauth_rock rock) static const krb5_keyblock * client_keyblock(krb5_context context, krb5_kdcpreauth_rock rock) { + if (rock->client_keyblock->enctype == ENCTYPE_NULL) + return NULL; return rock->client_keyblock; } @@ -562,8 +564,23 @@ cleanup: return valid ? 0 : KRB5KDC_ERR_PREAUTH_EXPIRED; } +static krb5_error_code +replace_reply_key(krb5_context context, krb5_kdcpreauth_rock rock, + const krb5_keyblock *key, krb5_boolean is_strengthen) +{ + krb5_keyblock copy; + + if (krb5_copy_keyblock_contents(context, key, ©) != 0) + return ENOMEM; + krb5_free_keyblock_contents(context, rock->client_keyblock); + *rock->client_keyblock = copy; + if (!is_strengthen) + rock->replaced_reply_key = TRUE; + return 0; +} + static struct krb5_kdcpreauth_callbacks_st callbacks = { - 5, + 6, max_time_skew, client_keys, free_keys, @@ -581,7 +598,8 @@ static struct krb5_kdcpreauth_callbacks_st callbacks = { match_client, client_name, send_freshness_token, - check_freshness_token + check_freshness_token, + replace_reply_key }; static krb5_error_code diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index 45683ec..ded2912 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -447,6 +447,7 @@ struct krb5_kdcpreauth_rock_st { verto_ctx *vctx; krb5_data ***auth_indicators; krb5_boolean send_freshness_token; + krb5_boolean replaced_reply_key; }; #define isflagset(flagfield, flag) (flagfield & (flag)) diff --git a/src/plugins/preauth/otp/main.c b/src/plugins/preauth/otp/main.c index a1b6816..119714f 100644 --- a/src/plugins/preauth/otp/main.c +++ b/src/plugins/preauth/otp/main.c @@ -158,19 +158,36 @@ on_response(void *data, krb5_error_code retval, otp_response response, char *const *indicators) { struct request_state rs = *(struct request_state *)data; + krb5_context context = rs.context; + krb5_keyblock *armor_key; char *const *ind; free(data); if (retval == 0 && response != otp_response_success) retval = KRB5_PREAUTH_FAILED; + if (retval) + goto done; - if (retval == 0) - rs.enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; + rs.enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; + armor_key = rs.preauth_cb->fast_armor(context, rs.rock); + if (armor_key == NULL) { + retval = ENOENT; + goto done; + } - for (ind = indicators; ind != NULL && *ind != NULL && retval == 0; ind++) - retval = rs.preauth_cb->add_auth_indicator(rs.context, rs.rock, *ind); + retval = rs.preauth_cb->replace_reply_key(context, rs.rock, armor_key, + FALSE); + if (retval) + goto done; + for (ind = indicators; ind != NULL && *ind != NULL; ind++) { + retval = rs.preauth_cb->add_auth_indicator(context, rs.rock, *ind); + if (retval) + goto done; + } + +done: rs.respond(rs.arg, retval, NULL, NULL, NULL); } @@ -343,31 +360,6 @@ error: (*respond)(arg, retval, NULL, NULL, NULL); } -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); -} - krb5_error_code kdcpreauth_otp_initvt(krb5_context context, int maj_ver, int min_ver, krb5_plugin_vtable vtable); @@ -389,7 +381,6 @@ kdcpreauth_otp_initvt(krb5_context context, int maj_ver, int min_ver, vt->flags = otp_flags; vt->edata = otp_edata; vt->verify = otp_verify; - vt->return_padata = otp_return_padata; com_err("otp", 0, "Loaded"); diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c index 81e9656..1147a8f 100644 --- a/src/plugins/preauth/pkinit/pkinit_srv.c +++ b/src/plugins/preauth/pkinit/pkinit_srv.c @@ -763,6 +763,7 @@ pkinit_server_return_padata(krb5_context context, unsigned char *dh_pubkey = NULL, *server_key = NULL; unsigned int server_key_len = 0, dh_pubkey_len = 0; + krb5_keyblock reply_key = { 0 }; krb5_kdc_dh_key_info dhkey_info; krb5_data *encoded_dhkey_info = NULL; @@ -800,12 +801,6 @@ pkinit_server_return_padata(krb5_context context, TRACE_PKINIT_SERVER_RETURN_PADATA(context); reqctx = (pkinit_kdc_req_context)modreq; - 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)) @@ -883,19 +878,19 @@ pkinit_server_return_padata(krb5_context context, } 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; - } - init_krb5_reply_key_pack(&key_pack); if (key_pack == NULL) { retval = ENOMEM; goto cleanup; } - retval = krb5_c_make_checksum(context, 0, encrypting_key, + retval = krb5_c_make_random_key(context, enctype, &key_pack->replyKey); + if (retval) { + pkiDebug("unable to make a session key\n"); + goto cleanup; + } + + retval = krb5_c_make_checksum(context, 0, &key_pack->replyKey, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, req_pkt, &key_pack->asChecksum); if (retval) { @@ -908,13 +903,10 @@ pkinit_server_return_padata(krb5_context context, 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); + pkiDebug("encrypting key (%d)\n", key_pack->replyKey.length); + print_buffer(key_pack->replyKey.contents, key_pack->replyKey.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) { @@ -944,6 +936,11 @@ pkinit_server_return_padata(krb5_context context, print_buffer_bin(rep->u.encKeyPack.data, rep->u.encKeyPack.length, "/tmp/kdc_enc_key_pack"); #endif + + retval = cb->replace_reply_key(context, rock, &key_pack->replyKey, + FALSE); + if (retval) + goto cleanup; } if (rep->choice == choice_pa_pk_as_rep_dhInfo && @@ -989,7 +986,7 @@ pkinit_server_return_padata(krb5_context context, rep->u.dh_Info.kdfID, request->client, request->server, enctype, req_pkt, out_data, - encrypting_key); + &reply_key); if (retval) { pkiDebug("pkinit_alg_agility_kdf failed: %s\n", error_message(retval)); @@ -999,13 +996,16 @@ pkinit_server_return_padata(krb5_context context, /* Otherwise, use the older octetstring2key() function */ } else { retval = pkinit_octetstring2key(context, enctype, server_key, - server_key_len, encrypting_key); + server_key_len, &reply_key); if (retval) { pkiDebug("pkinit_octetstring2key failed: %s\n", error_message(retval)); goto cleanup; } } + retval = cb->replace_reply_key(context, rock, &reply_key, FALSE); + if (retval) + goto cleanup; } *send_pa = malloc(sizeof(krb5_pa_data)); @@ -1034,6 +1034,7 @@ cleanup: free_krb5_pa_pk_as_req(&reqp); free_krb5_pa_pk_as_rep(&rep); free_krb5_reply_key_pack(&key_pack); + krb5_free_keyblock_contents(context, &reply_key); if (retval) pkiDebug("pkinit_verify_padata failure"); diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c index 88c964c..95cdb55 100644 --- a/src/plugins/preauth/spake/spake_kdc.c +++ b/src/plugins/preauth/spake/spake_kdc.c @@ -458,6 +458,10 @@ verify_response(krb5_context context, groupstate *gstate, ret = derive_key(context, gstate, group, ikey, &wbytes, &spakeresult, &thash, der_req, 0, &reply_key); + if (ret) + goto cleanup; + + ret = cb->replace_reply_key(context, rock, reply_key, TRUE); cleanup: zapfree(wbytes.data, wbytes.length); @@ -466,7 +470,7 @@ cleanup: krb5_free_data_contents(context, &thash); krb5_free_keyblock(context, k1); k5_free_spake_factor(context, factor); - (*respond)(arg, ret, (krb5_kdcpreauth_modreq)reply_key, NULL, NULL); + (*respond)(arg, ret, NULL, NULL, NULL); } /* @@ -533,23 +537,6 @@ spake_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, k5_free_pa_spake(context, pa_spake); } -/* If a key was set in the per-request module data, replace the reply key. Do - * not generate any pa-data to include with the KDC reply. */ -static krb5_error_code -spake_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt, - krb5_kdc_req *request, krb5_kdc_rep *reply, - krb5_keyblock *encrypting_key, krb5_pa_data **send_pa_out, - krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, - krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq) -{ - krb5_keyblock *reply_key = (krb5_keyblock *)modreq; - - if (reply_key == NULL) - return 0; - krb5_free_keyblock_contents(context, encrypting_key); - return krb5_copy_keyblock_contents(context, reply_key, encrypting_key); -} - /* Release a per-request module data object. */ static void spake_free_modreq(krb5_context context, krb5_kdcpreauth_moddata moddata, @@ -578,7 +565,6 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver, vt->fini = spake_fini; vt->edata = spake_edata; vt->verify = spake_verify; - vt->return_padata = spake_return; vt->free_modreq = spake_free_modreq; return 0; } |