1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
7 * Provide an interface to assemble and disassemble krb5_cred
12 #include "int-proto.h"
16 #include <stddef.h> /* NULL */
17 #include <stdlib.h> /* malloc */
18 #include <errno.h> /* ENOMEM */
20 /*-------------------- encrypt_credencpart --------------------*/
23 * encrypt the enc_part of krb5_cred
25 static krb5_error_code
26 encrypt_credencpart(krb5_context context, krb5_cred_enc_part *pcredpart,
27 krb5_key pkey, krb5_enc_data *pencdata)
29 krb5_error_code retval;
32 /* start by encoding to-be-encrypted part of the message */
33 if ((retval = encode_krb5_enc_cred_part(pcredpart, &scratch)))
37 * If the keyblock is NULL, just copy the data from the encoded
38 * data to the ciphertext area.
41 pencdata->ciphertext.data = scratch->data;
42 pencdata->ciphertext.length = scratch->length;
47 /* call the encryption routine */
48 retval = k5_encrypt_keyhelper(context, pkey,
49 KRB5_KEYUSAGE_KRB_CRED_ENCPART, scratch,
52 memset(scratch->data, 0, scratch->length);
53 krb5_free_data(context, scratch);
58 /*----------------------- krb5_mk_ncred_basic -----------------------*/
60 static krb5_error_code
61 krb5_mk_ncred_basic(krb5_context context,
62 krb5_creds **ppcreds, krb5_int32 nppcreds,
63 krb5_key key, krb5_replay_data *replaydata,
64 krb5_address *local_addr, krb5_address *remote_addr,
67 krb5_cred_enc_part credenc;
68 krb5_error_code retval;
72 credenc.magic = KV5M_CRED_ENC_PART;
74 credenc.s_address = 0;
75 credenc.r_address = 0;
76 if (local_addr) krb5_copy_addr(context, local_addr, &credenc.s_address);
77 if (remote_addr) krb5_copy_addr(context, remote_addr, &credenc.r_address);
79 credenc.nonce = replaydata->seq;
80 credenc.usec = replaydata->usec;
81 credenc.timestamp = replaydata->timestamp;
83 /* Get memory for creds and initialize it */
84 size = sizeof(krb5_cred_info *) * (nppcreds + 1);
85 credenc.ticket_info = (krb5_cred_info **) calloc(1, size);
86 if (credenc.ticket_info == NULL)
90 * For each credential in the list, initialize a cred info
91 * structure and copy the ticket into the ticket list.
93 for (i = 0; i < nppcreds; i++) {
94 credenc.ticket_info[i] = calloc(1, sizeof(krb5_cred_info));
95 if (credenc.ticket_info[i] == NULL) {
99 credenc.ticket_info[i+1] = NULL;
101 credenc.ticket_info[i]->magic = KV5M_CRED_INFO;
102 credenc.ticket_info[i]->times = ppcreds[i]->times;
103 credenc.ticket_info[i]->flags = ppcreds[i]->ticket_flags;
105 if ((retval = decode_krb5_ticket(&ppcreds[i]->ticket,
106 &pcred->tickets[i])))
109 if ((retval = krb5_copy_keyblock(context, &ppcreds[i]->keyblock,
110 &credenc.ticket_info[i]->session)))
113 if ((retval = krb5_copy_principal(context, ppcreds[i]->client,
114 &credenc.ticket_info[i]->client)))
117 if ((retval = krb5_copy_principal(context, ppcreds[i]->server,
118 &credenc.ticket_info[i]->server)))
121 if ((retval = krb5_copy_addresses(context, ppcreds[i]->addresses,
122 &credenc.ticket_info[i]->caddrs)))
127 * NULL terminate the lists.
129 pcred->tickets[i] = NULL;
131 /* encrypt the credential encrypted part */
132 retval = encrypt_credencpart(context, &credenc, key, &pcred->enc_part);
135 krb5_free_cred_enc_part(context, &credenc);
139 /*----------------------- krb5_mk_ncred -----------------------*/
142 * This functions takes as input an array of krb5_credentials, and
143 * outputs an encoded KRB_CRED message suitable for krb5_rd_cred
145 krb5_error_code KRB5_CALLCONV
146 krb5_mk_ncred(krb5_context context, krb5_auth_context auth_context,
147 krb5_creds **ppcreds, krb5_data **ppdata,
148 krb5_replay_data *outdata)
150 krb5_address * premote_fulladdr = NULL;
151 krb5_address * plocal_fulladdr = NULL;
152 krb5_address remote_fulladdr;
153 krb5_address local_fulladdr;
154 krb5_error_code retval;
156 krb5_replay_data replaydata;
159 krb5_boolean increased_sequence = FALSE;
161 local_fulladdr.contents = 0;
162 remote_fulladdr.contents = 0;
163 memset(&replaydata, 0, sizeof(krb5_replay_data));
166 return KRB5KRB_AP_ERR_BADADDR;
169 * Allocate memory for a NULL terminated list of tickets.
171 for (ncred = 0; ppcreds[ncred]; ncred++)
174 if ((pcred = (krb5_cred *)calloc(1, sizeof(krb5_cred))) == NULL)
178 = (krb5_ticket **)calloc((size_t)ncred+1,
179 sizeof(krb5_ticket *))) == NULL) {
185 if ((key = auth_context->send_subkey) == NULL)
186 key = auth_context->key;
188 /* Get replay info */
189 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
190 (auth_context->rcache == NULL)) {
191 retval = KRB5_RC_REQUIRED;
195 if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
196 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
197 && (outdata == NULL)) {
198 /* Need a better error */
199 retval = KRB5_RC_REQUIRED;
203 if ((retval = krb5_us_timeofday(context, &replaydata.timestamp,
206 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) {
207 outdata->timestamp = replaydata.timestamp;
208 outdata->usec = replaydata.usec;
210 if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
211 (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
212 replaydata.seq = auth_context->local_seq_number++;
213 increased_sequence = TRUE;
214 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)
215 outdata->seq = replaydata.seq;
218 if (auth_context->local_addr) {
219 if (auth_context->local_port) {
220 if ((retval = krb5_make_fulladdr(context, auth_context->local_addr,
221 auth_context->local_port,
224 plocal_fulladdr = &local_fulladdr;
226 plocal_fulladdr = auth_context->local_addr;
230 if (auth_context->remote_addr) {
231 if (auth_context->remote_port) {
232 if ((retval = krb5_make_fulladdr(context,auth_context->remote_addr,
233 auth_context->remote_port,
236 premote_fulladdr = &remote_fulladdr;
238 premote_fulladdr = auth_context->remote_addr;
242 /* Setup creds structure */
243 if ((retval = krb5_mk_ncred_basic(context, ppcreds, ncred, key,
244 &replaydata, plocal_fulladdr,
245 premote_fulladdr, pcred))) {
249 if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
250 krb5_donot_replay replay;
252 if ((retval = krb5_gen_replay_name(context, auth_context->local_addr,
253 "_forw", &replay.client)))
256 replay.server = ""; /* XXX */
257 replay.msghash = NULL;
258 replay.cusec = replaydata.usec;
259 replay.ctime = replaydata.timestamp;
260 if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
261 /* should we really error out here? XXX */
268 /* Encode creds structure */
269 retval = encode_krb5_cred(pcred, ppdata);
272 free(local_fulladdr.contents);
273 free(remote_fulladdr.contents);
274 krb5_free_cred(context, pcred);
277 if (increased_sequence)
278 auth_context->local_seq_number--;
283 /*----------------------- krb5_mk_1cred -----------------------*/
286 * A convenience function that calls krb5_mk_ncred.
288 krb5_error_code KRB5_CALLCONV
289 krb5_mk_1cred(krb5_context context, krb5_auth_context auth_context,
290 krb5_creds *pcreds, krb5_data **ppdata,
291 krb5_replay_data *outdata)
293 krb5_error_code retval;
294 krb5_creds **ppcreds;
296 if ((ppcreds = (krb5_creds **)malloc(sizeof(*ppcreds) * 2)) == NULL) {
303 retval = krb5_mk_ncred(context, auth_context, ppcreds,