svn rev #22140: branches/fast/src/lib/krb5/ error_tables/ krb/

hartmans@MIT.EDU hartmans at MIT.EDU
Thu Mar 26 01:37:26 EDT 2009


http://src.mit.edu/fisheye/changelog/krb5/?cs=22140
Commit By: hartmans
Log Message:
FAST encrypted response for  client

Implement routine to decrypt FAST response.  Use this in
process_error.  Implement new krb5int_fast_process_response to process
FAST in an AS-REP or TGS-rep.  Call that routine from
krb5_get_init_creds.
Add a new error code for FAST required but not supported.


Changed Files:
U   branches/fast/src/lib/krb5/error_tables/krb5_err.et
U   branches/fast/src/lib/krb5/krb/fast.c
U   branches/fast/src/lib/krb5/krb/fast.h
U   branches/fast/src/lib/krb5/krb/get_in_tkt.c
Modified: branches/fast/src/lib/krb5/error_tables/krb5_err.et
===================================================================
--- branches/fast/src/lib/krb5/error_tables/krb5_err.et	2009-03-26 05:37:23 UTC (rev 22139)
+++ branches/fast/src/lib/krb5/error_tables/krb5_err.et	2009-03-26 05:37:25 UTC (rev 22140)
@@ -347,4 +347,5 @@
 error_code KRB5_PLUGIN_OP_NOTSUPP,  "Plugin does not support the operaton"
 
 error_code KRB5_ERR_INVALID_UTF8,	"Invalid UTF-8 string"
+error_code KRB5_ERR_FAST_REQUIRED, "FAST protected pre-authentication required but not supported by KDC"
 end

Modified: branches/fast/src/lib/krb5/krb/fast.c
===================================================================
--- branches/fast/src/lib/krb5/krb/fast.c	2009-03-26 05:37:23 UTC (rev 22139)
+++ branches/fast/src/lib/krb5/krb/fast.c	2009-03-26 05:37:25 UTC (rev 22140)
@@ -246,6 +246,63 @@
     return retval;
 }
 
