Merge fast branch at 22166 onto trunk
authorSam Hartman <hartmans@mit.edu>
Fri, 3 Apr 2009 04:03:45 +0000 (04:03 +0000)
committerSam Hartman <hartmans@mit.edu>
Fri, 3 Apr 2009 04:03:45 +0000 (04:03 +0000)
ticket: 6436

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22167 dc483132-0cff-0310-8789-dd5450dbe970

20 files changed:
src/include/k5-int.h
src/kdc/do_as_req.c
src/kdc/do_tgs_req.c
src/kdc/fast_util.c
src/kdc/kdc_preauth.c
src/kdc/kdc_util.c
src/kdc/kdc_util.h
src/lib/crypto/arcfour/arcfour.c
src/lib/crypto/arcfour/arcfour.h
src/lib/crypto/etypes.c
src/lib/krb5/asn.1/asn1_k_encode.c
src/lib/krb5/asn.1/krb5_decode.c
src/lib/krb5/krb/Makefile.in
src/lib/krb5/krb/fast.c
src/lib/krb5/krb/fast.h
src/lib/krb5/krb/get_in_tkt.c
src/lib/krb5/krb/kfree.c
src/lib/krb5/krb/preauth2.c
src/lib/krb5/krb/t_ad_fx_armor.c [new file with mode: 0644]
src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c

