Пример #1
0
static krb5_error_code
encrypt_fast_reply(struct kdc_request_state *state,
                   const krb5_fast_response *response,
                   krb5_data **fx_fast_reply)
{
    krb5_error_code retval = 0;
    krb5_enc_data encrypted_reply;
    krb5_data *encoded_response = NULL;
    kdc_realm_t *kdc_active_realm = state->realm_data;

    assert(state->armor_key);
    retval = encode_krb5_fast_response(response, &encoded_response);
    if (retval== 0)
        retval = krb5_encrypt_helper(kdc_context, state->armor_key,
                                     KRB5_KEYUSAGE_FAST_REP,
                                     encoded_response, &encrypted_reply);
    if (encoded_response)
        krb5_free_data(kdc_context, encoded_response);
    encoded_response = NULL;
    if (retval == 0) {
        retval = encode_krb5_pa_fx_fast_reply(&encrypted_reply,
                                              fx_fast_reply);
        krb5_free_data_contents(kdc_context, &encrypted_reply.ciphertext);
    }
    return retval;
}
Пример #2
0
krb5_error_code
krb5_encrypt_tkt_part(krb5_context context, const krb5_keyblock *srv_key,
                      krb5_ticket *dec_ticket)
{
    krb5_data *scratch;
    krb5_error_code retval;
    krb5_enc_tkt_part *dec_tkt_part = dec_ticket->enc_part2;

    /*  start by encoding the to-be-encrypted part. */
    if ((retval = encode_krb5_enc_tkt_part(dec_tkt_part, &scratch))) {
        return retval;
    }

#define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \
        krb5_free_data(context, scratch); }

    /* call the encryption routine */
    retval = krb5_encrypt_helper(context, srv_key,
                                 KRB5_KEYUSAGE_KDC_REP_TICKET, scratch,
                                 &dec_ticket->enc_part);

    cleanup_scratch();

    return(retval);
}
Пример #3
0
static krb5_error_code
return_pkinit_kx(krb5_context context, krb5_kdc_req *request,
                 krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
                 krb5_pa_data **out_padata)
{
    krb5_error_code ret = 0;
    krb5_keyblock *session = reply->ticket->enc_part2->session;
    krb5_keyblock *new_session = NULL;
    krb5_pa_data *pa = NULL;
    krb5_enc_data enc;
    krb5_data *scratch = NULL;

    *out_padata = NULL;
    enc.ciphertext.data = NULL;
    if (!krb5_principal_compare(context, request->client,
                                krb5_anonymous_principal()))
        return 0;
    /*
     * The KDC contribution key needs to be a fresh key of an enctype supported
     * by the client and server. The existing session key meets these
     * requirements so we use it.
     */
    ret = krb5_c_fx_cf2_simple(context, session, "PKINIT",
                               encrypting_key, "KEYEXCHANGE",
                               &new_session);
    if (ret)
        goto cleanup;
    ret = encode_krb5_encryption_key( session, &scratch);
    if (ret)
        goto cleanup;
    ret = krb5_encrypt_helper(context, encrypting_key,
                              KRB5_KEYUSAGE_PA_PKINIT_KX, scratch, &enc);
    if (ret)
        goto cleanup;
    memset(scratch->data, 0, scratch->length);
    krb5_free_data(context, scratch);
    scratch = NULL;
    ret = encode_krb5_enc_data(&enc, &scratch);
    if (ret)
        goto cleanup;
    pa = malloc(sizeof(krb5_pa_data));
    if (pa == NULL) {
        ret = ENOMEM;
        goto cleanup;
    }
    pa->pa_type = KRB5_PADATA_PKINIT_KX;
    pa->length = scratch->length;
    pa->contents = (krb5_octet *) scratch->data;
    *out_padata = pa;
    scratch->data = NULL;
    memset(session->contents, 0, session->length);
    krb5_free_keyblock_contents(context, session);
    *session = *new_session;
    new_session->contents = NULL;
cleanup:
    krb5_free_data_contents(context, &enc.ciphertext);
    krb5_free_keyblock(context, new_session);
    krb5_free_data(context, scratch);
    return ret;
}
Пример #4
0
/*
 * This routine is the "obtain" function for the ENC_TIMESTAMP
 * preauthentication type.  It take the current time and encrypts it
 * in the user's key.
 */
static krb5_error_code
obtain_enc_ts_padata(krb5_context context, krb5_pa_data *in_padata, krb5_etype_info etype_info, krb5_keyblock *def_enc_key, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request, krb5_pa_data **out_padata)
{
    krb5_pa_enc_ts		pa_enc;
    krb5_error_code		retval;
    krb5_data *			scratch;
    krb5_enc_data 		enc_data;
    krb5_pa_data *		pa;

    retval = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec);
    if (retval)
	return retval;

    if ((retval = encode_krb5_pa_enc_ts(&pa_enc, &scratch)) != 0)
	return retval;

    enc_data.ciphertext.data = 0;

    if ((retval = krb5_encrypt_helper(context, def_enc_key,
				      KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
				      scratch, &enc_data)))
	goto cleanup;

    krb5_free_data(context, scratch);
    scratch = 0;
    
    if ((retval = encode_krb5_enc_data(&enc_data, &scratch)) != 0)
	goto cleanup;

    if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) {
	retval = ENOMEM;
	goto cleanup;
    }

    pa->magic = KV5M_PA_DATA;
    pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
    pa->length = scratch->length;
    pa->contents = (krb5_octet *) scratch->data;

    *out_padata = pa;

    free(scratch);
    scratch = 0;

    retval = 0;
    
