Implement TGS authenticator subkey usage
authorSam Hartman <hartmans@mit.edu>
Fri, 13 Feb 2009 15:55:32 +0000 (15:55 +0000)
committerSam Hartman <hartmans@mit.edu>
Fri, 13 Feb 2009 15:55:32 +0000 (15:55 +0000)
Implement support for use of a subkey in the TGS req.  This is needed
by FAST TGS support.  The interface to krb5_send_tgs changed in order
to gain a subkey output parameter.  Since this is a private interface
it was renamed to krb5int_send_tgs and removed from the export list.

* send_tgs.c: generate a subkey and return to caller
* decode_kdc_rep.c: Use subkey keyusage
* gc_via_tkt.c: pass in subkey to decode_kdc_rep
* send_tgs.c: use subkey for encrypting authorization data

ticket: 6393
tags: enhancement

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

src/include/k5-int.h
src/lib/krb5/krb/decode_kdc.c
src/lib/krb5/krb/gc_via_tkt.c
src/lib/krb5/krb/send_tgs.c
src/lib/krb5/libkrb5.exports

index 61d1aa18fff89ecdc6b8d3a613fae3ad1b6bbfac..79d1cf1cd36448b0cde75c72f76b717a636a5a6e 100644 (file)
@@ -2523,7 +2523,7 @@ krb5_error_code KRB5_CALLCONV krb5_get_default_config_files
 
 void KRB5_CALLCONV krb5_free_config_files
        (char **filenames);
-krb5_error_code krb5_send_tgs
+krb5_error_code krb5int_send_tgs
        (krb5_context,
                krb5_flags,
                const krb5_ticket_times *,
@@ -2534,11 +2534,16 @@ krb5_error_code krb5_send_tgs
                krb5_pa_data * const *,
                const krb5_data *,
                krb5_creds *,
-               krb5_response * );
+               krb5_response * , krb5_keyblock **subkey);
+                /* The subkey field is an output parameter; if a
+                * tgs-rep is received then the subkey will be filled
+                * in with the subkey needed to decrypt the TGS
+                * response. Otherwise it will be set to null.
+                */
 krb5_error_code krb5_decode_kdc_rep
        (krb5_context,
                krb5_data *,
-               const krb5_keyblock *,
+         const krb5_keyblock *,
                krb5_kdc_rep ** );
 
 krb5_error_code krb5_rd_req_decoded
index cdfc4ffbde43edb482399d38d94fa17b052a584d..a75bbf26652f6a8636c2ee2e61cd0e6968e1b922 100644 (file)
@@ -53,12 +53,7 @@ krb5_decode_kdc_rep(krb5_context context, krb5_data *enc_rep, const krb5_keybloc
        usage = KRB5_KEYUSAGE_AS_REP_ENCPART;
        retval = decode_krb5_as_rep(enc_rep, &local_dec_rep);
     } else if (krb5_is_tgs_rep(enc_rep)) {
-       usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY;
-       /* KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY would go here, except
-          that this client code base doesn't ever put a subkey in the
-          tgs_req authenticator, so the tgs_rep is never encrypted in
-          one.  (Check send_tgs.c:krb5_send_tgs_basic(), near the top
-          where authent.subkey is set to 0) */
+       usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY;
        retval = decode_krb5_tgs_rep(enc_rep, &local_dec_rep);
     } else {
        return KRB5KRB_AP_ERR_MSG_TYPE;
index 82972b7fc0ec8e0c5e59e6b0fa5334a72245fa2c..059da828a935300fc1cc39a3acb8746d12b1c986 100644 (file)
@@ -154,6 +154,7 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
     krb5_error *err_reply;
     krb5_response tgsrep;
     krb5_enctype *enctypes = 0;
+    krb5_keyblock *subkey = NULL;
 
 #ifdef DEBUG_REFERRALS
     printf("krb5_get_cred_via_tkt starting; referral flag is %s\n", kdcoptions&KDC_OPT_CANONICALIZE?"on":"off");
@@ -200,12 +201,12 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
        enctypes[1] = 0;
     }
     
