]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Remove FAST finish checksum
authorSam Hartman <hartmans@mit.edu>
Thu, 26 Mar 2009 05:37:18 +0000 (05:37 +0000)
committerSam Hartman <hartmans@mit.edu>
Thu, 26 Mar 2009 05:37:18 +0000 (05:37 +0000)
Per discussion on ietf-krb-wg, the checksum is unnecessary if a nonce
is included in the response .  For this to be secure, the cookie needs
to be inner padata when FAST is used.

* kdc/fast.c: when constructing fast responses  include the nonce
* lib/krb5/krb/fast.c: generate a random nonce for each time a fast request is constructed
* add nonce field to fast_response
* remove checksum field from fast_finished
* Look for cookie as inner padata when FAST is used

git-svn-id: svn://anonsvn.mit.edu/krb5/branches/fast@22138 dc483132-0cff-0310-8789-dd5450dbe970

src/include/k5-int.h
src/kdc/do_as_req.c
src/kdc/fast_util.c
src/kdc/kdc_util.h
src/lib/krb5/asn.1/asn1_k_decode.c
src/lib/krb5/asn.1/asn1_k_encode.c
src/lib/krb5/asn.1/krb5_decode.c
src/lib/krb5/krb/fast.c
src/lib/krb5/krb/fast.h
src/lib/krb5/krb/kfree.c

index b7e793bb94604e96215c85b196eeebace03fb98c..439d648e0499c708bac4464403bbd5c6660655f4 100644 (file)
@@ -989,19 +989,19 @@ typedef struct _krb5_fast_req {
 #define UNSUPPORTED_CRITICAL_FAST_OPTIONS 0x00ff
 #define KRB5_FAST_OPTION_HIDE_CLIENT_NAMES 0x01
 
-    typedef struct _krb5_fast_finished {
-       krb5_timestamp timestamp;
-       krb5_int32 usec;
-       krb5_principal client;
-       krb5_checksum checksum;
-       krb5_checksum ticket_checksum;
-    } krb5_fast_finished;
-
-       typedef struct _krb5_fast_response {
-           krb5_magic magic;
+typedef struct _krb5_fast_finished {
+    krb5_timestamp timestamp;
+    krb5_int32 usec;
+    krb5_principal client;
+    krb5_checksum ticket_checksum;
+} krb5_fast_finished;
+
+typedef struct _krb5_fast_response {
+    krb5_magic magic;
     krb5_pa_data **padata;
     krb5_keyblock *rep_key;
     krb5_fast_finished *finished;
+    krb5_int32 nonce;
 } krb5_fast_response;
 
 
index a79bcb990cd5b16cfeac33b2e002ea2558148c21..c6023ec604bd3c46f6bad91539061a12a24e6ea5 100644 (file)
@@ -766,7 +766,7 @@ prepare_error_as (struct kdc_request_state *rstate, krb5_kdc_req *request, int e
        }
     }
     retval = kdc_fast_handle_error(kdc_context, rstate,
-                                  pa, &errpkt);
+                                  request, pa, &errpkt);
     if (retval == 0)
     retval = krb5_mk_error(kdc_context, &errpkt, scratch);
     free(errpkt.text.data);
index e7d935a70590c9c6d88a367bfbe87c818e5011e7..fc5934ad498fd8d1d4e3a5a04dfa22b33169fc5f 100644 (file)
@@ -113,10 +113,7 @@ krb5_error_code  kdc_find_fast
     krb5_clear_error_message(kdc_context);
     fast_padata = find_pa_data(request->padata,
                               KRB5_PADATA_FX_FAST);
-    cookie_padata = find_pa_data(request->padata, KRB5_PADATA_FX_COOKIE);
-        if (fast_padata == NULL)
-       return 0; /*no fast*/
-    
+    if (fast_padata !=  NULL){
     scratch.length = fast_padata->length;
     scratch.data = (char *) fast_padata->contents;
     retval = decode_krb5_pa_fx_fast_request(&scratch, &fast_armored_req);
@@ -171,7 +168,20 @@ krb5_error_code  kdc_find_fast
        if ((fast_req->fast_options & UNSUPPORTED_CRITICAL_FAST_OPTIONS) !=0)
            retval = KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION;
     }