cleanup:
    if (scratch)
	krb5_free_data(context, scratch);
    if (enc_data.ciphertext.data)
	free(enc_data.ciphertext.data);
    return retval;
}
Пример #5
0
static krb5_error_code
ec_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt,
          krb5_kdc_req *request, krb5_kdc_rep *reply,
          krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
          krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
          krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
{
    krb5_error_code retval = 0;
    krb5_keyblock *challenge_key = (krb5_keyblock *)modreq;
    krb5_pa_enc_ts ts;
    krb5_data *plain = NULL;
    krb5_enc_data enc;
    krb5_data *encoded = NULL;
    krb5_pa_data *pa = NULL;

    if (challenge_key == NULL)
        return 0;
    enc.ciphertext.data = NULL; /* In case of error pass through */

    retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec);
    if (retval == 0)
        retval = encode_krb5_pa_enc_ts(&ts, &plain);
    if (retval == 0)
        retval = krb5_encrypt_helper(context, challenge_key,
                                     KRB5_KEYUSAGE_ENC_CHALLENGE_KDC,
                                     plain, &enc);
    if (retval == 0)
        retval = encode_krb5_enc_data(&enc, &encoded);
    if (retval == 0) {
        pa = calloc(1, sizeof(krb5_pa_data));
        if (pa == NULL)
            retval = ENOMEM;
    }
    if (retval == 0) {
        pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE;
        pa->contents = (unsigned char *) encoded->data;
        pa->length = encoded->length;
        encoded->data = NULL;
        *send_pa = pa;
        pa = NULL;
    }
    if (challenge_key)
        krb5_free_keyblock(context, challenge_key);
    if (encoded)
        krb5_free_data(context, encoded);
    if (plain)
        krb5_free_data(context, plain);
    if (enc.ciphertext.data)
        krb5_free_data_contents(context, &enc.ciphertext);
    return retval;
}
Пример #6
0
/* Takes the nonce from the challenge and encrypts it into the request. */
static krb5_error_code
encrypt_nonce(krb5_context ctx, krb5_keyblock *key,
              const krb5_pa_otp_challenge *chl, krb5_pa_otp_req *req)
{
    krb5_error_code retval;
    krb5_enc_data encdata;
    krb5_data *er;

    /* Encode the nonce. */
    retval = encode_krb5_pa_otp_enc_req(&chl->nonce, &er);
    if (retval != 0)
        return retval;

    /* Do the encryption. */
    retval = krb5_encrypt_helper(ctx, key, KRB5_KEYUSAGE_PA_OTP_REQUEST,
                                 er, &encdata);
    krb5_free_data(ctx, er);
    if (retval != 0)
        return retval;

    req->enc_data = encdata;
    return 0;
}
Пример #7
0
/* Construct an AP-REQ message for a TGS request. */
static krb5_error_code
tgs_construct_ap_req(krb5_context context, krb5_data *checksum_data,
                     krb5_creds *tgt, krb5_keyblock *subkey,
                     krb5_data **ap_req_asn1_out)
{
    krb5_cksumtype cksumtype;
    krb5_error_code ret;
    krb5_checksum checksum;
    krb5_authenticator authent;
    krb5_ap_req ap_req;
    krb5_data *authent_asn1 = NULL;
    krb5_ticket *ticket = NULL;
    krb5_enc_data authent_enc;

    *ap_req_asn1_out = NULL;
    memset(&checksum, 0, sizeof(checksum));
    memset(&ap_req, 0, sizeof(ap_req));
    memset(&authent_enc, 0, sizeof(authent_enc));

    /* Determine the authenticator checksum type. */
    switch (tgt->keyblock.enctype) {
    case ENCTYPE_DES_CBC_CRC:
    case ENCTYPE_DES_CBC_MD4:
    case ENCTYPE_DES_CBC_MD5:
    case ENCTYPE_ARCFOUR_HMAC:
    case ENCTYPE_ARCFOUR_HMAC_EXP:
        cksumtype = context->kdc_req_sumtype;
        break;
    default:
        ret = krb5int_c_mandatory_cksumtype(context, tgt->keyblock.enctype,
                                            &cksumtype);
        if (ret)
            goto cleanup;
    }

    /* Generate checksum. */
    ret = krb5_c_make_checksum(context, cksumtype, &tgt->keyblock,
                               KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, checksum_data,
                               &checksum);
    if (ret)
        goto cleanup;

    /* Construct, encode, and encrypt an authenticator. */
    authent.subkey = subkey;
    authent.seq_number = 0;
    authent.checksum = &checksum;
    authent.client = tgt->client;
    authent.authorization_data = tgt->authdata;
    ret = krb5_us_timeofday(context, &authent.ctime, &authent.cusec);
    if (ret)
        goto cleanup;
    ret = encode_krb5_authenticator(&authent, &authent_asn1);
    if (ret)
        goto cleanup;
    ret = krb5_encrypt_helper(context, &tgt->keyblock,
                              KRB5_KEYUSAGE_TGS_REQ_AUTH, authent_asn1,
                              &authent_enc);
    if (ret)
        goto cleanup;

    ret = decode_krb5_ticket(&tgt->ticket, &ticket);
    if (ret)
        goto cleanup;

    /* Encode the AP-REQ. */
    ap_req.authenticator = authent_enc;
    ap_req.ticket = ticket;
    ret = encode_krb5_ap_req(&ap_req, ap_req_asn1_out);

cleanup:
    free(checksum.contents);
    krb5_free_ticket(context, ticket);
    krb5_free_data_contents(context, &authent_enc.ciphertext);
    if (authent_asn1 != NULL)
        zapfree(authent_asn1->data, authent_asn1->length);
    free(authent_asn1);
    return ret;
}
Пример #8
0
/*
 * Construct a TGS request and return its ASN.1 encoding as well as the
 * timestamp, nonce, and subkey used.  The pacb_fn callback allows the caller
 * to amend the request padata after the nonce and subkey are determined.
 */
