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, ¤ttime))) 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