-    if (retval == 0 && cookie_padata != NULL) {
+           if (retval == 0)
+               cookie_padata = find_pa_data(fast_req->req_body->padata, KRB5_PADATA_FX_COOKIE);
+           if (retval == 0) {
+             state->fast_options = fast_req->fast_options;
+             if (request->kdc_state == state)
+               request->kdc_state = NULL;
+             krb5_free_kdc_req( kdc_context, request);
+             *requestptr = fast_req->req_body;
+             fast_req->req_body = NULL;
+       
+           }
+    }
+    else cookie_padata = find_pa_data(request->padata, KRB5_PADATA_FX_COOKIE);
+        if (retval == 0 && cookie_padata != NULL) {
        krb5_pa_data *new_padata = malloc(sizeof (krb5_pa_data));
        if (new_padata != NULL) {
            retval = ENOMEM;
@@ -188,16 +198,7 @@ krb5_error_code  kdc_find_fast
            }
        }
     }
-    if (retval == 0) {
-       state->fast_options = fast_req->fast_options;
-       if (request->kdc_state == state)
-           request->kdc_state = NULL;
-       krb5_free_kdc_req( kdc_context, request);
-       *requestptr = fast_req->req_body;
-       fast_req->req_body = NULL;
-       
-    }
-    if (fast_req)
+       if (fast_req)
        krb5_free_fast_req( kdc_context, fast_req);
     if (fast_armored_req)
        krb5_free_fast_armored_req(kdc_context, fast_armored_req);
@@ -232,7 +233,9 @@ void kdc_free_rstate
 }
 
 krb5_error_code kdc_fast_response_handle_padata
-(struct kdc_request_state *state, krb5_kdc_rep *rep, const krb5_data *pkt)
+(struct kdc_request_state *state,
+ krb5_kdc_req *request,
+ krb5_kdc_rep *rep)
 {
     krb5_error_code retval = 0;
     krb5_fast_finished finish;
@@ -246,7 +249,8 @@ krb5_error_code kdc_fast_response_handle_padata
        return 0;
     memset(&finish, 0, sizeof(finish));
     fast_response.padata = rep->padata;
-    fast_response.rep_key = state->reply_key; 
+    fast_response.rep_key = state->reply_key;
+    fast_response.nonce = request->nonce;
     fast_response.finished = &finish;
     finish.client = rep->client;
     pa_array = calloc(3, sizeof(*pa_array));
@@ -263,11 +267,6 @@ krb5_error_code kdc_fast_response_handle_padata
        retval = krb5_c_make_checksum(kdc_context, cksumtype,
                                      state->armor_key, KRB5_KEYUSAGE_FAST_FINISHED,
                                      encoded_ticket, &finish.ticket_checksum);
-/* xxx checksum should be something else; sticking ticket_checksum there is a placeholder*/
-    if (retval == 0)
-       retval = krb5_c_make_checksum(kdc_context, cksumtype,
-                                     state->armor_key, KRB5_KEYUSAGE_FAST_FINISHED,
-                                     encoded_ticket, &finish.checksum);
     if (retval == 0)
        retval = encode_krb5_fast_response(&fast_response,  &encoded_fast_response);
     if (retval == 0) {
@@ -286,10 +285,8 @@ krb5_error_code kdc_fast_response_handle_padata
        krb5_free_data(kdc_context, encoded_fast_response);
     if (encoded_ticket)
        krb5_free_data(kdc_context, encoded_ticket);
-    if (finish.checksum.contents)
-       krb5_free_checksum_contents(kdc_context, &finish.checksum);
     if (finish.ticket_checksum.contents)
-       krb5_free_checksum_contents(kdc_context, &finish.checksum);
+       krb5_free_checksum_contents(kdc_context, &finish.ticket_checksum);
     return retval;
 }
 
@@ -301,6 +298,7 @@ krb5_error_code kdc_fast_response_handle_padata
  */
 krb5_error_code kdc_fast_handle_error
 (krb5_context context, struct kdc_request_state *state,
+ krb5_kdc_req *request,
  krb5_pa_data  **in_padata, krb5_error *err)
 {
     krb5_error_code retval = 0;
@@ -335,6 +333,7 @@ krb5_error_code kdc_fast_handle_error
        pa[0].contents = (unsigned char *) encoded_fx_error->data;
        inner_pa[size++] = &pa[0];
        resp.padata = inner_pa;
+       resp.nonce = request->nonce;
        resp.rep_key = NULL;
        resp.finished = NULL;
     }
index 9d1b108a7719281f287909e2dc57da639e04c7b4..a54412528d1a27dfa7c3110a4914acbb82eb1736 100644 (file)
@@ -323,9 +323,12 @@ krb5_error_code  kdc_find_fast
  struct kdc_request_state *state);
 
 krb5_error_code kdc_fast_response_handle_padata