+static krb5_error_code decrypt_fast_reply
+(krb5_context context, struct krb5int_fast_request_state *state,
+ krb5_pa_data **in_padata,
+ krb5_fast_response **response)
+{
+    krb5_error_code retval = 0;
+    krb5_data scratch;
+    krb5_enc_data *encrypted_response = NULL;
+    krb5_pa_data *fx_reply = NULL;
+    krb5_fast_response *local_resp = NULL;
+    assert(state != NULL);
+    if (state->armor_key == NULL)
+	return 0;
+        fx_reply = krb5int_find_pa_data(context, in_padata, KRB5_PADATA_FX_FAST);
+    if (fx_reply == NULL)
+	retval = KRB5_ERR_FAST_REQUIRED;
+    if (retval == 0) {
+	scratch.data = (char *) fx_reply->contents;
+	scratch.length = fx_reply->length;
+	retval = decode_krb5_pa_fx_fast_reply(&scratch, &encrypted_response);
+    }
+    scratch.data = NULL;
+    if (retval == 0) {
+	scratch.data = malloc(encrypted_response->ciphertext.length);
+	if (scratch.data == NULL)
+	    retval = ENOMEM;
+	scratch.length = encrypted_response->ciphertext.length;
+    }
+    if (retval == 0)
+	retval = krb5_c_decrypt(context, state->armor_key,
+				KRB5_KEYUSAGE_FAST_REP, NULL,
+				encrypted_response, &scratch);
+    if (retval != 0) {
+	const char * errmsg;
+	errmsg = krb5_get_error_message(context, retval);
+	krb5_set_error_message(context, retval, "%s while decrypting FAST reply", errmsg);
+	krb5_free_error_message(context, errmsg);
+    }
+    if (retval == 0)
+	retval = decode_krb5_fast_response(&scratch, &local_resp);
+    if (retval == 0) {
+	if (local_resp->nonce != state->nonce) {
+	    retval = KRB5_KDCREP_MODIFIED;
+	    krb5_set_error_message(context, retval, "nonce modified in FAST response: KDC response modified");
+	}
+    }
+    if (retval == 0) {
+	*response = local_resp;
+	local_resp = NULL;
+    }
+    if (scratch.data)
+	free(scratch.data);
+    if (encrypted_response)
+	krb5_free_enc_data(context, encrypted_response);
+    return retval;
+}
+
 /*
  * FAST separates two concepts: the set of padata we're using to
  * decide what pre-auth mechanisms to use and the set of padata we're
@@ -269,15 +326,15 @@
     *out_padata = NULL;
     *retry = 0;
     if (state->armor_key) {
-	krb5_pa_data *fast_pa, *fx_error_pa;
+	krb5_pa_data *fx_error_pa;
 	krb5_pa_data **result = NULL;
 	krb5_data scratch, *encoded_td = NULL;
 	krb5_error *fx_error = NULL;
 	krb5_fast_response *fast_response = NULL;
 	retval = decode_krb5_padata_sequence(&err_reply->e_data, &result);
 	if (retval == 0)
-	    fast_pa = krb5int_find_pa_data(context, result, KRB5_PADATA_FX_FAST);
-	if (retval || fast_pa == NULL) {
+	    retval = decrypt_fast_reply(context, state, result, &fast_response);
+	if (retval) {
 	    /*This can happen if the KDC does not understand FAST. We
 	     * don't expect that, but treating it as the fatal error
 	     * indicated by the KDC seems reasonable.
@@ -286,17 +343,8 @@
 	    krb5_free_pa_data(context, result);
 	    return 0;
 	}
-	scratch.data = (char *) fast_pa->contents;
-	scratch.length = fast_pa->length;
-	retval = decode_krb5_fast_response(&scratch, &fast_response);
 	krb5_free_pa_data(context, result);
 	result = NULL;
-	if (retval == 0) {
-	    if (fast_response->nonce != state->nonce) {
-		krb5_set_error_message(context, KRB5_KDCREP_MODIFIED, "Nonce in reply did not match expected value");
-		retval = KRB5_KDCREP_MODIFIED;
-	    }
-	}
 	if (retval == 0) {	
 	    fx_error_pa = krb5int_find_pa_data(context, fast_response->padata, KRB5_PADATA_FX_ERROR);
 	    if (fx_error_pa == NULL) {
@@ -317,7 +365,7 @@
 	 */
 	if (retval == 0) 
 	    retval = encode_krb5_typed_data( (krb5_typed_data **) fast_response->padata,
-					    &encoded_td);
+					     &encoded_td);
 	if (retval == 0) {
 	    fx_error->e_data = *encoded_td;
 	    free(encoded_td); /*contents owned by fx_error*/
@@ -353,10 +401,58 @@
 				   "Error decoding padata in error reply");
 	    return retval;
 	}
+    }
+    return retval;
+}
+
+
+krb5_error_code krb5int_fast_process_response
+(krb5_context context, struct krb5int_fast_request_state *state,
+ krb5_kdc_rep *resp,
+ krb5_keyblock **as_key)
+{
+    krb5_error_code retval = 0;
+    krb5_fast_response *fast_response = NULL;
+    krb5_data *encoded_ticket = NULL;
+    krb5_boolean cksum_valid;
+    krb5_clear_error_message(context);
+    *as_key = NULL;
+        retval = decrypt_fast_reply(context, state, resp->padata,
+				&fast_response);
+    if (retval == 0) {
+	if (fast_response->finished == 0) {
+	    retval = KRB5_KDCREP_MODIFIED;
+	    krb5_set_error_message(context, retval, "FAST response missing finish message in KDC reply");
 	}
+    }
+    if (retval == 0)
+	retval = encode_krb5_ticket(resp->ticket, &encoded_ticket);
+    if (retval == 0)
+	retval = krb5_c_verify_checksum(context, state->armor_key,
+					KRB5_KEYUSAGE_FAST_FINISHED,
+					encoded_ticket,
+					&fast_response->finished->ticket_checksum,
+					&cksum_valid);
+    if (retval == 0 && cksum_valid == 0) {
+	retval = KRB5_KDCREP_MODIFIED;
+	krb5_set_error_message(context, retval, "ticket modified in KDC reply");
+    }
+    if (retval == 0) {
+	krb5_free_principal(context, resp->client);
+	resp->client = fast_response->finished->client;
+	fast_response->finished->client = NULL;
+	*as_key = fast_response->rep_key;
+	fast_response->rep_key = NULL;
+	krb5_free_pa_data(context, resp->padata);
+	resp->padata = fast_response->padata;
+	fast_response->padata = NULL;
+    }
+    if (fast_response)
+	krb5_free_fast_response(context, fast_response);
+    if (encoded_ticket)
+	krb5_free_data(context, encoded_ticket);
     return retval;
 }