krb5_error_code
k5_make_tgs_req(krb5_context context,
                struct krb5int_fast_request_state *fast_state,
                krb5_creds *tgt, krb5_flags kdcoptions,
                krb5_address *const *addrs, krb5_pa_data **in_padata,
                krb5_creds *desired, k5_pacb_fn pacb_fn, void *pacb_data,
                krb5_data *req_asn1_out, krb5_timestamp *timestamp_out,
                krb5_int32 *nonce_out, krb5_keyblock **subkey_out)
{
    krb5_error_code ret;
    krb5_kdc_req req;
    krb5_data *authdata_asn1 = NULL, *req_body_asn1 = NULL;
    krb5_data *ap_req_asn1 = NULL, *tgs_req_asn1 = NULL;
    krb5_ticket *sec_ticket = NULL;
    krb5_ticket *sec_ticket_arr[2];
    krb5_timestamp time_now;
    krb5_pa_data **padata = NULL, *pa;
    krb5_keyblock *subkey = NULL;
    krb5_enc_data authdata_enc;
    krb5_enctype enctypes[2], *defenctypes = NULL;
    size_t count, i;

    *req_asn1_out = empty_data();
    *timestamp_out = 0;
    *nonce_out = 0;
    *subkey_out = NULL;
    memset(&req, 0, sizeof(req));
    memset(&authdata_enc, 0, sizeof(authdata_enc));

    /* tgt's client principal must match the desired client principal. */
    if (!krb5_principal_compare(context, tgt->client, desired->client))
        return KRB5_PRINC_NOMATCH;

    /* tgt must be an actual credential, not a template. */
    if (!tgt->ticket.length)
        return KRB5_NO_TKT_SUPPLIED;

    req.kdc_options = kdcoptions;
    req.server = desired->server;
    req.from = desired->times.starttime;
    req.till = desired->times.endtime ? desired->times.endtime :
        tgt->times.endtime;
    req.rtime = desired->times.renew_till;
    ret = krb5_timeofday(context, &time_now);
    if (ret)
        return ret;
    *nonce_out = req.nonce = (krb5_int32)time_now;
    *timestamp_out = time_now;

    req.addresses = (krb5_address **)addrs;

    /* Generate subkey. */
    ret = krb5_generate_subkey(context, &tgt->keyblock, &subkey);
    if (ret)
        return ret;
    TRACE_SEND_TGS_SUBKEY(context, subkey);

    ret = krb5int_fast_tgs_armor(context, fast_state, subkey, &tgt->keyblock,
                                 NULL, NULL);
    if (ret)
        goto cleanup;

    if (desired->authdata != NULL) {
        ret = encode_krb5_authdata(desired->authdata, &authdata_asn1);
        if (ret)
            goto cleanup;
        ret = krb5_encrypt_helper(context, subkey,
                                  KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY,
                                  authdata_asn1, &authdata_enc);
        if (ret)
            goto cleanup;
        req.authorization_data = authdata_enc;
    }

    if (desired->keyblock.enctype != ENCTYPE_NULL) {
        if (!krb5_c_valid_enctype(desired->keyblock.enctype)) {
            ret = KRB5_PROG_ETYPE_NOSUPP;
            goto cleanup;
        }
        enctypes[0] = desired->keyblock.enctype;
        enctypes[1] = ENCTYPE_NULL;
        req.ktype = enctypes;
        req.nktypes = 1;
    } else {
        /* Get the default TGS enctypes. */
        ret = krb5_get_tgs_ktypes(context, desired->server, &defenctypes);
        if (ret)
            goto cleanup;
        for (count = 0; defenctypes[count]; count++);
        req.ktype = defenctypes;
        req.nktypes = count;
    }
    TRACE_SEND_TGS_ETYPES(context, req.ktype);

    if (kdcoptions & (KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)) {
        if (desired->second_ticket.length == 0) {
            ret = KRB5_NO_2ND_TKT;
            goto cleanup;
        }
        ret = decode_krb5_ticket(&desired->second_ticket, &sec_ticket);
        if (ret)
            goto cleanup;
        sec_ticket_arr[0] = sec_ticket;
        sec_ticket_arr[1] = NULL;
        req.second_ticket = sec_ticket_arr;
    }

    /* Encode the request body. */
    ret = krb5int_fast_prep_req_body(context, fast_state, &req,
                                     &req_body_asn1);
    if (ret)
        goto cleanup;

    ret = tgs_construct_ap_req(context, req_body_asn1, tgt, subkey,
                               &ap_req_asn1);
    if (ret)
        goto cleanup;

    for (count = 0; in_padata != NULL && in_padata[count] != NULL; count++);

    /* Construct a padata array for the request, beginning with the ap-req. */
    padata = k5calloc(count + 2, sizeof(krb5_pa_data *), &ret);
    if (padata == NULL)
        goto cleanup;
    padata[0] = k5alloc(sizeof(krb5_pa_data), &ret);
    if (padata[0] == NULL)
        goto cleanup;
    padata[0]->pa_type = KRB5_PADATA_AP_REQ;
    padata[0]->contents = k5memdup(ap_req_asn1->data, ap_req_asn1->length,
                                   &ret);
    if (padata[0] == NULL)
        goto cleanup;
    padata[0]->length = ap_req_asn1->length;

    /* Append copies of any other supplied padata. */
    for (i = 0; in_padata != NULL && in_padata[i] != NULL; i++) {
        pa = k5alloc(sizeof(krb5_pa_data), &ret);
        if (pa == NULL)
            goto cleanup;
        pa->pa_type = in_padata[i]->pa_type;
        pa->length = in_padata[i]->length;
        pa->contents = k5memdup(in_padata[i]->contents, in_padata[i]->length,
                                &ret);
        if (pa->contents == NULL)
            goto cleanup;
        padata[i + 1] = pa;
    }
    req.padata = padata;

    if (pacb_fn != NULL) {
        ret = (*pacb_fn)(context, subkey, &req, pacb_data);
        if (ret)
            goto cleanup;
    }

    /* Encode the TGS-REQ.  Discard the krb5_data container. */
    ret = krb5int_fast_prep_req(context, fast_state, &req, ap_req_asn1,
                                encode_krb5_tgs_req, &tgs_req_asn1);
    if (ret)
        goto cleanup;
    *req_asn1_out = *tgs_req_asn1;
    free(tgs_req_asn1);
    tgs_req_asn1 = NULL;

    *subkey_out = subkey;
    subkey = NULL;

cleanup:
    krb5_free_data(context, authdata_asn1);
    krb5_free_data(context, req_body_asn1);
    krb5_free_data(context, ap_req_asn1);
    krb5_free_pa_data(context, req.padata);
    krb5_free_ticket(context, sec_ticket);
    krb5_free_data_contents(context, &authdata_enc.ciphertext);
    krb5_free_keyblock(context, subkey);
    free(defenctypes);
    return ret;
}
Пример #9
0
krb5_error_code
krb5int_fast_prep_req(krb5_context context,
                      struct krb5int_fast_request_state *state,
                      krb5_kdc_req *request,
                      const krb5_data *to_be_checksummed,
                      kdc_req_encoder_proc encoder,
                      krb5_data **encoded_request)
{
    krb5_error_code retval = 0;
    krb5_pa_data *pa_array[2];
    krb5_pa_data pa[2];
    krb5_fast_req fast_req;
    krb5_fast_armored_req *armored_req = NULL;
    krb5_data *encoded_fast_req = NULL;
    krb5_data *encoded_armored_req = NULL;
    krb5_data *local_encoded_result = NULL;
    krb5_data random_data;
    char random_buf[4];

    assert(state != NULL);
    assert(state->fast_outer_request.padata == NULL);
    memset(pa_array, 0, sizeof pa_array);
    if (state->armor_key == NULL) {
        return encoder(request, encoded_request);
    }

    TRACE_FAST_ENCODE(context);
    /* Fill in a fresh random nonce for each inner request*/
    random_data.length = 4;
    random_data.data = (char *)random_buf;
    retval = krb5_c_random_make_octets(context, &random_data);
    if (retval == 0) {
        request->nonce = 0x7fffffff & load_32_n(random_buf);
        state->nonce = request->nonce;
    }
    fast_req.req_body =  request;
    if (fast_req.req_body->padata == NULL) {
        fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *));
        if (fast_req.req_body->padata == NULL)
            retval = ENOMEM;
    }
    fast_req.fast_options = state->fast_options;
    if (retval == 0)
        retval = encode_krb5_fast_req(&fast_req, &encoded_fast_req);
    if (retval == 0) {
        armored_req = calloc(1, sizeof(krb5_fast_armored_req));
        if (armored_req == NULL)
            retval = ENOMEM;
    }
    if (retval == 0)
        armored_req->armor = state->armor;
    if (retval ==0)
        retval = krb5_c_make_checksum(context, 0, state->armor_key,
                                      KRB5_KEYUSAGE_FAST_REQ_CHKSUM,
                                      to_be_checksummed,
                                      &armored_req->req_checksum);
    if (retval == 0)
        retval = krb5_encrypt_helper(context, state->armor_key,
                                     KRB5_KEYUSAGE_FAST_ENC, encoded_fast_req,
                                     &armored_req->enc_part);
    if (retval == 0)
        retval = encode_krb5_pa_fx_fast_request(armored_req,
                                                &encoded_armored_req);
    if (retval==0) {
        pa[0].pa_type = KRB5_PADATA_FX_FAST;
        pa[0].contents = (unsigned char *) encoded_armored_req->data;
        pa[0].length = encoded_armored_req->length;
        pa_array[0] = &pa[0];
    }
    state->fast_outer_request.padata = pa_array;
    if(retval == 0)
        retval = encoder(&state->fast_outer_request, &local_encoded_result);
    if (retval == 0) {
        *encoded_request = local_encoded_result;
        local_encoded_result = NULL;
    }
    if (encoded_armored_req)
        krb5_free_data(context, encoded_armored_req);
    if (armored_req) {
        armored_req->armor = NULL; /*owned by state*/
        krb5_free_fast_armored_req(context, armored_req);
    }
    if (encoded_fast_req)
        krb5_free_data(context, encoded_fast_req);
    if (local_encoded_result)
        krb5_free_data(context, local_encoded_result);
    state->fast_outer_request.padata = NULL;
    return retval;
}
Пример #10
0
/* due to argument promotion rules, we need to use the DECLARG/OLDDECLARG
   stuff... */