-(struct kdc_request_state *state, krb5_kdc_rep *rep, const krb5_data *pkt);
+(struct kdc_request_state *state,
+ krb5_kdc_req *request,
+ krb5_kdc_rep *rep);
 krb5_error_code kdc_fast_handle_error
 (krb5_context context, struct kdc_request_state *state,
+ krb5_kdc_req *request,
  krb5_pa_data  **in_padata, krb5_error *err);
 
  
index 2c11f4601041300cfe5ab10adcbbf6b584f1b7a8..c6857fe6024f8def3c31ed9674b14fc25abeae44 100644 (file)
@@ -1653,7 +1653,6 @@ asn1_error_code asn1_decode_fast_finished
 {
     setup();
     val->client = NULL;
-    val->checksum.contents = NULL;
     val->ticket_checksum.contents = NULL;
     {begin_structure();
     get_field(val->timestamp, 0, asn1_decode_kerberos_time);
@@ -1661,14 +1660,12 @@ asn1_error_code asn1_decode_fast_finished
     alloc_field(val->client);
     get_field(val->client, 2, asn1_decode_realm);
     get_field(val->client, 3, asn1_decode_principal_name);
-    get_field(val->checksum, 4, asn1_decode_checksum);
-    get_field(val->ticket_checksum, 5, asn1_decode_checksum);
+    get_field(val->ticket_checksum, 4, asn1_decode_checksum);
     end_structure();
     }
     return 0;
  error_out:
     krb5_free_principal(NULL, val->client);
-    krb5_free_checksum_contents(NULL, &val->checksum);
     krb5_free_checksum_contents( NULL, &val->ticket_checksum);
     return retval;
 }
index 1ce4c29d261540be194ef896870f8eabcc78cf83..53ce7fee1d3a96565c6e3c1298ff01430272f243 100644 (file)
@@ -1224,8 +1224,7 @@ static const struct field_info fast_finished_fields[] = {
     FIELDOF_NORM( krb5_fast_finished, int32, usec, 1),
     FIELDOF_NORM( krb5_fast_finished, realm_of_principal, client, 2),
     FIELDOF_NORM(krb5_fast_finished, principal, client, 3),
-    FIELDOF_NORM( krb5_fast_finished, checksum, checksum, 4),
-    FIELDOF_NORM( krb5_fast_finished, checksum, ticket_checksum, 5),
+    FIELDOF_NORM( krb5_fast_finished, checksum, ticket_checksum, 4),
 };
 
 DEFSEQTYPE( fast_finished, krb5_fast_finished, fast_finished_fields, 0);
@@ -1236,6 +1235,7 @@ static const struct field_info fast_response_fields[] = {
     FIELDOF_NORM(krb5_fast_response, ptr_seqof_pa_data, padata, 0),
     FIELDOF_OPT( krb5_fast_response, ptr_encryption_key, rep_key, 1, 1),
     FIELDOF_OPT( krb5_fast_response, ptr_fast_finished, finished, 2, 2),
+    FIELDOF_NORM(krb5_fast_response, int32, nonce, 3),
 };
 
 static unsigned int fast_response_optional (const void *p)