-    retval = krb5_send_tgs(context, kdcoptions, &in_cred->times, enctypes, 
+    retval = krb5int_send_tgs(context, kdcoptions, &in_cred->times, enctypes, 
                           in_cred->server, address, in_cred->authdata,
                           0,           /* no padata */
                           (kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) ? 
                           &in_cred->second_ticket : NULL,
-                          tkt, &tgsrep);
+                          tkt, &tgsrep, &subkey);
     if (enctypes)
        free(enctypes);
     if (retval) {
@@ -280,7 +281,7 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
     }
 
     if ((retval = krb5_decode_kdc_rep(context, &tgsrep.response,
-                                     &tkt->keyblock, &dec_rep)))
+                                     subkey, &dec_rep)))
        goto error_4;
 
     if (dec_rep->msg_type != KRB5_TGS_REP) {
@@ -334,6 +335,9 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
                               &in_cred->second_ticket,  out_cred);
 
 error_3:;
+    if (subkey != NULL)
+      krb5_free_keyblock(context, subkey);
+    
     memset(dec_rep->enc_part2->session->contents, 0,
           dec_rep->enc_part2->session->length);
     krb5_free_kdc_rep(context, dec_rep);
index 83914c4989a7768e45f16c01b04c641281ed6495..9a10b92718a7ce4b91a8681fc7c2fe7a924c7ebb 100644 (file)
@@ -30,7 +30,7 @@
 #include "k5-int.h"
 
 /*
- Sends a request to the TGS and waits for a response.
+Constructs a TGS request
  options is used for the options in the KRB_TGS_REQ.
  timestruct values are used for from, till, rtime " " "
  enctype is used for enctype " " ", and to encrypt the authorization data, 
@@ -48,7 +48,8 @@
  returns system errors
  */
 static krb5_error_code 
-krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cred, krb5_data *outbuf)
+tgs_construct_tgsreq(krb5_context context, krb5_data *in_data,
+                   krb5_creds *in_cred, krb5_data *outbuf, krb5_keyblock **subkey)
 {   
     krb5_error_code       retval;
     krb5_checksum         checksum;
@@ -56,6 +57,12 @@ krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cre
     krb5_ap_req          request;
     krb5_data          * scratch;
     krb5_data           * toutbuf;
+    checksum.contents = NULL;
+/* Generate subkey*/
+    if ((retval = krb5_generate_subkey( context, &in_cred->keyblock,
+                                       subkey)) != 0)
+       return retval;
+    
 
     /* Generate checksum */
     if ((retval = krb5_c_make_checksum(context, context->kdc_req_sumtype,
@@ -63,43 +70,42 @@ krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cre
                                       KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
                                       in_data, &checksum))) {
        free(checksum.contents);
-       return(retval);
+       goto cleanup;
     }
 
     /* gen authenticator */
-    authent.subkey = 0;
+    authent.subkey = *subkey; /*owned by caller*/
     authent.seq_number = 0;
     authent.checksum = &checksum;
     authent.client = in_cred->client;
     authent.authorization_data = in_cred->authdata;
     if ((retval = krb5_us_timeofday(context, &authent.ctime,
-                                   &authent.cusec))) {
-        free(checksum.contents);
-       return(retval);
-    }
+                                   &authent.cusec))) 
+       goto cleanup;
+
 
     /* encode the authenticator */
-    if ((retval = encode_krb5_authenticator(&authent, &scratch))) {
-        free(checksum.contents);
-       return(retval);
-    }
+    if ((retval = encode_krb5_authenticator(&authent, &scratch)))
+       goto cleanup;
+
 
     free(checksum.contents);
+    checksum.contents = NULL;
 
-    request.authenticator.ciphertext.data = 0;
+    request.authenticator.ciphertext.data = NULL;
     request.authenticator.kvno = 0;
     request.ap_options = 0;
     request.ticket = 0;
 
     if ((retval = decode_krb5_ticket(&(in_cred)->ticket, &request.ticket)))
        /* Cleanup scratch and scratch data */
-        goto cleanup_data;
+        goto cleanup;
 
     /* call the encryption routine */ 
     if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
                                      KRB5_KEYUSAGE_TGS_REQ_AUTH,
                                      scratch, &request.authenticator)))
