krb5 commit: Modernize rd_cred.c

Greg Hudson ghudson at MIT.EDU
Sat May 17 18:43:32 EDT 2014


https://github.com/krb5/krb5/commit/ba1558660f0cbd8639ac323dac11c52f88ac079d
commit ba1558660f0cbd8639ac323dac11c52f88ac079d
Author: Greg Hudson <ghudson at mit.edu>
Date:   Thu May 8 12:14:42 2014 -0400

    Modernize rd_cred.c
    
    Adjust the internal abstractions so that decrypt_encpart is
    responsible for the fallback from receiving subkey to session key, and
    krb5_rd_cred is responsible for decoding and calling decrypt_encpart.
    Rename krb5_rd_cred_basic to make_cred_list since it is now only
    responsible for constructing the list.

 src/lib/krb5/krb/rd_cred.c |  326 +++++++++++++++++++-------------------------
 1 files changed, 138 insertions(+), 188 deletions(-)

diff --git a/src/lib/krb5/krb/rd_cred.c b/src/lib/krb5/krb/rd_cred.c
index acc05c9..b08108b 100644
--- a/src/lib/krb5/krb/rd_cred.c
+++ b/src/lib/krb5/krb/rd_cred.c
@@ -1,7 +1,7 @@
 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /* lib/krb5/krb/rd_cred.c - definition of krb5_rd_cred() */
 /*
- * Copyright 1994-2009 by the Massachusetts Institute of Technology.
+ * Copyright 1994-2009,2014 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -28,239 +28,189 @@
 #include "cleanup.h"
 #include "auth_con.h"
 
-#include <stddef.h>           /* NULL */
-#include <stdlib.h>           /* malloc */
-#include <errno.h>            /* ENOMEM */
-
-/*-------------------- decrypt_credencdata --------------------*/
+#include <stdlib.h>
+#include <errno.h>
 
 /*
- * decrypt the enc_part of a krb5_cred
+ * Decrypt and decode the enc_part of a krb5_cred using the receiving subkey or
+ * the session key of authcon.  If neither key is present, ctext->ciphertext is
+ * assumed to be unencrypted plain text.
  */
 static krb5_error_code
