1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/rd_cred.c - definition of krb5_rd_cred() */
4 * Copyright 1994-2009,2014 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
35 * Decrypt and decode the enc_part of a krb5_cred using the receiving subkey or
36 * the session key of authcon. If neither key is present, ctext->ciphertext is
37 * assumed to be unencrypted plain text.
39 static krb5_error_code
40 decrypt_encpart(krb5_context context, krb5_enc_data *ctext,
41 krb5_auth_context authcon, krb5_cred_enc_part **encpart_out)
44 krb5_data plain = empty_data();
45 krb5_boolean decrypted = FALSE;
49 if (authcon->recv_subkey == NULL && authcon->key == NULL)
50 return decode_krb5_enc_cred_part(&ctext->ciphertext, encpart_out);
52 ret = alloc_data(&plain, ctext->ciphertext.length);
55 if (authcon->recv_subkey != NULL) {
56 ret = krb5_k_decrypt(context, authcon->recv_subkey,
57 KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0, ctext, &plain);
58 decrypted = (ret == 0);
60 if (!decrypted && authcon->key != NULL) {
61 ret = krb5_k_decrypt(context, authcon->key,
62 KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0, ctext, &plain);
63 decrypted = (ret == 0);
66 ret = decode_krb5_enc_cred_part(&plain, encpart_out);
67 zapfree(plain.data, plain.length);
71 /* Produce a list of credentials from a KRB-CRED message and its enc_part. */
72 static krb5_error_code
73 make_cred_list(krb5_context context, krb5_cred *krbcred,
74 krb5_cred_enc_part *encpart, krb5_creds ***creds_out)
76 krb5_error_code ret = 0;
77 krb5_creds **list = NULL;
79 krb5_data *ticket_data;
84 /* Allocate the list of creds. */
85 for (count = 0; krbcred->tickets[count] != NULL; count++);
86 list = k5calloc(count + 1, sizeof(*list), &ret);
90 /* For each credential, create a strcture in the list of credentials and
91 * copy the information. */
92 for (i = 0; i < count; i++) {
93 list[i] = k5alloc(sizeof(*list[i]), &ret);
97 info = encpart->ticket_info[i];
98 ret = krb5_copy_principal(context, info->client, &list[i]->client);
102 ret = krb5_copy_principal(context, info->server, &list[i]->server);
106 ret = krb5_copy_keyblock_contents(context, info->session,
111 ret = krb5_copy_addresses(context, info->caddrs, &list[i]->addresses);
115 ret = encode_krb5_ticket(krbcred->tickets[i], &ticket_data);
118 list[i]->ticket = *ticket_data;
121 list[i]->is_skey = FALSE;
122 list[i]->magic = KV5M_CREDS;
123 list[i]->times = info->times;
124 list[i]->ticket_flags = info->flags;
125 list[i]->authdata = NULL;
126 list[i]->second_ticket = empty_data();
133 krb5_free_tgt_creds(context, list);
137 /* Validate a KRB-CRED message in creddata, and return a list of forwarded
138 * credentials along with replay cache information. */
139 krb5_error_code KRB5_CALLCONV
140 krb5_rd_cred(krb5_context context, krb5_auth_context authcon,
141 krb5_data *creddata, krb5_creds ***creds_out,
142 krb5_replay_data *replaydata_out)
144 krb5_error_code ret = 0;
145 krb5_creds **credlist = NULL;
146 krb5_cred *krbcred = NULL;
147 krb5_cred_enc_part *encpart = NULL;
148 krb5_donot_replay replay;
149 const krb5_int32 flags = authcon->auth_context_flags;
153 if (((flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
154 (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
155 replaydata_out == NULL)
156 return KRB5_RC_REQUIRED;
158 if ((flags & KRB5_AUTH_CONTEXT_DO_TIME) && authcon->rcache == NULL)
159 return KRB5_RC_REQUIRED;
161 ret = decode_krb5_cred(creddata, &krbcred);
165 ret = decrypt_encpart(context, &krbcred->enc_part, authcon, &encpart);
169 ret = make_cred_list(context, krbcred, encpart, &credlist);
173 if (flags & KRB5_AUTH_CONTEXT_DO_TIME) {
174 ret = krb5_check_clockskew(context, encpart->timestamp);
178 ret = krb5_gen_replay_name(context, authcon->remote_addr, "_forw",
184 replay.msghash = NULL;
185 replay.cusec = encpart->usec;
186 replay.ctime = encpart->timestamp;
187 ret = krb5_rc_store(context, authcon->rcache, &replay);
193 if (flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
194 if (authcon->remote_seq_number != (uint32_t)encpart->nonce) {
195 ret = KRB5KRB_AP_ERR_BADORDER;
198 authcon->remote_seq_number++;
201 *creds_out = credlist;
203 if ((flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
204 (flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
205 replaydata_out->timestamp = encpart->timestamp;
206 replaydata_out->usec = encpart->usec;
207 replaydata_out->seq = encpart->nonce;
211 krb5_free_tgt_creds(context, credlist);
212 krb5_free_cred(context, krbcred);
213 krb5_free_cred_enc_part(context, encpart);
214 free(encpart); /* krb5_free_cred_enc_part doesn't do this */