This commit was manufactured by cvs2svn to create tag
[krb5.git] / src / lib / krb5 / krb / mk_req_ext.c
index 13003a704a15b0da8e3f20a90e849dcd176f768d..88daab56704bd2d734af8da6004204e412a30260 100644 (file)
  * this permission notice appear in supporting documentation, and that
  * the name of M.I.T. not be used in advertising or publicity pertaining
  * to distribution of the software without specific, written prior
- * permission.  M.I.T. makes no representations about the suitability of
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
  * this software for any purpose.  It is provided "as is" without express
  * or implied warranty.
  * 
  */
 
 
-#include <krb5/krb5.h>
-#include <krb5/asn1.h>
-
-#include <krb5/libos.h>
-#include <krb5/los-proto.h>
-
-#include <krb5/ext-proto.h>
+#include "k5-int.h"
+#include "auth_con.h"
 
 /*
  Formats a KRB_AP_REQ message into outbuf, with more complete options than
 */
 
 static krb5_error_code 
-krb5_generate_authenticator PROTOTYPE(( krb5_authenticator *, krb5_principal,
+krb5_generate_authenticator PROTOTYPE((krb5_context,
+                                      krb5_authenticator *, krb5_principal,
                                       const krb5_checksum *, krb5_keyblock *,
                                       krb5_int32, krb5_authdata ** ));
 
-krb5_error_code
-krb5_mk_req_extended(ap_req_options, checksum, kdc_options,
-                    sequence, newkey, ccache, creds, authentp, outbuf)
-const krb5_flags ap_req_options;
-const krb5_checksum *checksum;
-const krb5_flags kdc_options;
-krb5_int32 sequence;
-krb5_keyblock **newkey;
-krb5_ccache ccache;
-krb5_creds *creds;
-krb5_authenticator *authentp;
-krb5_data *outbuf;
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, in_creds,
+                    outbuf)
+    krb5_context         context;
+    krb5_auth_context  FAR * auth_context;
+    const krb5_flags     ap_req_options;
+    krb5_data          FAR * in_data;
+    krb5_creds                 FAR * in_creds;
+    krb5_data          FAR * outbuf;
 {
-    krb5_error_code retval;
+    krb5_error_code      retval;
+    krb5_checksum        checksum;
+    krb5_checksum        *checksump = 0;
+    krb5_auth_context    new_auth_context;
+
     krb5_ap_req request;
-    krb5_authenticator authent;
-    krb5_data *scratch;
-    krb5_enctype etype;
-    krb5_encrypt_block eblock;
+    krb5_data *scratch = 0;
     krb5_data *toutbuf;
 
-    if ((ap_req_options & AP_OPTS_USE_SESSION_KEY) &&
-       !creds->ticket.length)
+    request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
+    request.authenticator.ciphertext.data = 0;
+    request.ticket = 0;
+    
+    if (!in_creds->ticket.length) 
        return(KRB5_NO_TKT_SUPPLIED);
 
-    if (!creds->ticket.length) {
-       /* go get creds */
-       if (retval = krb5_get_credentials(kdc_options,
-                                         ccache,
-                                         creds))
-           return(retval);
-    }
-    /* verify a valid etype is available */
-    if (!valid_keytype(creds->keyblock.keytype))
-       return KRB5_PROG_KEYTYPE_NOSUPP;
-
-    if (creds->keyblock.etype == ETYPE_UNKNOWN)
-       etype = krb5_keytype_array[creds->keyblock.keytype]->system->proto_enctype;
-    else
-       etype = creds->keyblock.etype;
-
-    if (!valid_etype(etype))
-       return KRB5_PROG_ETYPE_NOSUPP;
-
-    request.ap_options = ap_req_options;
     /* we need a native ticket */
-    if (retval = decode_krb5_ticket(&creds->ticket, &request.ticket))
+    if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
        return(retval);
+    
+    /* verify that the ticket is not expired */
+    if ((retval = krb5_validate_times(context, &in_creds->times)) != 0)
+       goto cleanup;
+
+    /* generate auth_context if needed */
+    if (*auth_context == NULL) {
+       if ((retval = krb5_auth_con_init(context, &new_auth_context)))
+           goto cleanup;
+       *auth_context = new_auth_context;
+    }
 
-#define cleanup_ticket() krb5_free_ticket(request.ticket)
-    if (newkey) {
-       if (retval = krb5_generate_subkey(&creds->keyblock, newkey)) {
-           cleanup_ticket();
-           return retval;
+    /* set auth context keyblock */
+    if ((retval = krb5_copy_keyblock(context, &in_creds->keyblock, 
+                                    &((*auth_context)->keyblock))))
+       goto cleanup;
+
+    /* generate seq number if needed */
+    if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
+     || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
+      && ((*auth_context)->local_seq_number == 0)) 
+       if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock,
+                                    &(*auth_context)->local_seq_number)))
+           goto cleanup;
+       
+
+    /* generate subkey if needed */
+    if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->local_subkey)) {
+       /* Provide some more fodder for random number code.
+          This isn't strong cryptographically; the point here is not
+          to guarantee randomness, but to make it less likely that multiple
+          sessions could pick the same subkey.  */
+       struct {
+           krb5_int32 sec, usec;
+       } rnd_data;
+       krb5_data d;
+       krb5_crypto_us_timeofday (&rnd_data.sec, &rnd_data.usec);
+       d.length = sizeof (rnd_data);
+       d.data = (char *) &rnd_data;
+       (void) krb5_c_random_seed (context, &d);
+
+       if ((retval = krb5_generate_subkey(context, &(in_creds)->keyblock, 
+                                          &(*auth_context)->local_subkey)))
+           goto cleanup;
+    }
+
+    if (in_data) {
+       if ((*auth_context)->req_cksumtype == 0x8003) {
+           /* XXX Special hack for GSSAPI */
+           checksum.checksum_type = 0x8003;
+           checksum.length = in_data->length;
+           checksum.contents = (krb5_octet *) in_data->data;
+       } else {
+           if ((retval = krb5_c_make_checksum(context, 
+                                              (*auth_context)->req_cksumtype,
+                                              (*auth_context)->keyblock,
+                                              KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
+                                              in_data, &checksum)))
+               goto cleanup_cksum;
        }
+       checksump = &checksum;
     }