krb5_error_code
krb5_encode_kdc_rep(krb5_context context, krb5_msgtype type,
		    const krb5_enc_kdc_rep_part *encpart,
		    int using_subkey, const krb5_keyblock *client_key,
		    krb5_kdc_rep *dec_rep, krb5_data **enc_rep)
{
    krb5_data *scratch;
    krb5_error_code retval;
    krb5_enc_kdc_rep_part tmp_encpart;
    krb5_keyusage usage;

    if (!krb5_c_valid_enctype(dec_rep->enc_part.enctype))
	return KRB5_PROG_ETYPE_NOSUPP;

    switch (type) {
    case KRB5_AS_REP:
	usage = KRB5_KEYUSAGE_AS_REP_ENCPART;
	break;
    case KRB5_TGS_REP:
	if (using_subkey)
	    usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY;
	else
	    usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY;
	break;
    default:
	return KRB5_BADMSGTYPE;
    }

    /*
     * We don't want to modify encpart, but we need to be able to pass
     * in the message type to the encoder, so it can set the ASN.1
     * type correct.
     * 
     * Although note that it may be doing nothing with the message
     * type, to be compatible with old versions of Kerberos that always
     * encode this as a TGS_REP regardly of what it really should be;
     * also note that the reason why we are passing it in a structure
     * instead of as an argument to encode_krb5_enc_kdc_rep_part (the
     * way we should) is for compatibility with the ISODE version of
     * this fuction.  Ah, compatibility....
     */
    tmp_encpart = *encpart;
    tmp_encpart.msg_type = type;
    retval = encode_krb5_enc_kdc_rep_part(&tmp_encpart, &scratch);
    if (retval) {
	return retval;
    }
    memset(&tmp_encpart, 0, sizeof(tmp_encpart));

#define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \
krb5_free_data(context, scratch); }

    retval = krb5_encrypt_helper(context, client_key, usage, scratch,
				 &dec_rep->enc_part);

#define cleanup_encpart() { \
(void) memset(dec_rep->enc_part.ciphertext.data, 0, \
	     dec_rep->enc_part.ciphertext.length); \
free(dec_rep->enc_part.ciphertext.data); \
dec_rep->enc_part.ciphertext.length = 0; \
dec_rep->enc_part.ciphertext.data = 0;}

    cleanup_scratch();

    if (retval)
	return(retval);

    /* now it's ready to be encoded for the wire! */

    switch (type) {
    case KRB5_AS_REP:
	retval = encode_krb5_as_rep(dec_rep, enc_rep);
	break;
    case KRB5_TGS_REP:
	retval = encode_krb5_tgs_rep(dec_rep, enc_rep);
	break;
    }

    if (retval)
	cleanup_encpart();

    return retval;
}
Пример #11
0
/*
 * Solaris Kerberos
 * Same as krb5_send_tgs plus an extra arg to return the FQDN
 * of the KDC sent the request.
 */