index b69e40a9ead8fbe67ac0a44be53095058cba6a74..32d60915da920036dd32b9c92ddca292cd0725d8 100644 (file)
@@ -1142,7 +1142,8 @@ krb5_error_code decode_krb5_fast_response
     get_field(rep->padata, 0, asn1_decode_sequence_of_pa_data);
     opt_field(rep->rep_key, 1, asn1_decode_encryption_key_ptr);
     opt_field(rep->finished, 2, asn1_decode_fast_finished_ptr);
-    end_structure(); }
+    get_field(rep->nonce, 3, asn1_decode_int32);
+        end_structure(); }
     rep->magic = KV5M_FAST_RESPONSE;
     cleanup(free);
 }
index 4d5f62e8e9534f4e644afd9658fd4d3e1727ec43..5a8614a85d5e5ec3668c3cfe4f0b245074e34c3b 100644 (file)
@@ -159,7 +159,7 @@ krb5_error_code krb5int_fast_as_armor
 
 krb5_error_code 
 krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *state,
-                      const krb5_kdc_req *request,
+                       krb5_kdc_req *request,
                       const krb5_data *to_be_checksummed, kdc_req_encoder_proc encoder,
                       krb5_data **encoded_request)
 {
@@ -172,6 +172,8 @@ krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *
     krb5_data *encoded_armored_req = NULL;
     krb5_data *local_encoded_result = NULL;
     krb5_cksumtype cksumtype;
+    krb5_data random_data;
+    char random_buf[4];
 
     assert(state != NULL);
     assert(state->fast_outer_request.padata == NULL);
@@ -179,6 +181,14 @@ krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *
     if (state->armor_key == NULL) {
        return encoder(request, encoded_request);
     }
+/* Fill in a fresh random nonce for each inner request*/
+       random_data.length = 4;
+       random_data.data = (char *)random_buf;
+       retval = krb5_c_random_make_octets(context, &random_data);
+       if (retval == 0) {
+                   request->nonce = 0x7fffffff & load_32_n(random_buf);
+                   state->nonce = request->nonce;
+       }
     fast_req.req_body =  request;
     if (fast_req.req_body->padata == NULL) {
        fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *));
@@ -287,6 +297,12 @@ krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_sta
        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) {
                krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED, "Expecting FX_ERROR pa-data inside FAST container");
index acd12b345cdf78d130b031540f3fecdbe7e1eb6b..5425923a2391d926f683a49fef51c43381c1b189 100644 (file)
@@ -39,6 +39,7 @@ struct krb5int_fast_request_state {
     krb5_ui_4 fast_state_flags;
     krb5_ui_4 fast_options;
     krb5_data cookie_contents;
+    krb5_int32 nonce;
 };
 
 krb5_error_code
@@ -49,7 +50,7 @@ typedef krb5_error_code(*kdc_req_encoder_proc) (const krb5_kdc_req *, krb5_data
 
 krb5_error_code 
 krb5int_fast_prep_req (krb5_context context, struct krb5int_fast_request_state *state,
-                      const krb5_kdc_req *request,
+                      krb5_kdc_req *request,
                       const krb5_data *to_be_checksummed, kdc_req_encoder_proc encoder,
                       krb5_data **encoded_request);
 krb5_error_code
index d3ad3f7fae47687d41823d05e5c9da3cb02fbb57..d17d46bc7d94ad247e354009c0fca893ad76e7a3 100644 (file)
@@ -828,7 +828,6 @@ void krb5_free_fast_finished
   if (!val)
     return;
   krb5_free_principal(context, val->client);
-  krb5_free_checksum_contents(context, &val->checksum);
   krb5_free_checksum_contents(context, &val->ticket_checksum);
   free(val);
 }