-decrypt_credencdata(krb5_context context, krb5_cred *pcred,
-                    krb5_key pkey, krb5_cred_enc_part *pcredenc)
+decrypt_encpart(krb5_context context, krb5_enc_data *ctext,
+                krb5_auth_context authcon, krb5_cred_enc_part **encpart_out)
 {
-    krb5_cred_enc_part  * ppart = NULL;
-    krb5_error_code       retval = 0;
-    krb5_data             scratch;
-
-    scratch.length = pcred->enc_part.ciphertext.length;
-    if (!(scratch.data = (char *)malloc(scratch.length)))
-        return ENOMEM;
-
-    if (pkey != NULL) {
-        if ((retval = krb5_k_decrypt(context, pkey,
-                                     KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0,
-                                     &pcred->enc_part, &scratch)))
-            goto cleanup;
-    } else {
-        memcpy(scratch.data, pcred->enc_part.ciphertext.data, scratch.length);
+    krb5_error_code ret;
+    krb5_data plain = empty_data();
+    krb5_boolean decrypted = FALSE;
+
+    *encpart_out = NULL;
+
+    if (authcon->recv_subkey == NULL && authcon->key == NULL)
+        return decode_krb5_enc_cred_part(&ctext->ciphertext, encpart_out);
+
+    ret = alloc_data(&plain, ctext->ciphertext.length);
+    if (ret)
+        return ret;
+    if (authcon->recv_subkey != NULL) {
+        ret = krb5_k_decrypt(context, authcon->recv_subkey,
+                             KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0, ctext, &plain);
+        decrypted = (ret == 0);
     }
-
-    /*  now decode the decrypted stuff */
-    if ((retval = decode_krb5_enc_cred_part(&scratch, &ppart)))
-        goto cleanup;
-
-    *pcredenc = *ppart;
-
-cleanup:
-    if (ppart != NULL) {
-        memset(ppart, 0, sizeof(*ppart));
-        free(ppart);
+    if (!decrypted && authcon->key != NULL) {
+        ret = krb5_k_decrypt(context, authcon->key,
+                             KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0, ctext, &plain);
+        decrypted = (ret == 0);
     }
-    memset(scratch.data, 0, scratch.length);
-    free(scratch.data);
-
-    return retval;
+    if (decrypted)
+        ret = decode_krb5_enc_cred_part(&plain, encpart_out);
+    zapfree(plain.data, plain.length);
+    return ret;
 }
-/*----------------------- krb5_rd_cred_basic -----------------------*/
 
+/* Produce a list of credentials from a KRB-CRED message and its enc_part. */
 static krb5_error_code
-krb5_rd_cred_basic(krb5_context context, krb5_data *pcreddata,
-                   krb5_key pkey, krb5_replay_data *replaydata,
-                   krb5_creds ***pppcreds)
+make_cred_list(krb5_context context, krb5_cred *krbcred,
+               krb5_cred_enc_part *encpart, krb5_creds ***creds_out)
 {
-    krb5_error_code       retval = 0;
-    krb5_cred           * pcred = NULL;
-    krb5_int32            ncreds = 0;
-    krb5_int32            i = 0;
-    krb5_cred_enc_part    encpart;
-
-    /* decode cred message */
-    if ((retval = decode_krb5_cred(pcreddata, &pcred)))
-        return retval;
-
-    memset(&encpart, 0, sizeof(encpart));
-
-    if ((retval = decrypt_credencdata(context, pcred, pkey, &encpart)))
-        goto cleanup_cred;
-
-
-    replaydata->timestamp = encpart.timestamp;
-    replaydata->usec = encpart.usec;
-    replaydata->seq = encpart.nonce;
-
-    /*
-     * Allocate the list of creds.  The memory is allocated so that
-     * krb5_free_tgt_creds can be used to free the list.
-     */
-    for (ncreds = 0; pcred->tickets[ncreds]; ncreds++);
-
-    if ((*pppcreds =
-         (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) *
-                                        (ncreds + 1)))) == NULL) {
-        retval = ENOMEM;
-        goto cleanup_cred;
-    }
-    (*pppcreds)[0] = NULL;
-
-    /*
-     * For each credential, create a strcture in the list of
-     * credentials and copy the information.
-     */
-    while (i < ncreds) {
-        krb5_cred_info  * pinfo;
-        krb5_creds      * pcur;
-        krb5_data       * pdata;
+    krb5_error_code ret = 0;
+    krb5_creds **list = NULL;
+    krb5_cred_info *info;
+    krb5_data *ticket_data;
+    size_t i, count;
+
+    *creds_out = NULL;
+
+    /* Allocate the list of creds. */
+    for (count = 0; krbcred->tickets[count] != NULL; count++);
+    list = k5calloc(count + 1, sizeof(*list), &ret);
+    if (list == NULL)
+        goto cleanup;
 
-        if ((pcur = (krb5_creds *)calloc(1, sizeof(krb5_creds))) == NULL) {
-            retval = ENOMEM;
+    /* For each credential, create a strcture in the list of credentials and
+     * copy the information. */
+    for (i = 0; i < count; i++) {
+        list[i] = k5alloc(sizeof(*list[i]), &ret);
+        if (list[i] == NULL)
             goto cleanup;
-        }
-
-        (*pppcreds)[i] = pcur;
-        (*pppcreds)[i+1] = 0;
-        pinfo = encpart.ticket_info[i++];
 
-        if ((retval = krb5_copy_principal(context, pinfo->client,
-                                          &pcur->client)))
+        info = encpart->ticket_info[i];
+        ret = krb5_copy_principal(context, info->client, &list[i]->client);
+        if (ret)
             goto cleanup;
 
-        if ((retval = krb5_copy_principal(context, pinfo->server,
-                                          &pcur->server)))
+        ret = krb5_copy_principal(context, info->server, &list[i]->server);
+        if (ret)
             goto cleanup;
 
-        if ((retval = krb5_copy_keyblock_contents(context, pinfo->session,
-                                                  &pcur->keyblock)))
+        ret = krb5_copy_keyblock_contents(context, info->session,
+                                          &list[i]->keyblock);
+        if (ret)
             goto cleanup;
 
-        if ((retval = krb5_copy_addresses(context, pinfo->caddrs,
-                                          &pcur->addresses)))
+        ret = krb5_copy_addresses(context, info->caddrs, &list[i]->addresses);
+        if (ret)
             goto cleanup;
 
-        if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata)))
+        ret = encode_krb5_ticket(krbcred->tickets[i], &ticket_data);
+        if (ret)
             goto cleanup;
-
-        pcur->ticket = *pdata;
-        free(pdata);
-
-
-        pcur->is_skey = FALSE;
-        pcur->magic = KV5M_CREDS;
-        pcur->times = pinfo->times;
-        pcur->ticket_flags = pinfo->flags;
-        pcur->authdata = NULL;   /* not used */
-        memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket));
+        list[i]->ticket = *ticket_data;
+        free(ticket_data);
+
+        list[i]->is_skey = FALSE;
+        list[i]->magic = KV5M_CREDS;
+        list[i]->times = info->times;
+        list[i]->ticket_flags = info->flags;
+        list[i]->authdata = NULL;
+        list[i]->second_ticket = empty_data();
     }
 
-    /*
-     * NULL terminate the list
-     */
-    (*pppcreds)[i] = NULL;
+    *creds_out = list;
+    list = NULL;
 
 cleanup:
-    if (retval) {
-        krb5_free_tgt_creds(context, *pppcreds);
-        *pppcreds = NULL;
-    }
-
-cleanup_cred:
-    krb5_free_cred(context, pcred);
-    krb5_free_cred_enc_part(context, &encpart);
-
-    return retval;
+    krb5_free_tgt_creds(context, list);
+    return ret;
 }
 