krb5_error_code
krb5_send_tgs2(krb5_context context, krb5_flags kdcoptions,
	      const krb5_ticket_times *timestruct, const krb5_enctype *ktypes,
	      krb5_const_principal sname, krb5_address *const *addrs,
	      krb5_authdata *const *authorization_data,
	      krb5_pa_data *const *padata, const krb5_data *second_ticket,
	    krb5_creds *in_cred, krb5_response *rep, char **hostname_used)
{
    krb5_error_code retval;
    krb5_kdc_req tgsreq;
    krb5_data *scratch, scratch2;
    krb5_ticket *sec_ticket = 0;
    krb5_ticket *sec_ticket_arr[2];
    krb5_timestamp time_now;
    krb5_pa_data **combined_padata;
    krb5_pa_data ap_req_padata;
    int tcp_only = 0, use_master;

    /* 
     * in_creds MUST be a valid credential NOT just a partially filled in
     * place holder for us to get credentials for the caller.
     */
    if (!in_cred->ticket.length)
        return(KRB5_NO_TKT_SUPPLIED);

    memset((char *)&tgsreq, 0, sizeof(tgsreq));

    tgsreq.kdc_options = kdcoptions;
    tgsreq.server = (krb5_principal) sname;

    tgsreq.from = timestruct->starttime;
    tgsreq.till = timestruct->endtime ? timestruct->endtime :
	    in_cred->times.endtime;
    tgsreq.rtime = timestruct->renew_till;
    if ((retval = krb5_timeofday(context, &time_now)))
	return(retval);
    /* XXX we know they are the same size... */
    rep->expected_nonce = tgsreq.nonce = (krb5_int32) time_now;
    rep->request_time = time_now;

    tgsreq.addresses = (krb5_address **) addrs;

    if (authorization_data) {
	/* need to encrypt it in the request */

	if ((retval = encode_krb5_authdata(authorization_data,
					   &scratch)))
	    return(retval);

	if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
					  KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
					  scratch,
					  &tgsreq.authorization_data))) {
	    krb5_xfree(tgsreq.authorization_data.ciphertext.data);
	    krb5_free_data(context, scratch);
	    return retval;
	}

	krb5_free_data(context, scratch);
    }

    /* Get the encryption types list */
    if (ktypes) {
	/* Check passed ktypes and make sure they're valid. */
   	for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
    	    if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes]))
		return KRB5_PROG_ETYPE_NOSUPP;
	}
    	tgsreq.ktype = (krb5_enctype *)ktypes;
    } else {
        /* Get the default ktypes */
	/* Solaris Kerberos */
	if ((retval = krb5_get_tgs_ktypes(context, sname, &(tgsreq.ktype))))
		goto send_tgs_error_2;
	for(tgsreq.nktypes = 0; tgsreq.ktype[tgsreq.nktypes]; tgsreq.nktypes++);
    }

    if (second_ticket) {
	if ((retval = decode_krb5_ticket(second_ticket, &sec_ticket)))
	    goto send_tgs_error_1;
	sec_ticket_arr[0] = sec_ticket;
	sec_ticket_arr[1] = 0;
	tgsreq.second_ticket = sec_ticket_arr;
    } else
	tgsreq.second_ticket = 0;

    /* encode the body; then checksum it */
    if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch)))
	goto send_tgs_error_2;

    /*
     * Get an ap_req.
     */
    if ((retval = krb5_send_tgs_basic(context, scratch, in_cred, &scratch2))) {
        krb5_free_data(context, scratch);
	goto send_tgs_error_2;
    }
    krb5_free_data(context, scratch);

    ap_req_padata.pa_type = KRB5_PADATA_AP_REQ;
    ap_req_padata.length = scratch2.length;
    ap_req_padata.contents = (krb5_octet *)scratch2.data;

    /* combine in any other supplied padata */
    if (padata) {
	krb5_pa_data * const * counter;
	register unsigned int i = 0;
	for (counter = padata; *counter; counter++, i++);
	combined_padata = malloc((i+2) * sizeof(*combined_padata));
	if (!combined_padata) {
	    krb5_xfree(ap_req_padata.contents);
	    retval = ENOMEM;
	    goto send_tgs_error_2;
	}
	combined_padata[0] = &ap_req_padata;
	for (i = 1, counter = padata; *counter; counter++, i++)
	    combined_padata[i] = (krb5_pa_data *) *counter;
	combined_padata[i] = 0;
    } else {
	combined_padata = (krb5_pa_data **)malloc(2*sizeof(*combined_padata));
	if (!combined_padata) {
	    krb5_xfree(ap_req_padata.contents);
	    retval = ENOMEM;
	    goto send_tgs_error_2;
	}
	combined_padata[0] = &ap_req_padata;
	combined_padata[1] = 0;
    }
    tgsreq.padata = combined_padata;

    /* the TGS_REQ is assembled in tgsreq, so encode it */
    if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch))) {
	krb5_xfree(ap_req_padata.contents);
	krb5_xfree(combined_padata);
	goto send_tgs_error_2;
    }
    krb5_xfree(ap_req_padata.contents);
    krb5_xfree(combined_padata);

    /* now send request & get response from KDC */
send_again:
    use_master = 0;
    retval = krb5_sendto_kdc2(context, scratch, 
			    krb5_princ_realm(context, sname),
			    &rep->response, &use_master, tcp_only,
			    hostname_used);
    if (retval == 0) {
	if (krb5_is_krb_error(&rep->response)) {
	    if (!tcp_only) {
		krb5_error *err_reply;
		retval = decode_krb5_error(&rep->response, &err_reply);
		/* Solaris Kerberos */
		if (retval == 0) {
		    if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG) {
			tcp_only = 1;
			krb5_free_error(context, err_reply);
			free(rep->response.data);
			rep->response.data = 0;
			goto send_again;
		    }
		    krb5_free_error(context, err_reply);
		}
	    }
	} else if (krb5_is_tgs_rep(&rep->response))
	    rep->message_type = KRB5_TGS_REP;
        else /* XXX: assume it's an error */
	    rep->message_type = KRB5_ERROR;
    }

    krb5_free_data(context, scratch);
    
send_tgs_error_2:;
    if (sec_ticket) 
	krb5_free_ticket(context, sec_ticket);

send_tgs_error_1:;
    if (ktypes == NULL)
	krb5_xfree(tgsreq.ktype);
    if (tgsreq.authorization_data.ciphertext.data) {
	memset(tgsreq.authorization_data.ciphertext.data, 0,
               tgsreq.authorization_data.ciphertext.length); 
	krb5_xfree(tgsreq.authorization_data.ciphertext.data);
    }

    return retval;
}
Пример #12
0
static krb5_error_code
encts_process(krb5_context context, krb5_clpreauth_moddata moddata,
              krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
              krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
              krb5_kdc_req *request, krb5_data *encoded_request_body,
              krb5_data *encoded_previous_request, krb5_pa_data *padata,
              krb5_prompter_fct prompter, void *prompter_data,
              krb5_clpreauth_get_as_key_fn gak_fct, void *gak_data,
              krb5_data *salt, krb5_data *s2kparams, krb5_keyblock *as_key,
              krb5_pa_data ***out_padata)
{
    krb5_error_code ret;
    krb5_pa_enc_ts pa_enc;
    krb5_data *ts = NULL, *enc_ts = NULL;
    krb5_enc_data enc_data;
    krb5_pa_data **pa = NULL;
    krb5_enctype etype = cb->get_etype(context, rock);

    enc_data.ciphertext = empty_data();

    if (as_key->length == 0) {
#ifdef DEBUG
        fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__,
                 salt->length);
        if ((int) salt->length > 0)
            fprintf (stderr, " '%.*s'", salt->length, salt->data);
        fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n",
                 etype, request->ktype[0]);
