KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_mk_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *outbuf) { krb5_error_code ret; AP_REP ap; EncAPRepPart body; u_char *buf = NULL; size_t buf_size; size_t len = 0; krb5_crypto crypto; ap.pvno = 5; ap.msg_type = krb_ap_rep; memset (&body, 0, sizeof(body)); body.ctime = auth_context->authenticator->ctime; body.cusec = auth_context->authenticator->cusec; if (auth_context->flags & KRB5_AUTH_CONTEXT_USE_SUBKEY) { if (auth_context->local_subkey == NULL) { ret = krb5_auth_con_generatelocalsubkey(context, auth_context, auth_context->keyblock); if(ret) { free_EncAPRepPart(&body); return ret; } } ret = krb5_copy_keyblock(context, auth_context->local_subkey, &body.subkey); if (ret) { free_EncAPRepPart(&body); return krb5_enomem(context); } } else body.subkey = NULL; if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { if(auth_context->local_seqnumber == 0) krb5_generate_seq_number (context, auth_context->keyblock, &auth_context->local_seqnumber); ALLOC(body.seq_number, 1); if (body.seq_number == NULL) { free_EncAPRepPart(&body); return krb5_enomem(context); } *(body.seq_number) = auth_context->local_seqnumber; } else body.seq_number = NULL; ap.enc_part.etype = auth_context->keyblock->keytype; ap.enc_part.kvno = NULL; ASN1_MALLOC_ENCODE(EncAPRepPart, buf, buf_size, &body, &len, ret); free_EncAPRepPart (&body); if(ret) return ret; if (buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); ret = krb5_crypto_init(context, auth_context->keyblock, 0 /* ap.enc_part.etype */, &crypto); if (ret) { free (buf); return ret; } ret = krb5_encrypt (context, crypto, KRB5_KU_AP_REQ_ENC_PART, buf + buf_size - len, len, &ap.enc_part.cipher); krb5_crypto_destroy(context, crypto); free(buf); if (ret) return ret; ASN1_MALLOC_ENCODE(AP_REP, outbuf->data, outbuf->length, &ap, &len, ret); if (ret == 0 && outbuf->length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); free_AP_REP (&ap); return ret; }
krb5_error_code KRB5_CALLCONV krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context, krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_data *outbuf) { krb5_error_code retval; krb5_checksum checksum; krb5_checksum *checksump = 0; krb5_auth_context new_auth_context; krb5_enctype *desired_etypes = NULL; krb5_ap_req request; krb5_data *scratch = 0; krb5_data *toutbuf; request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK; request.authenticator.ciphertext.data = NULL; request.ticket = 0; if (!in_creds->ticket.length) return(KRB5_NO_TKT_SUPPLIED); if ((ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) && !(ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) return(EINVAL); /* we need a native ticket */ if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket))) return(retval); /* verify that the ticket is not expired */ if ((retval = krb5int_validate_times(context, &in_creds->times)) != 0) goto cleanup; /* generate auth_context if needed */ if (*auth_context == NULL) { if ((retval = krb5_auth_con_init(context, &new_auth_context))) goto cleanup; *auth_context = new_auth_context; } if ((*auth_context)->key != NULL) { krb5_k_free_key(context, (*auth_context)->key); (*auth_context)->key = NULL; } /* set auth context keyblock */ if ((retval = krb5_k_create_key(context, &in_creds->keyblock, &((*auth_context)->key)))) goto cleanup; /* generate seq number if needed */ if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && ((*auth_context)->local_seq_number == 0)) { if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock, &(*auth_context)->local_seq_number))) goto cleanup; } /* generate subkey if needed */ if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->send_subkey)) { retval = k5_generate_and_save_subkey(context, *auth_context, &in_creds->keyblock, in_creds->keyblock.enctype); if (retval) goto cleanup; } if (!in_data && (*auth_context)->checksum_func) { retval = (*auth_context)->checksum_func( context, *auth_context, (*auth_context)->checksum_func_data, &in_data); if (retval) goto cleanup; } if (in_data) { if ((*auth_context)->req_cksumtype == 0x8003) { /* XXX Special hack for GSSAPI */ checksum.checksum_type = 0x8003; checksum.length = in_data->length; checksum.contents = (krb5_octet *) in_data->data; } else { krb5_enctype enctype = krb5_k_key_enctype(context, (*auth_context)->key); krb5_cksumtype cksumtype = ap_req_cksum(context, *auth_context, enctype); if ((retval = krb5_k_make_checksum(context, cksumtype, (*auth_context)->key, KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM, in_data, &checksum))) goto cleanup_cksum; } checksump = &checksum; } /* Generate authenticator */ if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof( krb5_authenticator))) == NULL) { retval = ENOMEM; goto cleanup_cksum; } if (ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) { if ((*auth_context)->permitted_etypes == NULL) { retval = krb5_get_tgs_ktypes(context, in_creds->server, &desired_etypes); if (retval) goto cleanup_cksum; } else desired_etypes = (*auth_context)->permitted_etypes; } TRACE_MK_REQ(context, in_creds, (*auth_context)->local_seq_number, (*auth_context)->send_subkey, &in_creds->keyblock); if ((retval = generate_authenticator(context, (*auth_context)->authentp, in_creds->client, checksump, (*auth_context)->send_subkey, (*auth_context)->local_seq_number, in_creds->authdata, (*auth_context)->ad_context, desired_etypes, in_creds->keyblock.enctype))) goto cleanup_cksum; /* encode the authenticator */ if ((retval = encode_krb5_authenticator((*auth_context)->authentp, &scratch))) goto cleanup_cksum; /* call the encryption routine */ if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock, KRB5_KEYUSAGE_AP_REQ_AUTH, scratch, &request.authenticator))) goto cleanup_cksum; if ((retval = encode_krb5_ap_req(&request, &toutbuf))) goto cleanup_cksum; *outbuf = *toutbuf; free(toutbuf); cleanup_cksum: /* Null out these fields, to prevent pointer sharing problems; * they were supplied by the caller */ if ((*auth_context)->authentp != NULL) { (*auth_context)->authentp->client = NULL; (*auth_context)->authentp->checksum = NULL; } if (checksump && checksump->checksum_type != 0x8003) free(checksump->contents); cleanup: if (desired_etypes && desired_etypes != (*auth_context)->permitted_etypes) free(desired_etypes); if (request.ticket) krb5_free_ticket(context, request.ticket); if (request.authenticator.ciphertext.data) { (void) memset(request.authenticator.ciphertext.data, 0, request.authenticator.ciphertext.length); free(request.authenticator.ciphertext.data); } if (scratch) { memset(scratch->data, 0, scratch->length); free(scratch->data); free(scratch); } return retval; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL _krb5_build_authenticator (krb5_context context, krb5_auth_context auth_context, krb5_enctype enctype, krb5_creds *cred, Checksum *cksum, krb5_data *result, krb5_key_usage usage) { Authenticator auth; u_char *buf = NULL; size_t buf_size; size_t len = 0; krb5_error_code ret; krb5_crypto crypto; memset(&auth, 0, sizeof(auth)); auth.authenticator_vno = 5; copy_Realm(&cred->client->realm, &auth.crealm); copy_PrincipalName(&cred->client->name, &auth.cname); krb5_us_timeofday (context, &auth.ctime, &auth.cusec); ret = krb5_auth_con_getlocalsubkey(context, auth_context, &auth.subkey); if(ret) goto fail; if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { if(auth_context->local_seqnumber == 0) krb5_generate_seq_number (context, &cred->session, &auth_context->local_seqnumber); ALLOC(auth.seq_number, 1); if(auth.seq_number == NULL) { ret = ENOMEM; goto fail; } *auth.seq_number = auth_context->local_seqnumber; } else auth.seq_number = NULL; auth.authorization_data = NULL; if (cksum) { ALLOC(auth.cksum, 1); if (auth.cksum == NULL) { ret = ENOMEM; goto fail; } ret = copy_Checksum(cksum, auth.cksum); if (ret) goto fail; if (auth.cksum->cksumtype == CKSUMTYPE_GSSAPI) { /* * This is not GSS-API specific, we only enable it for * GSS for now */ ret = make_etypelist(context, &auth.authorization_data); if (ret) goto fail; } } /* XXX - Copy more to auth_context? */ auth_context->authenticator->ctime = auth.ctime; auth_context->authenticator->cusec = auth.cusec; ASN1_MALLOC_ENCODE(Authenticator, buf, buf_size, &auth, &len, ret); if (ret) goto fail; if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); ret = krb5_crypto_init(context, &cred->session, enctype, &crypto); if (ret) goto fail; ret = krb5_encrypt (context, crypto, usage /* KRB5_KU_AP_REQ_AUTH */, buf, len, result); krb5_crypto_destroy(context, crypto); if (ret) goto fail; fail: free_Authenticator (&auth); free (buf); return ret; }
static krb5_error_code k5_mk_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *outbuf, int dce_style) { krb5_error_code retval; krb5_ap_rep_enc_part repl; krb5_ap_rep reply; krb5_data * scratch; krb5_data * toutbuf; /* Make the reply */ if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && (auth_context->local_seq_number == 0)) { if ((retval = krb5_generate_seq_number(context, &auth_context->key->keyblock, &auth_context->local_seq_number))) return(retval); } if (dce_style) { krb5_us_timeofday(context, &repl.ctime, &repl.cusec); } else { repl.ctime = auth_context->authentp->ctime; repl.cusec = auth_context->authentp->cusec; } if (dce_style) repl.subkey = NULL; else if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_USE_SUBKEY) { assert(auth_context->negotiated_etype != ENCTYPE_NULL); retval = k5_generate_and_save_subkey(context, auth_context, &auth_context->key->keyblock, auth_context->negotiated_etype); if (retval) return retval; repl.subkey = &auth_context->send_subkey->keyblock; } else repl.subkey = auth_context->authentp->subkey; if (dce_style) repl.seq_number = auth_context->remote_seq_number; else repl.seq_number = auth_context->local_seq_number; TRACE_MK_REP(context, repl.ctime, repl.cusec, repl.subkey, repl.seq_number); /* encode it before encrypting */ if ((retval = encode_krb5_ap_rep_enc_part(&repl, &scratch))) return retval; if ((retval = k5_encrypt_keyhelper(context, auth_context->key, KRB5_KEYUSAGE_AP_REP_ENCPART, scratch, &reply.enc_part))) goto cleanup_scratch; if (!(retval = encode_krb5_ap_rep(&reply, &toutbuf))) { *outbuf = *toutbuf; free(toutbuf); } memset(reply.enc_part.ciphertext.data, 0, reply.enc_part.ciphertext.length); free(reply.enc_part.ciphertext.data); reply.enc_part.ciphertext.length = 0; reply.enc_part.ciphertext.data = 0; cleanup_scratch: memset(scratch->data, 0, scratch->length); krb5_free_data(context, scratch); return retval; }