xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/rd_cred.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate #include <k5-int.h>
9*7c478bd9Sstevel@tonic-gate #include "cleanup.h"
10*7c478bd9Sstevel@tonic-gate #include <auth_con.h>
11*7c478bd9Sstevel@tonic-gate 
12*7c478bd9Sstevel@tonic-gate #include <stddef.h>           /* NULL */
13*7c478bd9Sstevel@tonic-gate #include <stdlib.h>           /* malloc */
14*7c478bd9Sstevel@tonic-gate #include <errno.h>            /* ENOMEM */
15*7c478bd9Sstevel@tonic-gate 
16*7c478bd9Sstevel@tonic-gate /*-------------------- decrypt_credencdata --------------------*/
17*7c478bd9Sstevel@tonic-gate 
18*7c478bd9Sstevel@tonic-gate /*
19*7c478bd9Sstevel@tonic-gate  * decrypt the enc_part of a krb5_cred
20*7c478bd9Sstevel@tonic-gate  */
21*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22*7c478bd9Sstevel@tonic-gate static krb5_error_code
23*7c478bd9Sstevel@tonic-gate decrypt_credencdata(
24*7c478bd9Sstevel@tonic-gate     krb5_context	  context,
25*7c478bd9Sstevel@tonic-gate     krb5_cred 		* pcred,
26*7c478bd9Sstevel@tonic-gate     krb5_keyblock 	* pkeyblock,
27*7c478bd9Sstevel@tonic-gate     krb5_cred_enc_part 	* pcredenc)
28*7c478bd9Sstevel@tonic-gate {
29*7c478bd9Sstevel@tonic-gate     krb5_cred_enc_part  * ppart = NULL;
30*7c478bd9Sstevel@tonic-gate     krb5_error_code 	  retval;
31*7c478bd9Sstevel@tonic-gate     krb5_data 		  scratch;
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate     scratch.length = pcred->enc_part.ciphertext.length;
34*7c478bd9Sstevel@tonic-gate     if (!(scratch.data = (char *)malloc(scratch.length)))
35*7c478bd9Sstevel@tonic-gate 	return ENOMEM;
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate     if (pkeyblock != NULL) {
38*7c478bd9Sstevel@tonic-gate 	    if ((retval = krb5_c_decrypt(context, pkeyblock,
39*7c478bd9Sstevel@tonic-gate 					KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0,
40*7c478bd9Sstevel@tonic-gate 					&pcred->enc_part, &scratch)))
41*7c478bd9Sstevel@tonic-gate 		goto cleanup;
42*7c478bd9Sstevel@tonic-gate     } else {
43*7c478bd9Sstevel@tonic-gate 	(void) memcpy(scratch.data, pcred->enc_part.ciphertext.data, scratch.length);
44*7c478bd9Sstevel@tonic-gate     }
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate     /*  now decode the decrypted stuff */
47*7c478bd9Sstevel@tonic-gate     if ((retval = decode_krb5_enc_cred_part(&scratch, &ppart)))
48*7c478bd9Sstevel@tonic-gate     	goto cleanup;
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate     /* this is a struct copy so ppart must be freed */
51*7c478bd9Sstevel@tonic-gate     *pcredenc = *ppart;
52*7c478bd9Sstevel@tonic-gate     retval = 0;
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate cleanup:
55*7c478bd9Sstevel@tonic-gate     if (ppart != NULL) {
56*7c478bd9Sstevel@tonic-gate 	memset(ppart, 0, sizeof(*ppart));
57*7c478bd9Sstevel@tonic-gate 	krb5_xfree(ppart);
58*7c478bd9Sstevel@tonic-gate     }
59*7c478bd9Sstevel@tonic-gate     (void) memset(scratch.data, 0, scratch.length);
60*7c478bd9Sstevel@tonic-gate     krb5_xfree(scratch.data);
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate     return retval;
63*7c478bd9Sstevel@tonic-gate }
64*7c478bd9Sstevel@tonic-gate /*----------------------- krb5_rd_cred_basic -----------------------*/
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate static krb5_error_code
67*7c478bd9Sstevel@tonic-gate krb5_rd_cred_basic(
68*7c478bd9Sstevel@tonic-gate     krb5_context          context,
69*7c478bd9Sstevel@tonic-gate     krb5_data		* pcreddata,
70*7c478bd9Sstevel@tonic-gate     krb5_keyblock 	* pkeyblock,
71*7c478bd9Sstevel@tonic-gate     krb5_replay_data    * replaydata,
72*7c478bd9Sstevel@tonic-gate     krb5_creds        *** pppcreds)
73*7c478bd9Sstevel@tonic-gate {
74*7c478bd9Sstevel@tonic-gate     krb5_error_code       retval;
75*7c478bd9Sstevel@tonic-gate     krb5_cred 		* pcred;
76*7c478bd9Sstevel@tonic-gate     krb5_int32 		  ncreds;
77*7c478bd9Sstevel@tonic-gate     krb5_int32 		  i = 0;
78*7c478bd9Sstevel@tonic-gate     krb5_cred_enc_part 	  encpart;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate     /* decode cred message */
81*7c478bd9Sstevel@tonic-gate     if ((retval = decode_krb5_cred(pcreddata, &pcred)))
82*7c478bd9Sstevel@tonic-gate     	return retval;
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate     (void) memset(&encpart, 0, sizeof(encpart));
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate     if ((retval = decrypt_credencdata(context, pcred, pkeyblock, &encpart)))
87*7c478bd9Sstevel@tonic-gate 	goto cleanup_cred;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate     replaydata->timestamp = encpart.timestamp;
90*7c478bd9Sstevel@tonic-gate     replaydata->usec = encpart.usec;
91*7c478bd9Sstevel@tonic-gate     replaydata->seq = encpart.nonce;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate    /*
94*7c478bd9Sstevel@tonic-gate     * Allocate the list of creds.  The memory is allocated so that
95*7c478bd9Sstevel@tonic-gate     * krb5_free_tgt_creds can be used to free the list.
96*7c478bd9Sstevel@tonic-gate     */
97*7c478bd9Sstevel@tonic-gate     for (ncreds = 0; pcred->tickets[ncreds]; ncreds++);
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate     if ((*pppcreds =
100*7c478bd9Sstevel@tonic-gate         (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) *
101*7c478bd9Sstevel@tonic-gate 				       (ncreds + 1)))) == NULL) {
102*7c478bd9Sstevel@tonic-gate         retval = ENOMEM;
103*7c478bd9Sstevel@tonic-gate         goto cleanup_cred;
104*7c478bd9Sstevel@tonic-gate     }
105*7c478bd9Sstevel@tonic-gate     (*pppcreds)[0] = NULL;
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate     /*
108*7c478bd9Sstevel@tonic-gate      * For each credential, create a strcture in the list of
109*7c478bd9Sstevel@tonic-gate      * credentials and copy the information.
110*7c478bd9Sstevel@tonic-gate      */
111*7c478bd9Sstevel@tonic-gate     while (i < ncreds) {
112*7c478bd9Sstevel@tonic-gate         krb5_cred_info 	* pinfo;
113*7c478bd9Sstevel@tonic-gate         krb5_creds 	* pcur;
114*7c478bd9Sstevel@tonic-gate 	krb5_data	* pdata;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate         if ((pcur = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) {
117*7c478bd9Sstevel@tonic-gate 	    retval = ENOMEM;
118*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
119*7c478bd9Sstevel@tonic-gate         }
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate         (*pppcreds)[i] = pcur;
122*7c478bd9Sstevel@tonic-gate         (*pppcreds)[i+1] = 0;
123*7c478bd9Sstevel@tonic-gate         pinfo = encpart.ticket_info[i++];
124*7c478bd9Sstevel@tonic-gate         (void) memset(pcur, 0, sizeof(krb5_creds));
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate         if ((retval = krb5_copy_principal(context, pinfo->client,
127*7c478bd9Sstevel@tonic-gate 					  &pcur->client)))
128*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate         if ((retval = krb5_copy_principal(context, pinfo->server,
131*7c478bd9Sstevel@tonic-gate 					  &pcur->server)))
132*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate       	if ((retval = krb5_copy_keyblock_contents(context, pinfo->session,
135*7c478bd9Sstevel@tonic-gate 						  &pcur->keyblock)))
136*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate         if ((retval = krb5_copy_addresses(context, pinfo->caddrs,
139*7c478bd9Sstevel@tonic-gate 					  &pcur->addresses)))
140*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate         if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata)))
143*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	pcur->ticket = *pdata;
146*7c478bd9Sstevel@tonic-gate 	krb5_xfree(pdata);
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate         pcur->is_skey = FALSE;
150*7c478bd9Sstevel@tonic-gate         pcur->magic = KV5M_CREDS;
151*7c478bd9Sstevel@tonic-gate         pcur->times = pinfo->times;
152*7c478bd9Sstevel@tonic-gate         pcur->ticket_flags = pinfo->flags;
153*7c478bd9Sstevel@tonic-gate         pcur->authdata = NULL;   /* not used */
154*7c478bd9Sstevel@tonic-gate         (void) memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket));
155*7c478bd9Sstevel@tonic-gate     }
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate     /*
158*7c478bd9Sstevel@tonic-gate      * NULL terminate the list
159*7c478bd9Sstevel@tonic-gate      */
160*7c478bd9Sstevel@tonic-gate     (*pppcreds)[i] = NULL;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate cleanup:
163*7c478bd9Sstevel@tonic-gate     if (retval)
164*7c478bd9Sstevel@tonic-gate 	krb5_free_tgt_creds(context, *pppcreds);
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate cleanup_cred:
167*7c478bd9Sstevel@tonic-gate     krb5_free_cred(context, pcred);
168*7c478bd9Sstevel@tonic-gate     krb5_free_cred_enc_part(context, &encpart);
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate     return retval;
171*7c478bd9Sstevel@tonic-gate }
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate /*----------------------- krb5_rd_cred -----------------------*/
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate #define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew)
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate /*
178*7c478bd9Sstevel@tonic-gate  * This functions takes as input an KRB_CRED message, validates it, and
179*7c478bd9Sstevel@tonic-gate  * outputs the nonce and an array of the forwarded credentials.
180*7c478bd9Sstevel@tonic-gate  */
181*7c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
182*7c478bd9Sstevel@tonic-gate krb5_rd_cred(
183*7c478bd9Sstevel@tonic-gate     krb5_context          context,
184*7c478bd9Sstevel@tonic-gate     krb5_auth_context     auth_context,
185*7c478bd9Sstevel@tonic-gate     krb5_data 		* pcreddata,
186*7c478bd9Sstevel@tonic-gate     krb5_creds        * * * pppcreds,
187*7c478bd9Sstevel@tonic-gate     krb5_replay_data  	* outdata)
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate     krb5_error_code       retval;
190*7c478bd9Sstevel@tonic-gate     krb5_keyblock       * keyblock;
191*7c478bd9Sstevel@tonic-gate     krb5_replay_data      replaydata;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate     /* Get keyblock */
194*7c478bd9Sstevel@tonic-gate     if ((keyblock = auth_context->recv_subkey) == NULL)
195*7c478bd9Sstevel@tonic-gate 	keyblock = auth_context->keyblock;
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate     if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
198*7c478bd9Sstevel@tonic-gate       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
199*7c478bd9Sstevel@tonic-gate       (outdata == NULL))
200*7c478bd9Sstevel@tonic-gate         /* Need a better error */
201*7c478bd9Sstevel@tonic-gate         return KRB5_RC_REQUIRED;
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
204*7c478bd9Sstevel@tonic-gate       (auth_context->rcache == NULL))
205*7c478bd9Sstevel@tonic-gate         return KRB5_RC_REQUIRED;
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate     /*
208*7c478bd9Sstevel@tonic-gate      * If decrypting with the first keyblock we try fails, perhaps the
209*7c478bd9Sstevel@tonic-gate      * credentials are stored in the session key so try decrypting with
210*7c478bd9Sstevel@tonic-gate      * that.
211*7c478bd9Sstevel@tonic-gate      */
212*7c478bd9Sstevel@tonic-gate     if ((retval = krb5_rd_cred_basic(context, pcreddata, keyblock,
213*7c478bd9Sstevel@tonic-gate                                      &replaydata, pppcreds))) {
214*7c478bd9Sstevel@tonic-gate 	if ((retval = krb5_rd_cred_basic(context, pcreddata,
215*7c478bd9Sstevel@tonic-gate                                          auth_context->keyblock,
216*7c478bd9Sstevel@tonic-gate                                          &replaydata, pppcreds))) {
217*7c478bd9Sstevel@tonic-gate             return retval;
218*7c478bd9Sstevel@tonic-gate     	}
219*7c478bd9Sstevel@tonic-gate     }
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
223*7c478bd9Sstevel@tonic-gate         krb5_donot_replay replay;
224*7c478bd9Sstevel@tonic-gate         krb5_timestamp currenttime;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate         if ((retval = krb5_timeofday(context, &currenttime)))
227*7c478bd9Sstevel@tonic-gate             goto error;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate         if (!in_clock_skew(replaydata.timestamp)) {
230*7c478bd9Sstevel@tonic-gate             retval =  KRB5KRB_AP_ERR_SKEW;
231*7c478bd9Sstevel@tonic-gate             goto error;
232*7c478bd9Sstevel@tonic-gate         }
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate         if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr,
235*7c478bd9Sstevel@tonic-gate 					   "_forw", &replay.client)))
236*7c478bd9Sstevel@tonic-gate             goto error;
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate         replay.server = "";             /* XXX */
239*7c478bd9Sstevel@tonic-gate         replay.cusec = replaydata.usec;
240*7c478bd9Sstevel@tonic-gate         replay.ctime = replaydata.timestamp;
241*7c478bd9Sstevel@tonic-gate         if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
242*7c478bd9Sstevel@tonic-gate 		krb5_xfree(replay.client);
243*7c478bd9Sstevel@tonic-gate 		goto error;
244*7c478bd9Sstevel@tonic-gate         }
245*7c478bd9Sstevel@tonic-gate         krb5_xfree(replay.client);
246*7c478bd9Sstevel@tonic-gate     }
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
249*7c478bd9Sstevel@tonic-gate         if (auth_context->remote_seq_number != replaydata.seq) {
250*7c478bd9Sstevel@tonic-gate             retval =  KRB5KRB_AP_ERR_BADORDER;
251*7c478bd9Sstevel@tonic-gate             goto error;
252*7c478bd9Sstevel@tonic-gate         }
253*7c478bd9Sstevel@tonic-gate         auth_context->remote_seq_number++;
254*7c478bd9Sstevel@tonic-gate     }
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
257*7c478bd9Sstevel@tonic-gate       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
258*7c478bd9Sstevel@tonic-gate         outdata->timestamp = replaydata.timestamp;
259*7c478bd9Sstevel@tonic-gate         outdata->usec = replaydata.usec;
260*7c478bd9Sstevel@tonic-gate         outdata->seq = replaydata.seq;
261*7c478bd9Sstevel@tonic-gate     }
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate error:
264*7c478bd9Sstevel@tonic-gate     if (retval) {
265*7c478bd9Sstevel@tonic-gate 	krb5_free_tgt_creds(context, *pppcreds);
266*7c478bd9Sstevel@tonic-gate 	*pppcreds = NULL;
267*7c478bd9Sstevel@tonic-gate     }
268*7c478bd9Sstevel@tonic-gate     return retval;
269*7c478bd9Sstevel@tonic-gate }
270