#endif
        ret = (*gak_fct)(context, request->client, etype, prompter,
                         prompter_data, salt, s2kparams, as_key, gak_data);
        if (ret)
            goto cleanup;
        TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key);
    }

    /* now get the time of day, and encrypt it accordingly */
    ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec);
    if (ret)
        goto cleanup;

    ret = encode_krb5_pa_enc_ts(&pa_enc, &ts);
    if (ret)
        goto cleanup;

    ret = krb5_encrypt_helper(context, as_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
                              ts, &enc_data);
    if (ret)
        goto cleanup;
    TRACE_PREAUTH_ENC_TS(context, pa_enc.patimestamp, pa_enc.pausec,
                         ts, &enc_data.ciphertext);

    ret = encode_krb5_enc_data(&enc_data, &enc_ts);
    if (ret)
        goto cleanup;

    pa = k5alloc(2 * sizeof(krb5_pa_data *), &ret);
    if (pa == NULL)
        goto cleanup;

    pa[0] = k5alloc(sizeof(krb5_pa_data), &ret);
    if (pa[0] == NULL)
        goto cleanup;

    pa[0]->magic = KV5M_PA_DATA;
    pa[0]->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
    pa[0]->length = enc_ts->length;
    pa[0]->contents = (krb5_octet *) enc_ts->data;
    enc_ts->data = NULL;
    pa[1] = NULL;
    *out_padata = pa;
    pa = NULL;

cleanup:
    krb5_free_data(context, ts);
    krb5_free_data(context, enc_ts);
    free(enc_data.ciphertext.data);
    free(pa);
    return ret;
}
Пример #13
0
static krb5_error_code
ec_process(krb5_context context, krb5_clpreauth_moddata moddata,
           krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
           krb5_clpreauth_callbacks cb,
           krb5_clpreauth_rock rock, krb5_kdc_req *request,
           krb5_data *encoded_request_body,
           krb5_data *encoded_previous_request, krb5_pa_data *padata,
           krb5_prompter_fct prompter, void *prompter_data,
           krb5_pa_data ***out_padata)
{
    krb5_error_code retval = 0;
    krb5_keyblock *challenge_key = NULL, *armor_key, *as_key;

    armor_key = cb->fast_armor(context, rock);
    if (armor_key == NULL)
        return ENOENT;
    retval = cb->get_as_key(context, rock, &as_key);
    if (retval == 0 && padata->length) {
        krb5_enc_data *enc = NULL;
        krb5_data scratch;
        scratch.length = padata->length;
        scratch.data = (char *) padata->contents;
        retval = krb5_c_fx_cf2_simple(context,armor_key, "kdcchallengearmor",
                                      as_key, "challengelongterm",
                                      &challenge_key);
        if (retval == 0)
            retval = decode_krb5_enc_data(&scratch, &enc);
        scratch.data = NULL;
        if (retval == 0) {
            scratch.data = malloc(enc->ciphertext.length);
            scratch.length = enc->ciphertext.length;
            if (scratch.data == NULL)
                retval = ENOMEM;
        }
        if (retval == 0)
            retval = krb5_c_decrypt(context, challenge_key,
                                    KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, NULL,
                                    enc, &scratch);
        /*
         * Per draft 11 of the preauth framework, the client MAY but is not
         * required to actually check the timestamp from the KDC other than to
         * confirm it decrypts. This code does not perform that check.
         */
        if (scratch.data)
            krb5_free_data_contents(context, &scratch);
        /* If we had a callback to assert that the KDC is verified, we would
         * call it here. */
        if (enc)
            krb5_free_enc_data(context, enc);
    } else if (retval == 0) { /*No padata; we send*/
        krb5_enc_data enc;
        krb5_pa_data **pa = NULL;
        krb5_data *encoded_ts = NULL;
        krb5_pa_enc_ts ts;
        enc.ciphertext.data = NULL;
        /* Use the timestamp from the preauth-required error if possible.
         * This time should always be secured by the FAST channel. */
        retval = cb->get_preauth_time(context, rock, FALSE, &ts.patimestamp,
                                      &ts.pausec);
        if (retval == 0)
            retval = encode_krb5_pa_enc_ts(&ts, &encoded_ts);
        if (retval == 0)
            retval = krb5_c_fx_cf2_simple(context,
                                          armor_key, "clientchallengearmor",
                                          as_key, "challengelongterm",
                                          &challenge_key);
        if (retval == 0)
            retval = krb5_encrypt_helper(context, challenge_key,
                                         KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT,
                                         encoded_ts, &enc);
        if (encoded_ts)
            krb5_free_data(context, encoded_ts);
        encoded_ts = NULL;
        if (retval == 0) {
            retval = encode_krb5_enc_data(&enc, &encoded_ts);
            krb5_free_data_contents(context, &enc.ciphertext);
        }
        if (retval == 0) {
            pa = calloc(2, sizeof(krb5_pa_data *));
            if (pa == NULL)
                retval = ENOMEM;
        }
        if (retval == 0) {
            pa[0] = calloc(1, sizeof(krb5_pa_data));
            if (pa[0] == NULL)
                retval = ENOMEM;
        }
        if (retval == 0) {
            pa[0]->length = encoded_ts->length;
            pa[0]->contents = (unsigned char *) encoded_ts->data;
            pa[0]->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE;
            encoded_ts->data = NULL;
            *out_padata = pa;
            pa = NULL;
        }
        free(pa);
        krb5_free_data(context, encoded_ts);
    }
    if (challenge_key)
        krb5_free_keyblock(context, challenge_key);
    return retval;
}
Пример #14
0
static krb5_error_code
encts_process(krb5_context context, krb5_clpreauth_moddata moddata,
              krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
              krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
              krb5_kdc_req *request, krb5_data *encoded_request_body,
              krb5_data *encoded_previous_request, krb5_pa_data *padata,
              krb5_prompter_fct prompter, void *prompter_data,
              krb5_pa_data ***out_padata)
{
    krb5_error_code ret;
    krb5_pa_enc_ts pa_enc;
    krb5_data *ts = NULL, *enc_ts = NULL;
    krb5_enc_data enc_data;
    krb5_pa_data **pa = NULL;
    krb5_keyblock *as_key;

    enc_data.ciphertext = empty_data();

    ret = cb->get_as_key(context, rock, &as_key);
    if (ret)
        goto cleanup;
    TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key);

    /*
     * Try and use the timestamp of the preauth request, even if it's
     * unauthenticated.  We could be fooled into making a preauth response for
     * a future time, but that has no security consequences other than the
     * KDC's audit logs.  If kdc_timesync is not configured, then this will
     * just use local time.
     */
    ret = cb->get_preauth_time(context, rock, TRUE, &pa_enc.patimestamp,
                               &pa_enc.pausec);
    if (ret)
        goto cleanup;

    ret = encode_krb5_pa_enc_ts(&pa_enc, &ts);
    if (ret)
        goto cleanup;

    ret = krb5_encrypt_helper(context, as_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
                              ts, &enc_data);
    if (ret)
        goto cleanup;
    TRACE_PREAUTH_ENC_TS(context, pa_enc.patimestamp, pa_enc.pausec,
                         ts, &enc_data.ciphertext);

    ret = encode_krb5_enc_data(&enc_data, &enc_ts);
    if (ret)
        goto cleanup;

    pa = k5alloc(2 * sizeof(krb5_pa_data *), &ret);
    if (pa == NULL)
        goto cleanup;

    pa[0] = k5alloc(sizeof(krb5_pa_data), &ret);
    if (pa[0] == NULL)
        goto cleanup;

    pa[0]->magic = KV5M_PA_DATA;
    pa[0]->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
    pa[0]->length = enc_ts->length;
    pa[0]->contents = (krb5_octet *) enc_ts->data;
    enc_ts->data = NULL;
    pa[1] = NULL;
    *out_padata = pa;
    pa = NULL;