-#define cleanup_key() {if (newkey) krb5_free_keyblock(*newkey);}
-    if (retval = krb5_generate_authenticator(&authent, creds->client, checksum,
-                                            newkey ? *newkey : 0,
-                                            sequence, creds->authdata)) {
-       cleanup_key();
-       cleanup_ticket();
-       return retval;
+
+    /* Generate authenticator */
+    if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof(
+                                       krb5_authenticator))) == NULL) {
+       retval = ENOMEM;
+       goto cleanup_cksum;
     }
-    
+
+    if ((retval = krb5_generate_authenticator(context,
+                                             (*auth_context)->authentp,
+                                             (in_creds)->client, checksump,
+                                             (*auth_context)->local_subkey,
+                                             (*auth_context)->local_seq_number,
+                                             (in_creds)->authdata)))
+       goto cleanup_cksum;
+       
     /* encode the authenticator */
-    retval = encode_krb5_authenticator(&authent, &scratch);
-    if (retval) {
-       cleanup_key();
-       cleanup_ticket();
-       return(retval);
-    }
+    if ((retval = encode_krb5_authenticator((*auth_context)->authentp,
+                                           &scratch)))
+       goto cleanup_cksum;
     
     /* Null out these fields, to prevent pointer sharing problems;
      * they were supplied by the caller
      */