index db3976057e3cdea2a9d5144855c6a6351d30ee76..5e159d9a4fb67503f43710b479a4f19692953485 100644 (file)
@@ -982,7 +982,7 @@ typedef struct _krb5_fast_armored_req {
 
 typedef struct _krb5_fast_req {
     krb5_magic magic;
-    krb5_int32 fast_options;
+    krb5_flags fast_options;
     /* padata from req_body is used*/
    krb5_kdc_req *req_body;
 } krb5_fast_req;
@@ -1001,7 +1001,7 @@ typedef struct _krb5_fast_finished {
 typedef struct _krb5_fast_response {
     krb5_magic magic;
     krb5_pa_data **padata;
-    krb5_keyblock *rep_key;
+    krb5_keyblock *strengthen_key;
     krb5_fast_finished *finished;
     krb5_int32 nonce;
 } krb5_fast_response;
index 7b590f4e01f1676ae0bd414e32a1212f1cfd6a6d..4f1715d678ade8ce03e77dc82337cd4efdf01df1 100644 (file)
@@ -119,6 +119,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     krb5_keylist_node *tmp_mkey_list;
     struct kdc_request_state *state = NULL;
     krb5_data encoded_req_body;
+    krb5_keyblock *as_encrypting_key = NULL;
     
 
 #if APPLE_PKINIT
@@ -592,7 +593,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
        goto errout;
     }
     ticket_reply.enc_part.kvno = server_key->key_data_kvno;
-    errcode = kdc_fast_response_handle_padata(state, request, &reply);
+    errcode = kdc_fast_response_handle_padata(state, request, &reply, client_keyblock.enctype);
     if (errcode) {
        status = "fast response handling";
        goto errout;
@@ -602,8 +603,13 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
 
     reply.enc_part.enctype = client_keyblock.enctype;
 
-    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart, 
-                                 0, &client_keyblock,  &reply, response);
+    errcode = kdc_fast_handle_reply_key(state, &client_keyblock, &as_encrypting_key);
+    if (errcode) {
+       status = "generating reply key";
+       goto errout;
+    }
+        errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart, 
+                                 0, as_encrypting_key,  &reply, response);
     reply.enc_part.kvno = client_key->key_data_kvno;
     if (errcode) {
        status = "ENCODE_KDC_REP";
@@ -637,7 +643,8 @@ errout:
 egress:
     if (pa_context)
        free_padata_context(kdc_context, &pa_context);
-
+    if (as_encrypting_key)
+       krb5_free_keyblock(kdc_context, as_encrypting_key);
     if (errcode)
        emsg = krb5_get_error_message(kdc_context, errcode);
 
@@ -760,7 +767,7 @@ prepare_error_as (struct kdc_request_state *rstate, krb5_kdc_req *request, int e
            if (pa == NULL)
                retval = ENOMEM;
            else                for (size = 0; td[size]; size++) {
-               krb5_pa_data *pad = malloc(sizeof(krb5_pa_data *));
+               krb5_pa_data *pad = malloc(sizeof(krb5_pa_data ));
                if (pad == NULL) {
                    retval = ENOMEM;
                    break;
index e06d94dfca861657c0bb9afe9a3cf9f08e3fda6a..598c8797176c5b83065a769e606b6de5175a164d 100644 (file)
@@ -878,7 +878,8 @@ tgt_again:
 
     reply.enc_part.enctype = subkey ? subkey->enctype :
     header_ticket->enc_part2->session->enctype;
-    errcode  = kdc_fast_response_handle_padata(state, request, &reply);
+    errcode  = kdc_fast_response_handle_padata(state, request, &reply,
+                                              subkey?subkey->enctype:header_ticket->enc_part2->session->enctype);
     if (errcode !=0 ) {
        status = "Preparing FAST padata";
        goto cleanup;
@@ -972,7 +973,7 @@ prepare_error_tgs (struct kdc_request_state *state,
                    krb5_data **response, const char *status)
 {
     krb5_error errpkt;
-    krb5_error_code retval;
+    krb5_error_code retval = 0;
     krb5_data *scratch;
 
     errpkt.ctime = request->nonce;
@@ -997,7 +998,8 @@ prepare_error_tgs (struct kdc_request_state *state,
     }
     errpkt.e_data.length = 0;
     errpkt.e_data.data = NULL;
-    retval = kdc_fast_handle_error(kdc_context, state, request, NULL, &errpkt);
+    if (state)
+       retval = kdc_fast_handle_error(kdc_context, state, request, NULL, &errpkt);
     if (retval) {
        free(scratch);
        free(errpkt.text.data);
index 10d1d3eb61d853ca5ce9da238f5faab360eb9478..ac6aa22c48c9102f688a270ccf76e5faf79d9624 100644 (file)
@@ -50,7 +50,7 @@ static krb5_error_code armor_ap_request
     krb5_ticket *ticket = NULL;
     krb5_keyblock *subkey = NULL;
     
-    assert(armor->armor_type = KRB5_FAST_ARMOR_AP_REQUEST);
+    assert(armor->armor_type == KRB5_FAST_ARMOR_AP_REQUEST);
     krb5_clear_error_message(kdc_context);
     retval = krb5_auth_con_init(kdc_context, &authcontext);
     if (retval == 0)
@@ -251,8 +251,8 @@ void kdc_free_rstate
     return;
     if (s->armor_key)
        krb5_free_keyblock(kdc_context, s->armor_key);
-    if (s->reply_key)
-       krb5_free_keyblock(kdc_context, s->reply_key);
+    if (s->strengthen_key)
+       krb5_free_keyblock(kdc_context, s->strengthen_key);
     if (s->cookie) {
        free(s->cookie->contents);
        free(s->cookie);
@@ -263,24 +263,33 @@ void kdc_free_rstate
 krb5_error_code kdc_fast_response_handle_padata
 (struct kdc_request_state *state,
  krb5_kdc_req *request,
- krb5_kdc_rep *rep)
+ krb5_kdc_rep *rep, krb5_enctype enctype)
 {
     krb5_error_code retval = 0;
     krb5_fast_finished finish;
     krb5_fast_response fast_response;
     krb5_data *encoded_ticket = NULL;
     krb5_data *encrypted_reply = NULL;
-    krb5_pa_data *pa = NULL, **pa_array;
+    krb5_pa_data *pa = NULL, **pa_array = NULL;
     krb5_cksumtype cksumtype = CKSUMTYPE_RSA_MD5;
     krb5_pa_data *empty_padata[] = {NULL};
+    krb5_keyblock *strengthen_key = NULL;
     
     if (!state->armor_key)
        return 0;
     memset(&finish, 0, sizeof(finish));
+    retval = krb5_init_keyblock(kdc_context, enctype, 0, &strengthen_key);
+    if (retval == 0)
+       retval = krb5_c_make_random_key(kdc_context, enctype, strengthen_key);
+    if (retval == 0) {
+       state->strengthen_key = strengthen_key;
+       strengthen_key = NULL;
+    }
+    
     fast_response.padata = rep->padata;
     if (fast_response.padata == NULL)
        fast_response.padata = &empty_padata[0];
-        fast_response.rep_key = state->reply_key;
+        fast_response.strengthen_key = state->strengthen_key;
     fast_response.nonce = request->nonce;
     fast_response.finished = &finish;
     finish.client = rep->client;
@@ -309,15 +318,20 @@ krb5_error_code kdc_fast_response_handle_padata
        pa_array[0] = &pa[0];
        rep->padata = pa_array;
        pa_array = NULL;
+       free(encrypted_reply);
        encrypted_reply = NULL;
        pa = NULL;
     }
     if (pa)
       free(pa);
+    if (pa_array)
+       free(pa_array);
     if (encrypted_reply)
        krb5_free_data(kdc_context, encrypted_reply);
     if (encoded_ticket)
        krb5_free_data(kdc_context, encoded_ticket);
+    if (strengthen_key != NULL)
+       krb5_free_keyblock(kdc_context, strengthen_key);
     if (finish.ticket_checksum.contents)
        krb5_free_checksum_contents(kdc_context, &finish.ticket_checksum);
     return retval;
@@ -339,8 +353,8 @@ krb5_error_code kdc_fast_handle_error
     krb5_fast_response resp;
     krb5_error fx_error;
     krb5_data *encoded_fx_error = NULL, *encrypted_reply = NULL;
-    krb5_pa_data pa[2];
-    krb5_pa_data *outer_pa[3];
+    krb5_pa_data pa[1];
+    krb5_pa_data *outer_pa[3], *cookie = NULL;
     krb5_pa_data **inner_pa = NULL;
     size_t size = 0;
     krb5_data *encoded_e_data = NULL;
@@ -366,15 +380,26 @@ krb5_error_code kdc_fast_handle_error
        pa[0].length = encoded_fx_error->length;
        pa[0].contents = (unsigned char *) encoded_fx_error->data;
        inner_pa[size++] = &pa[0];
-       resp.padata = inner_pa;
+       if (find_pa_data(inner_pa, KRB5_PADATA_FX_COOKIE) == NULL)
+           retval = kdc_preauth_get_cookie(state, &cookie);
+    }
+    if (cookie != NULL)
+       inner_pa[size++] = cookie;
+    if (retval == 0) {
+               resp.padata = inner_pa;
        resp.nonce = request->nonce;
-       resp.rep_key = NULL;
+       resp.strengthen_key = NULL;
        resp.finished = NULL;
     }
     if (retval == 0)
        retval = encrypt_fast_reply(state, &resp, &encrypted_reply);
     if (inner_pa)
        free(inner_pa); /*contained storage from caller and our stack*/
+    if (cookie) {
+       free(cookie->contents);
+       free(cookie);
+       cookie = NULL;
+    }
     if (retval == 0) {
        pa[0].pa_type = KRB5_PADATA_FX_FAST;
        pa[0].length = encrypted_reply->length;
@@ -396,3 +421,45 @@ krb5_error_code kdc_fast_handle_error
        krb5_free_data(kdc_context, encoded_fx_error);
     return retval;
 }
+
+krb5_error_code kdc_fast_handle_reply_key(struct kdc_request_state *state,
+                                         krb5_keyblock *existing_key,
+                                         krb5_keyblock **out_key)
+{
+    krb5_error_code retval = 0;
+    if (state->armor_key)
+       retval = krb5_c_fx_cf2_simple(kdc_context,
+                                     state->strengthen_key, "strengthenkey", 
+                                     existing_key,
+                                     "replykey", out_key);
+    else retval = krb5_copy_keyblock(kdc_context, existing_key, out_key);
+    return retval;
+}
+
+
+krb5_error_code kdc_preauth_get_cookie(struct kdc_request_state *state,
+                                   krb5_pa_data **cookie)
+{
+    char *contents;
+    krb5_pa_data *pa = NULL;
+    /* In our current implementation, the only purpose served by
+     * returning a cookie is to indicate that a conversation should
+     * continue on error.  Thus, the cookie can have a constant
+     * string.  If cookies are used for real, versioning so that KDCs
+     * can be upgraded, keying, expiration and many other issues need
+     * to be considered.
+     */
+    contents = strdup("MIT");
+    if (contents == NULL)
+       return ENOMEM;
+    pa = calloc(1, sizeof(krb5_pa_data));
+    if (pa == NULL) {
+       free(contents);
+       return ENOMEM;
+    }
+    pa->pa_type = KRB5_PADATA_FX_COOKIE;
+    pa->length = strlen(contents);
+    pa->contents = (unsigned char *) contents;
+    *cookie = pa;
+    return 0;
+}
index cf269753d1d4e782cf74908acbab191f2bb44e36..3dda38150e8f91b8de0b7d3911feea7e684bbace 100644 (file)
@@ -289,6 +289,17 @@ static krb5_preauth_systems static_preauth_systems[] = {
        verify_enc_timestamp,
        0
     },
+    {
+       "FAST",
+        KRB5_PADATA_FX_FAST,
+        PA_HARDWARE,
+       NULL,
+       NULL,
+       NULL,
+        NULL,
+       NULL,
+       0
+    },
     {
        "etype-info",
        KRB5_PADATA_ETYPE_INFO,
@@ -961,7 +972,8 @@ void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client,
     e_data->data = 0;
     
     hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH);
-    pa_data = malloc(sizeof(krb5_pa_data *) * (n_preauth_systems+1));
+    /* Allocate 1 entry for the terminator and one for the cookie*/
+    pa_data = malloc(sizeof(krb5_pa_data *) * (n_preauth_systems+21));
     if (pa_data == 0)
        return;
     memset(pa_data, 0, sizeof(krb5_pa_data *) * (n_preauth_systems+1));
@@ -995,6 +1007,8 @@ void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client,
                          "%spreauth required but hint list is empty",
                          hw_only ? "hw" : "");
     }
+/* If we fail to get the cookie it is probably still reasonable to continue with the response*/
+    kdc_preauth_get_cookie(request->kdc_state, pa);
     retval = encode_krb5_padata_sequence(pa_data, &edat);
     if (retval)
        goto errout;
index 08d84db68960886cdcc9a7d18d1f24f373050b43..8e531f03b880935fd9f5b5c1b2064b597038fafd 100644 (file)
@@ -347,13 +347,13 @@ kdc_process_tgs_req(krb5_kdc_req *request, const krb5_fulladdr *from,
                                   authenticator->authorization_data,
                                   KRB5_AUTHDATA_FX_ARMOR, &authdata);
     if (retval != 0)
-       goto cleanup_auth_context;
+       goto cleanup_authenticator;
         if (authdata&& authdata[0]) {
        krb5_set_error_message(kdc_context, KRB5KDC_ERR_POLICY,
                               "ticket valid only as FAST armor");
        retval = KRB5KDC_ERR_POLICY;
        krb5_free_authdata(kdc_context, authdata);
-       goto cleanup_auth_context;
+       goto cleanup_authenticator;
     }
     krb5_free_authdata(kdc_context, authdata);
     
index 90de8d39b7aa9694a2ba295e9b9ff9412baf06ff..0604426045e5b5e426b2736b340329692807e84b 100644 (file)
@@ -302,11 +302,12 @@ void log_tgs_alt_tgt(krb5_principal p);
 
 struct kdc_request_state {
     krb5_keyblock *armor_key;
-  krb5_keyblock *reply_key; /*When replaced by FAST*/
+  krb5_keyblock *strengthen_key; 
     krb5_pa_data *cookie;
     krb5_int32 fast_options;
     krb5_int32 fast_internal_flags;
 };
+
 krb5_error_code kdc_make_rstate(struct kdc_request_state **out);
 void kdc_free_rstate
 (struct kdc_request_state *s);
@@ -325,12 +326,21 @@ krb5_error_code  kdc_find_fast
 krb5_error_code kdc_fast_response_handle_padata
 (struct kdc_request_state *state,
  krb5_kdc_req *request,
- krb5_kdc_rep *rep);
+ krb5_kdc_rep *rep,
+ krb5_enctype enctype);
 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 kdc_fast_handle_reply_key(struct kdc_request_state *state,
+                                         krb5_keyblock *existing_key,
+                                         krb5_keyblock **out_key);
+
+
+krb5_error_code kdc_preauth_get_cookie(struct kdc_request_state *state,
+                                   krb5_pa_data **cookie);
+
  
 
 
index ea3129688a093ccb4bb0ebdebdda1cf9d415de25..8d35d7eefca1c42592577082748068261d31eb8b 100644 (file)
@@ -8,6 +8,8 @@ of RSA Data Security)
 */
 #include "k5-int.h"
 #include "arcfour-int.h"
+#include "../hash_provider/hash_provider.h"
+
 const char *const krb5int_arcfour_l40 = "fortybits";
 
 void
@@ -304,3 +306,12 @@ krb5_arcfour_decrypt(const struct krb5_enc_provider *enc,
   return (ret);
 }
 
+ krb5_error_code krb5int_arcfour_prf(
+                                        const struct krb5_enc_provider *enc,
+                                        const struct krb5_hash_provider *hash,
+                                        const krb5_keyblock *key,
+                                        const krb5_data *in, krb5_data *out)
+ {
+   assert(out->length == 20);
+   return krb5_hmac(&krb5int_hash_sha1, key, 1, in, out);
+ }
index e8ff203ca168d7507dda13d79ad9f35abe386031..be408febc632d7519ff8662da7d91409a3ed5918 100644 (file)
@@ -34,5 +34,10 @@ extern krb5_error_code krb5int_arcfour_string_to_key(
 
 extern const struct krb5_enc_provider krb5int_enc_arcfour;
 extern const struct krb5_aead_provider krb5int_aead_arcfour;
+ krb5_error_code krb5int_arcfour_prf(
+                                        const struct krb5_enc_provider *enc,
+                                        const struct krb5_hash_provider *hash,
+                                        const krb5_keyblock *key,
+                                        const krb5_data *in, krb5_data *out);
 
 #endif /* ARCFOUR_H */
index e7f547b91a98692f94d6284376250d176d945f08..debf585fa7051019a5745af76bfbf412762acd6e 100644 (file)
@@ -119,10 +119,10 @@ const struct krb5_keytypes krb5_enctypes_list[] = {
       "ArcFour with HMAC/md5",
       &krb5int_enc_arcfour,
       &krb5int_hash_md5,
-      0,
+      20,
       krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
-      NULL, /*PRF*/
+      krb5int_arcfour_prf, /*PRF*/
       CKSUMTYPE_HMAC_MD5_ARCFOUR,
       &krb5int_aead_arcfour,
       0 /*flags*/ },
@@ -131,10 +131,10 @@ const struct krb5_keytypes krb5_enctypes_list[] = {
       "Exportable ArcFour with HMAC/md5",
       &krb5int_enc_arcfour,
       &krb5int_hash_md5,
-      0,
+      20,
       krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
-      NULL, /*PRF*/
+      krb5int_arcfour_prf, /*PRF*/
       CKSUMTYPE_HMAC_MD5_ARCFOUR,
       &krb5int_aead_arcfour,
       ETYPE_WEAK
index efa75643d5d75af3fab0b5127889c46cb1072c9a..ed01b7560d6e3edc4b57343b52e150deb67331ef 100644 (file)
@@ -1211,7 +1211,7 @@ DEFFIELDTYPE(fast_req_padata, krb5_kdc_req,
 DEFPTRTYPE(ptr_fast_req_padata, fast_req_padata);
 
 static const struct field_info fast_req_fields[] = {
-    FIELDOF_NORM(krb5_fast_req, int32, fast_options, 0),
+    FIELDOF_NORM(krb5_fast_req, krb5_flags, fast_options, 0),
     FIELDOF_NORM( krb5_fast_req, ptr_fast_req_padata, req_body, 1),
     FIELDOF_NORM( krb5_fast_req, ptr_kdc_req_body, req_body, 2),
 };
@@ -1233,7 +1233,7 @@ DEFPTRTYPE( ptr_fast_finished, fast_finished);
 
 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_encryption_key, strengthen_key, 1, 1),
     FIELDOF_OPT( krb5_fast_response, ptr_fast_finished, finished, 2, 2),
     FIELDOF_NORM(krb5_fast_response, int32, nonce, 3),
 };
@@ -1242,7 +1242,7 @@ static unsigned int fast_response_optional (const void *p)
 {
     unsigned int optional = 0;
     const krb5_fast_response *val = p;
-    if (val->rep_key)
+    if (val->strengthen_key)
         optional |= (1u <<1);
     if (val->finished)
         optional |= (1u<<2);
index 9080d97ec77dc1f761df9d9d6d94637a57a3fc2f..7a08ec88849877112ae08c5c942b4575f80a2768 100644 (file)
@@ -1114,7 +1114,7 @@ krb5_error_code decode_krb5_fast_req
     alloc_field(rep->req_body);
     clear_field(rep, req_body->padata);
     {begin_structure();
-    get_field(rep->fast_options, 0, asn1_decode_int32);
+    get_field(rep->fast_options, 0, asn1_decode_krb5_flags);
     opt_field(rep->req_body->padata, 1, asn1_decode_sequence_of_pa_data);
     get_field(*(rep->req_body), 2, asn1_decode_kdc_req_body);
     end_structure(); }
@@ -1137,10 +1137,10 @@ krb5_error_code decode_krb5_fast_response
     alloc_field(rep);
     clear_field(rep, finished);
     clear_field(rep, padata);
-    clear_field(rep,rep_key);
+    clear_field(rep,strengthen_key);
     {begin_structure();
     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->strengthen_key, 1, asn1_decode_encryption_key_ptr);
     opt_field(rep->finished, 2, asn1_decode_fast_finished_ptr);
     get_field(rep->nonce, 3, asn1_decode_int32);
         end_structure(); }
index acc18f6f462790c2db3ae95071be8b350889a1e0..c5256b3137a1f7124f2b7855da71d0c23170770a 100644 (file)
@@ -271,6 +271,7 @@ SRCS=       $(srcdir)/addr_comp.c   \
        $(srcdir)/srv_dec_tkt.c \
        $(srcdir)/srv_rcache.c  \
        $(srcdir)/str_conv.c    \
+       $(srcdir)/t_ad_fx_armor.c \
        $(srcdir)/tgtname.c     \
        $(srcdir)/unparse.c     \
        $(srcdir)/valid_times.c \
@@ -317,6 +318,9 @@ T_PRINC_OBJS= t_princ.o parse.o unparse.o
 
 t_walk_rtree: $(T_WALK_RTREE_OBJS) $(KRB5_BASE_DEPLIBS)
        $(CC_LINK) -o t_walk_rtree $(T_WALK_RTREE_OBJS) $(KRB5_BASE_LIBS)
+t_ad_fx_armor: t_ad_fx_armor.o
+       $(CC_LINK) -o $@ $< $(KRB5_BASE_LIBS)
+
 t_authdata: t_authdata.o copy_auth.o
        $(CC_LINK) -o $@ $< copy_auth.o $(KRB5_BASE_LIBS)
 
index e9f54be788bd7616624fc41b5a8b62c81e52a187..ef57e6d832f4128099e090079b9bc3d15aa8a8ce 100644 (file)
@@ -299,6 +299,8 @@ static krb5_error_code decrypt_fast_reply
        free(scratch.data);
     if (encrypted_response)
        krb5_free_enc_data(context, encrypted_response);
+    if (local_resp)
+       krb5_free_fast_response(context, local_resp);
     return retval;
 }
 
@@ -376,9 +378,11 @@ krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_sta
            fast_response->padata = NULL;
            /*
             * If there is more than the fx_error padata, then we want
-            * to retry the error
+            * to retry the error if a cookie is present
             */
            *retry = (*out_padata)[1] != NULL;
+           if (krb5int_find_pa_data(context, *out_padata, KRB5_PADATA_FX_COOKIE) == NULL)
+               *retry = 0;
        }
        if (fx_error)
            krb5_free_error(context, fx_error);
@@ -408,14 +412,14 @@ krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_sta
 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_keyblock **strengthen_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;
+    *strengthen_key = NULL;
     if (state->armor_key == 0)
        return 0;
         retval = decrypt_fast_reply(context, state, resp->padata,
@@ -442,8 +446,8 @@ krb5_error_code krb5int_fast_process_response
        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;
+       *strengthen_key = fast_response->strengthen_key;
+       fast_response->strengthen_key = NULL;
        krb5_free_pa_data(context, resp->padata);
        resp->padata = fast_response->padata;
        fast_response->padata = NULL;
@@ -454,6 +458,29 @@ krb5_error_code krb5int_fast_process_response
        krb5_free_data(context, encoded_ticket);
     return retval;
 }
+
+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;
+}
+
+
 krb5_error_code
 krb5int_fast_make_state( krb5_context context, struct krb5int_fast_request_state **state)
 {
@@ -473,11 +500,6 @@ krb5int_fast_free_state( krb5_context context, struct krb5int_fast_request_state
     /*We are responsible for none of the store in the fast_outer_req*/
     krb5_free_keyblock(context, state->armor_key);
     krb5_free_fast_armor(context, state->armor);
-    if (state->cookie) {
-       free(state->cookie->contents);
-       free(state->cookie);
-       state->cookie = NULL;
-    }
     free(state);
 }
 
index e21df6504b7a97121fb4816433797139c1703980..4cc142335e1125b338cbf77ba13fb19a076b9e29 100644 (file)
@@ -38,7 +38,6 @@ struct krb5int_fast_request_state {
     krb5_fast_armor *armor;
     krb5_ui_4 fast_state_flags;
     krb5_ui_4 fast_options;
-  krb5_pa_data *cookie;
     krb5_int32 nonce;
 };
 
@@ -61,7 +60,7 @@ krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_sta
 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_keyblock **strengthen_key);
 
 krb5_error_code
 krb5int_fast_make_state( krb5_context context, struct krb5int_fast_request_state **state);