-
 krb5_error_code
 krb5int_fast_make_state( krb5_context context, struct krb5int_fast_request_state **state)
 {
@@ -381,6 +477,7 @@
 	free(state->cookie);
 	state->cookie = NULL;
     }
+    free(state);
 }
 
 krb5_pa_data * krb5int_find_pa_data

Modified: branches/fast/src/lib/krb5/krb/fast.h
===================================================================
--- branches/fast/src/lib/krb5/krb/fast.h	2009-03-26 05:37:23 UTC (rev 22139)
+++ branches/fast/src/lib/krb5/krb/fast.h	2009-03-26 05:37:25 UTC (rev 22140)
@@ -58,6 +58,11 @@
 			   krb5_error **err_replyptr			   , krb5_pa_data ***out_padata,
 			   krb5_boolean *retry);
 
+krb5_error_code krb5int_fast_process_response
+(krb5_context context, struct krb5int_fast_request_state *state,
+ krb5_kdc_rep *resp,
+ krb5_keyblock **as_key);
+
 krb5_error_code
 krb5int_fast_make_state( krb5_context context, struct krb5int_fast_request_state **state);
 

Modified: branches/fast/src/lib/krb5/krb/get_in_tkt.c
===================================================================
--- branches/fast/src/lib/krb5/krb/get_in_tkt.c	2009-03-26 05:37:23 UTC (rev 22139)
+++ branches/fast/src/lib/krb5/krb/get_in_tkt.c	2009-03-26 05:37:25 UTC (rev 22140)
@@ -968,6 +968,7 @@
     krb5_data salt;
     krb5_data s2kparams;
     krb5_keyblock as_key;
+    krb5_keyblock *fast_as_key = NULL;
     krb5_error *err_reply;
     krb5_kdc_rep *local_as_reply;
     krb5_timestamp time_now;
@@ -993,7 +994,7 @@
     preauth_to_use = NULL;
     kdc_padata = NULL;
     as_key.length = 0;
-    salt.length = 0;
+        salt.length = 0;
     salt.data = NULL;
 
 	local_as_reply = 0;
@@ -1396,6 +1397,10 @@
 
     /* process any preauth data in the as_reply */
     krb5_clear_preauth_context_use_counts(context);
+    ret = krb5int_fast_process_response(context, fast_state,
+				       local_as_reply, &fast_as_key);
+    if (ret)
+	goto cleanup;
     if ((ret = sort_krb5_padata_sequence(context, &request.server->realm,
 					 local_as_reply->padata)))
 	goto cleanup;
@@ -1441,8 +1446,14 @@
        it.  If decrypting the as_rep fails, or if there isn't an
        as_key at all yet, then use the gak_fct to get one, and try
        again.  */
-
-    if (as_key.length)
+    if (fast_as_key) {
+	if (as_key.length)
+	    krb5_free_keyblock_contents(context, &as_key);
+	as_key = *fast_as_key;
+	free(fast_as_key);
+	fast_as_key = NULL;
+    }
+        if (as_key.length)
 	ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
 			       NULL, &as_key, krb5_kdc_rep_decrypt_proc,
 			       NULL);
@@ -1499,6 +1510,7 @@
 	}
     }
     krb5_preauth_request_context_fini(context);
+	krb5_free_keyblock(context, fast_as_key);
     if (fast_state)
 	krb5int_fast_free_state(context, fast_state);
     if (out_padata)




More information about the cvs-krb5 mailing list