-       goto cleanup_ticket;
+       goto cleanup;
 
     retval = encode_krb5_ap_req(&request, &toutbuf);
     *outbuf = *toutbuf;
@@ -110,25 +116,30 @@ krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cre
            request.authenticator.ciphertext.length);
     free(request.authenticator.ciphertext.data);
 
-cleanup_ticket:
+ cleanup:
+if (request.ticket)
     krb5_free_ticket(context, request.ticket);
 
-cleanup_data:
-    memset(scratch->data, 0, scratch->length);
+ if (scratch != NULL && scratch->data != NULL) { 
+zap(scratch->data,  scratch->length);
     free(scratch->data);
-
     free(scratch);
+ }
 
+ if (*subkey && retval != 0) {
+     krb5_free_keyblock(context, *subkey);
+     *subkey = NULL;
+ }
     return retval;
 }
 
 krb5_error_code
-krb5_send_tgs(krb5_context context, krb5_flags kdcoptions,
+krb5int_send_tgs(krb5_context context, krb5_flags kdcoptions,
              const krb5_ticket_times *timestruct, const krb5_enctype *ktypes,
              krb5_const_principal sname, krb5_address *const *addrs,
              krb5_authdata *const *authorization_data,
              krb5_pa_data *const *padata, const krb5_data *second_ticket,
-             krb5_creds *in_cred, krb5_response *rep)
+             krb5_creds *in_cred, krb5_response *rep, krb5_keyblock **subkey)
 {
     krb5_error_code retval;
     krb5_kdc_req tgsreq;
@@ -140,6 +151,8 @@ krb5_send_tgs(krb5_context context, krb5_flags kdcoptions,
     krb5_pa_data ap_req_padata;
     int tcp_only = 0, use_master;
 
+    assert (subkey != NULL);
+    *subkey  = NULL;
     /* 
      * in_creds MUST be a valid credential NOT just a partially filled in
      * place holder for us to get credentials for the caller.
@@ -170,8 +183,8 @@ krb5_send_tgs(krb5_context context, krb5_flags kdcoptions,
        if ((retval = encode_krb5_authdata(authorization_data, &scratch)))
            return(retval);
 
-       if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
-                                         KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
+       if ((retval = krb5_encrypt_helper(context, *subkey,
+                                         KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY,
                                          scratch,
                                          &tgsreq.authorization_data))) {
            free(tgsreq.authorization_data.ciphertext.data);
@@ -212,7 +225,8 @@ krb5_send_tgs(krb5_context context, krb5_flags kdcoptions,
     /*
      * Get an ap_req.
      */
-    if ((retval = krb5_send_tgs_basic(context, scratch, in_cred, &scratch2))) {
+    if ((retval = tgs_construct_tgsreq(context, scratch, in_cred
+                                      , &scratch2, subkey))) {
         krb5_free_data(context, scratch);
        goto send_tgs_error_2;
     }
@@ -275,7 +289,7 @@ send_again:
                    tcp_only = 1;
                    krb5_free_error(context, err_reply);
                    free(rep->response.data);
-                   rep->response.data = 0;
+                   rep->response.data = NULL;
                    goto send_again;
                }
                krb5_free_error(context, err_reply);
@@ -303,6 +317,11 @@ send_tgs_error_1:;
                tgsreq.authorization_data.ciphertext.length); 
        free(tgsreq.authorization_data.ciphertext.data);
     }
+    if (rep->message_type != KRB5_TGS_REP && *subkey){
+       krb5_free_keyblock(context, *subkey);
+       *subkey = NULL;
+    }
+
 
     return retval;
 }
index c69aead5d7f9adfada8ca2bc01141136565043e9..2671ebca577ee5065b1cc79be8e847f30a6c0f71 100644 (file)
@@ -449,7 +449,6 @@ krb5_recvauth_version
 krb5_register_serializer
 krb5_salttype_to_string
 krb5_secure_config_files
-krb5_send_tgs
 krb5_sendauth
 krb5_sendto_kdc
 krb5_ser_address_init