@@ -73,5 +72,11 @@ krb5_error_code krb5int_fast_as_armor
  krb5_gic_opt_ext *opte,
  krb5_kdc_req *request);
 
+krb5_error_code krb5int_fast_reply_key(krb5_context context,
+                                      krb5_keyblock *strengthen_key,
+                                      krb5_keyblock *existing_key,
+                                      krb5_keyblock *output_key);
+
+                                      
 
 #endif
index 30a38cdae99429733840ebad81a48b34ce132e9e..2944652ffc63bc1efe545e150d6756c5dfe605a7 100644 (file)
@@ -967,8 +967,8 @@ krb5_get_init_creds(krb5_context context,
     int loopcount;
     krb5_data salt;
     krb5_data s2kparams;
-    krb5_keyblock as_key;
-    krb5_keyblock *fast_as_key = NULL;
+    krb5_keyblock as_key, encrypting_key;
+    krb5_keyblock *strengthen_key = NULL;
     krb5_error *err_reply;
     krb5_kdc_rep *local_as_reply;
     krb5_timestamp time_now;
@@ -994,6 +994,8 @@ krb5_get_init_creds(krb5_context context,
     preauth_to_use = NULL;
     kdc_padata = NULL;
     as_key.length = 0;
+    encrypting_key.length = 0;
+    encrypting_key.contents = NULL;
         salt.length = 0;
     salt.data = NULL;
 
@@ -1340,8 +1342,6 @@ krb5_get_init_creds(krb5_context context,
                out_padata = NULL;
                krb5_free_error(context, err_reply);
                err_reply = NULL;
-               if (ret)
-                   goto cleanup;
                ret = sort_krb5_padata_sequence(context,
                                                &request.server->realm,
                                                preauth_to_use);
@@ -1399,7 +1399,7 @@ krb5_get_init_creds(krb5_context context,
     /* 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);
+                                      local_as_reply, &strengthen_key);
     if (ret)
        goto cleanup;
     if ((ret = sort_krb5_padata_sequence(context, &request.server->realm,
@@ -1447,18 +1447,15 @@ krb5_get_init_creds(krb5_context context,
        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 (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,
+    if (as_key.length) {
+      ret = krb5int_fast_reply_key(context, strengthen_key, &as_key,
+                                  &encrypting_key);
+      if (ret)
+       goto cleanup;
+       ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
+                              NULL, &encrypting_key, krb5_kdc_rep_decrypt_proc,
                               NULL);
-    else
+    else
        ret = -1;
           
     if (ret) {
@@ -1470,6 +1467,10 @@ krb5_get_init_creds(krb5_context context,
                               &as_key, gak_data))))
            goto cleanup;
 
+       ret = krb5int_fast_reply_key(context, strengthen_key, &as_key,
+                                    &encrypting_key);
+       if (ret)
+         goto cleanup;
        if ((ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
                                    NULL, &as_key, krb5_kdc_rep_decrypt_proc,
                                    NULL)))
@@ -1511,8 +1512,10 @@ cleanup:
        }
     }
     krb5_preauth_request_context_fini(context);
-       krb5_free_keyblock(context, fast_as_key);
-    if (fast_state)
+       krb5_free_keyblock(context, strengthen_key);
+       if (encrypting_key.contents)
+         krb5_free_keyblock_contents(context, &encrypting_key);
+           if (fast_state)
        krb5int_fast_free_state(context, fast_state);
     if (out_padata)
        krb5_free_pa_data(context, out_padata);
index d17d46bc7d94ad247e354009c0fca893ad76e7a3..bec9a61bfa894cb92bc1b4b38aebf3bf6235535f 100644 (file)
@@ -819,6 +819,7 @@ void krb5_free_fast_response(krb5_context context, krb5_fast_response *val)
     return;
   krb5_free_pa_data(context, val->padata);
   krb5_free_fast_finished(context, val->finished);
+  krb5_free_keyblock(context, val->strengthen_key);
   free(val);
 }
 
index 4c7dd5e607b95c24dc8e750586ae9e8608135036..73f4e79b613b95c226536bbd39aa17d604b3c477 100644 (file)
@@ -645,6 +645,36 @@ krb5_error_code pa_salt(krb5_context context,
     return(0);
 }
 
+static
+krb5_error_code pa_fx_cookie(krb5_context context,
+                                krb5_kdc_req *request,
+                                krb5_pa_data *in_padata,
+                                krb5_pa_data **out_padata,
+                                krb5_data *salt,
+                                krb5_data *s2kparams,
+                                krb5_enctype *etype,
+                                krb5_keyblock *as_key,
+                                krb5_prompter_fct prompter,
+                                void *prompter_data,
+                                krb5_gic_get_as_key_fct gak_fct,
+                                void *gak_data)
+{
+    krb5_pa_data *pa = calloc(1, sizeof(krb5_pa_data));
+    krb5_octet *contents;
+    if (pa == NULL)
+       return ENOMEM;
+    contents = malloc(in_padata->length);
+    if (contents == NULL) {
+       free(pa);
+       return ENOMEM;
+    }
+    *pa = *in_padata;
+    pa->contents = contents;
+    memcpy(contents, in_padata->contents, pa->length);
+    *out_padata = pa;
+    return 0;
+}
+
 static
 krb5_error_code pa_enc_timestamp(krb5_context context,
                                 krb5_kdc_req *request,
@@ -1709,6 +1739,11 @@ static const pa_types_t pa_types[] = {
        pa_sam,
        PA_REAL,
     },
+    {
+       KRB5_PADATA_FX_COOKIE,
+       pa_fx_cookie,
+       PA_INFO,
+    },
     {
        -1,
        NULL,
diff --git a/src/lib/krb5/krb/t_ad_fx_armor.c b/src/lib/krb5/krb/t_ad_fx_armor.c
new file mode 100644 (file)
index 0000000..74d7e5f
--- /dev/null
@@ -0,0 +1,36 @@
+#include <memory.h>
+#include <stdio.h>
+#include <krb5/krb5.h>
+
+#define test(x) do {retval = (x); \
+  if(retval != 0) {                                            \
+  const char *errmsg = krb5_get_error_message(context, retval);        \
+  fprintf(stderr, "Error message: %s\n", errmsg); \
+  abort(); } \
+  } while(0);
+
+krb5_authdata ad_fx_armor = {0, KRB5_AUTHDATA_FX_ARMOR, 1, ""};
+krb5_authdata *array[] = {&ad_fx_armor, NULL};
+
+
+int main( int argc, char **argv)
+{
+    krb5_context context;
+    krb5_ccache ccache = NULL;
+    krb5_creds creds, *out_creds = NULL;
+    krb5_error_code retval = 0;
+    test(krb5_init_context(&context));
+    memset(&creds, 0, sizeof(creds));
+    creds.authdata = array;
+    test(krb5_cc_default(context, &ccache));
+    test(krb5_cc_get_principal(context, ccache, &creds.client));
+    test(krb5_parse_name(context, argv[1], &creds.server));
+    test(krb5_get_credentials(context, 0, ccache, &creds, &out_creds));
+    test(krb5_cc_destroy(context, ccache));
+    test(krb5_cc_default(context, &ccache));
+    test(krb5_cc_initialize(context, ccache, out_creds->client));
+    test(krb5_cc_store_cred(context, ccache, out_creds));
+    test(krb5_cc_close(context,ccache));
+    return 0;
+                
+} 
index 3fad7ccd3a7614db7979cf70236f0b9eea95c99d..692449150e1c89ab1bed54b4035842424baa0f0f 100644 (file)
@@ -116,6 +116,7 @@ static krb5_error_code process_preauth
        krb5_pa_data **pa_array = NULL;
        krb5_data *encoded_ts = NULL;
        krb5_pa_enc_ts ts;
+       enc.ciphertext.data = NULL;
        if (retval == 0)
        retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec);
        if (retval == 0)
@@ -300,8 +301,6 @@ static krb5_error_code kdc_verify_preauth
     }
     if (armor_key)
        krb5_free_keyblock(context, armor_key);
-    if (challenge_key)
-       krb5_free_keyblock(context, challenge_key);
     if (plain.data) 
        free(plain.data);
     if (enc)