summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2014-05-08 12:14:42 -0400
committerGreg Hudson <ghudson@mit.edu>2014-05-17 18:42:39 -0400
commitba1558660f0cbd8639ac323dac11c52f88ac079d (patch)
treefa58fef68224c8ea9216698928ca265dd0ff42c5
parentbff6bbf52401f9464df365d76f0987fbf8101c5e (diff)
downloadkrb5-ba1558660f0cbd8639ac323dac11c52f88ac079d.tar.gz
krb5-ba1558660f0cbd8639ac323dac11c52f88ac079d.tar.xz
krb5-ba1558660f0cbd8639ac323dac11c52f88ac079d.zip
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.
-rw-r--r--src/lib/krb5/krb/rd_cred.c326
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 acc05c99b..b08108bee 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;
}