cleanup:
    krb5_free_data(context, ts);
    krb5_free_data(context, enc_ts);
    free(enc_data.ciphertext.data);
    free(pa);
    return ret;
}
Пример #15
0
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;
}
Пример #16
0
/*
 Sends a request to the TGS and waits for a response.
 options is used for the options in the KRB_TGS_REQ.
 timestruct values are used for from, till, rtime " " "
 enctype is used for enctype " " ", and to encrypt the authorization data, 
 sname is used for sname " " "
 addrs, if non-NULL, is used for addresses " " "
 authorization_dat, if non-NULL, is used for authorization_dat " " "
 second_ticket, if required by options, is used for the 2nd ticket in the req.
 in_cred is used for the ticket & session key in the KRB_AP_REQ header " " "
 (the KDC realm is extracted from in_cred->server's realm)
 
 The response is placed into *rep.
 rep->response.data is set to point at allocated storage which should be
 freed by the caller when finished.

 returns system errors
 */
static krb5_error_code 
krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cred, krb5_data *outbuf)
{   
    krb5_error_code       retval;
    krb5_checksum         checksum;
    krb5_authenticator 	  authent;
    krb5_ap_req 	  request;
    krb5_data		* scratch;
    krb5_data           * toutbuf;

    /* Generate checksum */
    if ((retval = krb5_c_make_checksum(context, context->kdc_req_sumtype,
				       &in_cred->keyblock,
				       KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
				       in_data, &checksum))) {
	free(checksum.contents);
	return(retval);
    }

    /* gen authenticator */
    authent.subkey = 0;
    authent.seq_number = 0;
    authent.checksum = &checksum;
    authent.client = in_cred->client;
    authent.authorization_data = in_cred->authdata;
    if ((retval = krb5_us_timeofday(context, &authent.ctime,
				    &authent.cusec))) {
        free(checksum.contents);
	return(retval);
    }

    /* encode the authenticator */
    if ((retval = encode_krb5_authenticator(&authent, &scratch))) {
        free(checksum.contents);
	return(retval);
    }

    free(checksum.contents);

    request.authenticator.ciphertext.data = 0;
    request.authenticator.kvno = 0;
    request.ap_options = 0;
    request.ticket = 0;

    if ((retval = decode_krb5_ticket(&(in_cred)->ticket, &request.ticket)))
	/* Cleanup scratch and scratch data */
        goto cleanup_data;

    /* call the encryption routine */ 
    if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
				      KRB5_KEYUSAGE_TGS_REQ_AUTH,
				      scratch, &request.authenticator)))
	goto cleanup_ticket;

    retval = encode_krb5_ap_req(&request, &toutbuf);
    /* Solaris Kerberos */
    if (retval == 0) {
	*outbuf = *toutbuf;
	krb5_xfree(toutbuf);
    }


    memset(request.authenticator.ciphertext.data, 0,
           request.authenticator.ciphertext.length);
    free(request.authenticator.ciphertext.data);

cleanup_ticket:
    krb5_free_ticket(context, request.ticket);

cleanup_data:
    memset(scratch->data, 0, scratch->length);
    free(scratch->data);

    free(scratch);

    return retval;
}
Пример #17
0
static krb5_error_code
encts_process(krb5_context context, krb5_clpreauth_moddata moddata,
              krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
              krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
              krb5_kdc_req *request, krb5_data *encoded_request_body,
              krb5_data *encoded_previous_request, krb5_pa_data *padata,
              krb5_prompter_fct prompter, void *prompter_data,
              krb5_pa_data ***out_padata)
{
    krb5_error_code ret;
    krb5_pa_enc_ts pa_enc;
    krb5_data *ts = NULL, *enc_ts = NULL;
    krb5_enc_data enc_data;
    krb5_pa_data **pa = NULL;
    krb5_keyblock *as_key;

    enc_data.ciphertext = empty_data();

    ret = cb->get_as_key(context, rock, &as_key);
    if (ret)
        goto cleanup;
    TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key);

    /* now get the time of day, and encrypt it accordingly */
    ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec);
    if (ret)
        goto cleanup;

    ret = encode_krb5_pa_enc_ts(&pa_enc, &ts);
    if (ret)
        goto cleanup;

    ret = krb5_encrypt_helper(context, as_key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
                              ts, &enc_data);
    if (ret)
        goto cleanup;
    TRACE_PREAUTH_ENC_TS(context, pa_enc.patimestamp, pa_enc.pausec,
                         ts, &enc_data.ciphertext);

    ret = encode_krb5_enc_data(&enc_data, &enc_ts);
    if (ret)
        goto cleanup;

    pa = k5alloc(2 * sizeof(krb5_pa_data *), &ret);
    if (pa == NULL)
        goto cleanup;

    pa[0] = k5alloc(sizeof(krb5_pa_data), &ret);
    if (pa[0] == NULL)
        goto cleanup;

    pa[0]->magic = KV5M_PA_DATA;
    pa[0]->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
    pa[0]->length = enc_ts->length;
    pa[0]->contents = (krb5_octet *) enc_ts->data;
    enc_ts->data = NULL;
    pa[1] = NULL;
    *out_padata = pa;
    pa = NULL;