-    authent.client = NULL;
-    authent.checksum = NULL;
-    authent.authorization_data = NULL;
-    if (authentp)
-           *authentp = authent;
-    else
-           krb5_free_authenticator_contents(&authent);
-
-#define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \
-krb5_free_data(scratch); }
-
-    /* put together an eblock for this encryption */
-
-    krb5_use_cstype(&eblock, etype);
-    request.authenticator.etype = etype;
-    request.authenticator.kvno = 0; /* XXX user set? */
-    request.authenticator.ciphertext.length =
-       krb5_encrypt_size(scratch->length, eblock.crypto_entry);
-    /* add padding area, and zero it */
-    if (!(scratch->data = realloc(scratch->data,
-                                 request.authenticator.ciphertext.length))) {
-       /* may destroy scratch->data */
-       krb5_xfree(scratch);
-       retval = ENOMEM;
-       goto clean_ticket;
-    }
-    memset(scratch->data + scratch->length, 0,
-         request.authenticator.ciphertext.length - scratch->length);
-    if (!(request.authenticator.ciphertext.data =
-         malloc(request.authenticator.ciphertext.length))) {
-       retval = ENOMEM;
-       goto clean_scratch;
-    }
-
-#define cleanup_encpart() {\
-(void) memset(request.authenticator.ciphertext.data, 0,\
-            request.authenticator.ciphertext.length); \
-free(request.authenticator.ciphertext.data); \
-request.authenticator.ciphertext.length = 0; \
-request.authenticator.ciphertext.data = 0;}
-
-    /* do any necessary key pre-processing */
-    if (retval = krb5_process_key(&eblock, &creds->keyblock)) {
-       goto clean_encpart;
-    }
-
-#define cleanup_prockey() {(void) krb5_finish_key(&eblock);}
+    (*auth_context)->authentp->client = NULL;
+    (*auth_context)->authentp->checksum = NULL;
+    (*auth_context)->authentp->authorization_data = NULL;
 
     /* call the encryption routine */
-    if (retval = krb5_encrypt((krb5_pointer) scratch->data,
-                             (krb5_pointer) request.authenticator.ciphertext.data,
-                             scratch->length, &eblock, 0)) {
-       goto clean_prockey;
+    if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
+                                     KRB5_KEYUSAGE_AP_REQ_AUTH,
+                                     scratch, &request.authenticator)))
+       goto cleanup_cksum;
+
+    if ((retval = encode_krb5_ap_req(&request, &toutbuf)))
+       goto cleanup_cksum;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *outbuf = *toutbuf;
+#else
+    memcpy(outbuf, toutbuf, sizeof(krb5_data));
+#endif
+
+    krb5_xfree(toutbuf);
+
+cleanup_cksum:
+    if (checksump && checksump->checksum_type != 0x8003)
+      free(checksump->contents);
+
+cleanup:
+    if (request.ticket)
+       krb5_free_ticket(context, request.ticket);
+    if (request.authenticator.ciphertext.data) {
+       (void) memset(request.authenticator.ciphertext.data, 0,
+                     request.authenticator.ciphertext.length);
+       free(request.authenticator.ciphertext.data);
     }
-
-    /* authenticator now assembled-- do some cleanup */
-    cleanup_scratch();
-
-    if (retval = krb5_finish_key(&eblock)) {
-       cleanup_encpart();
-       return retval;
-    }
-
-    if (!(retval = encode_krb5_ap_req(&request, &toutbuf))) {
-       *outbuf = *toutbuf;
-       krb5_xfree(toutbuf);
+    if (scratch) {
+       memset(scratch->data, 0, scratch->length);
+        krb5_xfree(scratch->data);
+       krb5_xfree(scratch);
     }
-    cleanup_ticket();
-    cleanup_encpart();
-    return retval;
-
- clean_prockey:
-    cleanup_prockey();
- clean_encpart:
-    cleanup_encpart();
- clean_scratch:
-    cleanup_scratch();
- clean_ticket:
-    cleanup_key();
-    cleanup_ticket();
-
     return retval;
 }
 
 static krb5_error_code
-krb5_generate_authenticator(authent, client, cksum, key, seq_number, authorization)
-krb5_authenticator *authent;
-krb5_principal client;
-const krb5_checksum *cksum;
-krb5_keyblock *key;
-krb5_int32 seq_number;
-krb5_authdata **authorization;
+krb5_generate_authenticator(context, authent, client, cksum, key, seq_number, authorization)
+    krb5_context context;
+    krb5_authenticator *authent;
+    krb5_principal client;
+    const krb5_checksum *cksum;
+    krb5_keyblock *key;
+    krb5_int32 seq_number;
+    krb5_authdata **authorization;
 {
     krb5_error_code retval;
     
     authent->client = client;
     authent->checksum = (krb5_checksum *)cksum;
     if (key) {
-       retval = krb5_copy_keyblock(key, &authent->subkey);
+       retval = krb5_copy_keyblock(context, key, &authent->subkey);
        if (retval)
            return retval;
     } else
        authent->subkey = 0;
-    authent->subkey = key;
     authent->seq_number = seq_number;
     authent->authorization_data = authorization;
 
-    return(krb5_us_timeofday(&authent->ctime, &authent->cusec));
+    return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));
 }