diff options
author | Greg Hudson <ghudson@mit.edu> | 2014-05-08 12:14:42 -0400 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2014-05-17 18:42:39 -0400 |
commit | ba1558660f0cbd8639ac323dac11c52f88ac079d (patch) | |
tree | fa58fef68224c8ea9216698928ca265dd0ff42c5 | |
parent | bff6bbf52401f9464df365d76f0987fbf8101c5e (diff) | |
download | krb5-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.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 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; } |