-/*----------------------- krb5_rd_cred -----------------------*/
-
-/*
- * This functions takes as input an KRB_CRED message, validates it, and
- * outputs the array of the forwarded credentials and replay cache information
- */
+/* Validate a KRB-CRED message in creddata, and return a list of forwarded
+ * credentials along with replay cache information. */
 krb5_error_code KRB5_CALLCONV
-krb5_rd_cred(krb5_context context, krb5_auth_context auth_context,
-             krb5_data *pcreddata, krb5_creds ***pppcreds,
-             krb5_replay_data *outdata)
+krb5_rd_cred(krb5_context context, krb5_auth_context authcon,
+             krb5_data *creddata, krb5_creds ***creds_out,
+             krb5_replay_data *replaydata_out)
 {
-    krb5_error_code       retval = 0;
-    krb5_replay_data      replaydata;
-
-    if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
-         (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
-        (outdata == NULL))
-        /* Need a better error */
+    krb5_error_code ret = 0;
+    krb5_creds **credlist = NULL;
+    krb5_cred *krbcred = NULL;
+    krb5_cred_enc_part *encpart = NULL;
+    krb5_donot_replay replay;
+    const krb5_int32 flags = authcon->auth_context_flags;
+
+    *creds_out = NULL;
+
+    if (((flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+         (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+        replaydata_out == NULL)
         return KRB5_RC_REQUIRED;
 
-    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
-        (auth_context->rcache == NULL))
+    if ((flags & KRB5_AUTH_CONTEXT_DO_TIME) && authcon->rcache == NULL)
         return KRB5_RC_REQUIRED;
 
-    /*
-     * If decrypting with the subsession key fails, perhaps the
-     * credentials are stored in the session key so try decrypting with that.
-     */
-    if (auth_context->recv_subkey == NULL ||
-        (retval = krb5_rd_cred_basic(context, pcreddata,
-                                     auth_context->recv_subkey,
-                                     &replaydata, pppcreds))) {
-        retval = krb5_rd_cred_basic(context, pcreddata,
-                                    auth_context->key,
-                                    &replaydata, pppcreds);
-        if (retval)
-            return retval;
-    }
+    ret = decode_krb5_cred(creddata, &krbcred);
+    if (ret)
+        goto cleanup;
+
+    ret = decrypt_encpart(context, &krbcred->enc_part, authcon, &encpart);
+    if (ret)
+        goto cleanup;
 
-    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
-        krb5_donot_replay replay;
+    ret = make_cred_list(context, krbcred, encpart, &credlist);
+    if (ret)
+        goto cleanup;
 
-        if ((retval = krb5_check_clockskew(context, replaydata.timestamp)))
-            goto error;
+    if (flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+        ret = krb5_check_clockskew(context, encpart->timestamp);
+        if (ret)
+            goto cleanup;
 
-        if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr,
-                                           "_forw", &replay.client)))
-            goto error;
+        ret = krb5_gen_replay_name(context, authcon->remote_addr, "_forw",
+                                   &replay.client);
+        if (ret)
+            goto cleanup;
 
-        replay.server = "";             /* XXX */
+        replay.server = "";
         replay.msghash = NULL;
-        replay.cusec = replaydata.usec;
-        replay.ctime = replaydata.timestamp;
-        if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
-            free(replay.client);
-            goto error;
-        }
+        replay.cusec = encpart->usec;
+        replay.ctime = encpart->timestamp;
+        ret = krb5_rc_store(context, authcon->rcache, &replay);
         free(replay.client);
+        if (ret)
+            goto cleanup;
     }
 
-    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
-        if (auth_context->remote_seq_number != replaydata.seq) {
-            retval =  KRB5KRB_AP_ERR_BADORDER;
-            goto error;
+    if (flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+        if (authcon->remote_seq_number != (uint32_t)encpart->nonce) {
+            ret = KRB5KRB_AP_ERR_BADORDER;
+            goto cleanup;
         }
-        auth_context->remote_seq_number++;
+        authcon->remote_seq_number++;
     }
 
-    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
-        (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
-        outdata->timestamp = replaydata.timestamp;
-        outdata->usec = replaydata.usec;
-        outdata->seq = replaydata.seq;
+    *creds_out = credlist;
+    credlist = NULL;
+    if ((flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+        (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
+        replaydata_out->timestamp = encpart->timestamp;
+        replaydata_out->usec = encpart->usec;
+        replaydata_out->seq = encpart->nonce;
     }
 
-error:;
-    if (retval) {
-        krb5_free_tgt_creds(context, *pppcreds);
-        *pppcreds = NULL;
-    }
-    return retval;
+cleanup:
+    krb5_free_tgt_creds(context, credlist);
+    krb5_free_cred(context, krbcred);
+    krb5_free_cred_enc_part(context, encpart);
+    free(encpart);              /* krb5_free_cred_enc_part doesn't do this */
+    return ret;
 }


More information about the cvs-krb5 mailing list