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;
}
Exemple #2
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;
}
Exemple #3
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;
}
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;
}
Exemple #5
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;
}
Exemple #6
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;
}
Exemple #7
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;
}
Exemple #8
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);
}