cleanup:
    krb5_free_data(context, ts);
    krb5_free_data(context, enc_ts);
    free(enc_data.ciphertext.data);
    free(pa);
    return ret;
}
Пример #18
0
krb5_error_code
krb5int_fast_prep_req(krb5_context context,
                      struct krb5int_fast_request_state *state,
                      krb5_kdc_req *request,
                      const krb5_data *to_be_checksummed,
                      kdc_req_encoder_proc encoder,
                      krb5_data **encoded_request)
{
    krb5_error_code retval = 0;
    krb5_pa_data *pa_array[2], **pa_tgs_array = NULL;
    krb5_pa_data pa[2];
    krb5_fast_req fast_req;
    krb5_pa_data *tgs = NULL;
    krb5_fast_armored_req *armored_req = NULL;
    krb5_data *encoded_fast_req = NULL;
    krb5_data *encoded_armored_req = NULL;
    krb5_data *local_encoded_result = NULL;
    int i, j;

    assert(state != NULL);
    assert(state->fast_outer_request.padata == NULL);
    memset(pa_array, 0, sizeof(pa_array));
    if (state->armor_key == NULL) {
        return encoder(request, encoded_request);
    }

    TRACE_FAST_ENCODE(context);
    state->nonce = request->nonce;
    fast_req.req_body = request;
    if (fast_req.req_body->padata == NULL) {
        fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *));
        if (fast_req.req_body->padata == NULL)
            retval = ENOMEM;
    }
    fast_req.fast_options = state->fast_options;
    if (retval == 0
        && (tgs = krb5int_find_pa_data(context, fast_req.req_body->padata,
                                       KRB5_PADATA_AP_REQ)) != NULL) {
        krb5_pa_data **paptr = &fast_req.req_body->padata[0];
        for (i = 0, j = 0; paptr[j] != NULL; j++) {
            if (paptr[j]->pa_type == KRB5_PADATA_AP_REQ)
                paptr[j] = NULL;
            else
                paptr[i++] = paptr[j];
        }
        paptr[i] = NULL;
    }
    if (retval == 0)
        retval = encode_krb5_fast_req(&fast_req, &encoded_fast_req);
    if (retval == 0) {
        armored_req = calloc(1, sizeof(krb5_fast_armored_req));
        if (armored_req == NULL)
            retval = ENOMEM;
    }
    if (retval == 0)
        armored_req->armor = state->armor;
    if (retval ==0)
        retval = krb5_c_make_checksum(context, 0, state->armor_key,
                                      KRB5_KEYUSAGE_FAST_REQ_CHKSUM,
                                      to_be_checksummed,
                                      &armored_req->req_checksum);
    if (retval == 0)
        retval = krb5_encrypt_helper(context, state->armor_key,
                                     KRB5_KEYUSAGE_FAST_ENC, encoded_fast_req,
                                     &armored_req->enc_part);
    if (retval == 0)
        retval = encode_krb5_pa_fx_fast_request(armored_req,
                                                &encoded_armored_req);
    if (retval == 0) {
        pa[0].pa_type = KRB5_PADATA_FX_FAST;
        pa[0].contents = (unsigned char *) encoded_armored_req->data;
        pa[0].length = encoded_armored_req->length;
        if (tgs) {
            retval = make_tgs_outer_padata(tgs, pa, request->padata,
                                           &pa_tgs_array);
            state->fast_outer_request.padata = pa_tgs_array;
        } else {
            pa_array[0] = &pa[0];
            state->fast_outer_request.padata = pa_array;
        }
    }
    if (retval == 0)
        retval = encoder(&state->fast_outer_request, &local_encoded_result);
    if (retval == 0) {
        *encoded_request = local_encoded_result;
        local_encoded_result = NULL;
    }
    if (encoded_armored_req)
        krb5_free_data(context, encoded_armored_req);
    if (armored_req) {
        armored_req->armor = NULL; /*owned by state*/
        krb5_free_fast_armored_req(context, armored_req);
    }
    if (encoded_fast_req)
        krb5_free_data(context, encoded_fast_req);
    if (local_encoded_result)
        krb5_free_data(context, local_encoded_result);
    if (tgs) {
        free(tgs->contents);
        free(tgs);
    }
    state->fast_outer_request.padata = NULL;
    free(pa_tgs_array);
    return retval;
}
Пример #19
0
/*ARGSUSED*/
static
krb5_error_code pa_enc_timestamp(krb5_context context,
				 krb5_kdc_req *request,
				 krb5_pa_data *in_padata,
				 krb5_pa_data **out_padata,
				 krb5_data *salt,
				 krb5_data *s2kparams,
				 krb5_enctype *etype,
				 krb5_keyblock *as_key,
				 krb5_prompter_fct prompter,
				 void *prompter_data,
				 krb5_gic_get_as_key_fct gak_fct,
				 void *gak_data)
{
    krb5_error_code ret;
    krb5_pa_enc_ts pa_enc;
    krb5_data *tmp;
    krb5_enc_data enc_data;
    krb5_pa_data *pa;
   
    if (as_key->length == 0) {
#ifdef DEBUG
	if (salt != NULL && salt->data != NULL) {
	    fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__,
		 salt->length);
	    if (salt->length > 0)
	        fprintf (stderr, " '%*s'", salt->length, salt->data);
	    fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n",
		 *etype, request->ktype[0]);
	}
#endif
       if ((ret = ((*gak_fct)(context, request->client,
			     *etype ? *etype : request->ktype[0],
			     prompter, prompter_data,
			     salt, s2kparams, as_key, gak_data))))
           return(ret);
    }

    /* now get the time of day, and encrypt it accordingly */

    if ((ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec)))
	return(ret);

    if ((ret = encode_krb5_pa_enc_ts(&pa_enc, &tmp)))
	return(ret);

#ifdef DEBUG
    fprintf (stderr, "key type %d bytes %02x %02x ...\n",
	     as_key->enctype,
	     as_key->contents[0], as_key->contents[1]);
#endif
    ret = krb5_encrypt_helper(context, as_key,
			      KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
			      tmp, &enc_data);
#ifdef DEBUG
    fprintf (stderr, "enc data { type=%d kvno=%d data=%02x %02x ... }\n",
	     enc_data.enctype, enc_data.kvno,
	     0xff & enc_data.ciphertext.data[0],
	     0xff & enc_data.ciphertext.data[1]);
#endif

    krb5_free_data(context, tmp);

    if (ret) {
	krb5_xfree(enc_data.ciphertext.data);
	return(ret);
    }

    ret = encode_krb5_enc_data(&enc_data, &tmp);

    krb5_xfree(enc_data.ciphertext.data);

    if (ret)
	return(ret);

    if ((pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
	krb5_free_data(context, tmp);
	return(ENOMEM);
    }

    pa->magic = KV5M_PA_DATA;
    pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
    pa->length = tmp->length;
    pa->contents = (krb5_octet *) tmp->data;

    *out_padata = pa;

    krb5_xfree(tmp);

    return(0);
}