Beispiel #1
0
static krb5_error_code
decrypt_fast_reply(krb5_context context,
                   struct krb5int_fast_request_state *state,
                   krb5_pa_data **in_padata,
                   krb5_fast_response **response)
{
    krb5_error_code retval = 0;
    krb5_data scratch;
    krb5_enc_data *encrypted_response = NULL;
    krb5_pa_data *fx_reply = NULL;
    krb5_fast_response *local_resp = NULL;

    assert(state != NULL);
    assert(state->armor_key);
    fx_reply = krb5int_find_pa_data(context, in_padata, KRB5_PADATA_FX_FAST);
    if (fx_reply == NULL)
        retval = KRB5_ERR_FAST_REQUIRED;
    TRACE_FAST_DECODE(context);
    if (retval == 0) {
        scratch.data = (char *) fx_reply->contents;
        scratch.length = fx_reply->length;
        retval = decode_krb5_pa_fx_fast_reply(&scratch, &encrypted_response);
    }
    scratch.data = NULL;
    if (retval == 0) {
        scratch.data = malloc(encrypted_response->ciphertext.length);
        if (scratch.data == NULL)
            retval = ENOMEM;
        scratch.length = encrypted_response->ciphertext.length;
    }
    if (retval == 0)
        retval = krb5_c_decrypt(context, state->armor_key,
                                KRB5_KEYUSAGE_FAST_REP, NULL,
                                encrypted_response, &scratch);
    if (retval != 0)
        k5_prependmsg(context, retval, _("Failed to decrypt FAST reply"));
    if (retval == 0)
        retval = decode_krb5_fast_response(&scratch, &local_resp);
    if (retval == 0) {
        if (local_resp->nonce != state->nonce) {
            retval = KRB5_KDCREP_MODIFIED;
            k5_setmsg(context, retval, _("nonce modified in FAST response: "
                                         "KDC response modified"));
        }
    }
    if (retval == 0) {
        *response = local_resp;
        local_resp = NULL;
    }
    if (scratch.data)
        free(scratch.data);
    if (encrypted_response)
        krb5_free_enc_data(context, encrypted_response);
    if (local_resp)
        krb5_free_fast_response(context, local_resp);
    return retval;
}
Beispiel #2
0
Datei: fast.c Projekt: WeiY/krb5
krb5_error_code
krb5int_fast_process_response(krb5_context context,
                              struct krb5int_fast_request_state *state,
                              krb5_kdc_rep *resp,
                              krb5_keyblock **strengthen_key)
{
    krb5_error_code retval = 0;
    krb5_fast_response *fast_response = NULL;
    krb5_data *encoded_ticket = NULL;
    krb5_boolean cksum_valid;

    krb5_clear_error_message(context);
    *strengthen_key = NULL;
    if (state->armor_key == 0)
        return 0;
    retval = decrypt_fast_reply(context, state, resp->padata,
                                &fast_response);
    if (retval == 0) {
        if (fast_response->finished == 0) {
            retval = KRB5_KDCREP_MODIFIED;
            krb5_set_error_message(context, retval,
                                   _("FAST response missing finish message "
                                     "in KDC reply"));
        }
    }
    if (retval == 0)
        retval = encode_krb5_ticket(resp->ticket, &encoded_ticket);
    if (retval == 0)
        retval = krb5_c_verify_checksum(context, state->armor_key,
                                        KRB5_KEYUSAGE_FAST_FINISHED,
                                        encoded_ticket,
                                        &fast_response->finished->ticket_checksum,
                                        &cksum_valid);
    if (retval == 0 && cksum_valid == 0) {
        retval = KRB5_KDCREP_MODIFIED;
        krb5_set_error_message(context, retval,
                               _("Ticket modified in KDC reply"));
    }
    if (retval == 0) {
        krb5_free_principal(context, resp->client);
        resp->client = fast_response->finished->client;
        fast_response->finished->client = NULL;
        *strengthen_key = fast_response->strengthen_key;
        fast_response->strengthen_key = NULL;
        krb5_free_pa_data(context, resp->padata);
        resp->padata = fast_response->padata;
        fast_response->padata = NULL;
    }
    if (fast_response)
        krb5_free_fast_response(context, fast_response);
    if (encoded_ticket)
        krb5_free_data(context, encoded_ticket);
    return retval;
}
Beispiel #3
0
/*
 * If state contains an armor key and *err_replyptr contains a FAST error,
 * decode it and set *err_replyptr to the inner error and *out_padata to the
 * padata in the FAST response.  Otherwise, leave *err_replyptr alone and set
 * *out_padata to the error e_data decoded as pa-data or typed-data, or to NULL
 * if it doesn't decode as either.  In either case, set *retry to indicate
 * whether the client should try to make a follow-up request.
 */
krb5_error_code
krb5int_fast_process_error(krb5_context context,
                           struct krb5int_fast_request_state *state,
                           krb5_error **err_replyptr,
                           krb5_pa_data ***out_padata,
                           krb5_boolean *retry)
{
    krb5_error_code retval = 0;
    krb5_error *err_reply = *err_replyptr;
    krb5_pa_data *fx_error_pa;
    krb5_pa_data **result = NULL;
    krb5_data scratch = empty_data();
    krb5_error *fx_error = NULL;
    krb5_fast_response *fast_response = NULL;

    if (out_padata)
        *out_padata = NULL;
    if (retry)
        *retry = 0;

    if (state->armor_key) {
        retval = decode_krb5_padata_sequence(&err_reply->e_data, &result);
        if (retval == 0)
            retval = decrypt_fast_reply(context, state, result,
                                        &fast_response);
        if (retval) {
            /*
             * This can happen if the KDC does not understand FAST. We don't
             * expect that, but treating it as the fatal error indicated by the
             * KDC seems reasonable.
             */
            if (retry != NULL)
                *retry = 0;
            krb5_free_pa_data(context, result);
            return 0;
        }
        if (retval == 0) {
            fx_error_pa = krb5int_find_pa_data(context, fast_response->padata,
                                               KRB5_PADATA_FX_ERROR);
            if (fx_error_pa == NULL) {
                k5_setmsg(context, KRB5KDC_ERR_PREAUTH_FAILED,
                          _("Expecting FX_ERROR pa-data inside FAST "
                            "container"));
                retval = KRB5KDC_ERR_PREAUTH_FAILED;
            }
        }
        if (retval == 0) {
            scratch = make_data(fx_error_pa->contents, fx_error_pa->length);
            retval = decode_krb5_error(&scratch, &fx_error);
        }
        if (retval == 0) {
            krb5_free_error(context, err_reply);
            *err_replyptr = fx_error;
            fx_error = NULL;
            if (out_padata) {
                *out_padata = fast_response->padata;
                fast_response->padata = NULL;
            }
            /*
             * If there is more than the fx_error padata, then we want
             * to retry the error if a cookie is present
             */
            if (retry != NULL) {
                *retry = (*out_padata)[1] != NULL;
                if (krb5int_find_pa_data(context, *out_padata,
                                         KRB5_PADATA_FX_COOKIE) == NULL)
                    *retry = 0;
            }
        }
    } else { /*not FAST*/
        /* Possibly retry if there's any e_data to process. */
        if (retry)
            *retry = (err_reply->e_data.length > 0);
        /* Try to decode e_data as pa-data or typed-data for out_padata. */
        if (out_padata) {
            retval = decode_krb5_padata_sequence(&err_reply->e_data,
                                                 out_padata);
            if (retval != 0) {
                (void)decode_krb5_typed_data(&err_reply->e_data, out_padata);
                retval = 0;
            }
        }
    }
    krb5_free_pa_data(context, result);
    krb5_free_fast_response(context, fast_response);
    if (fx_error)
        krb5_free_error(context, fx_error);
    return retval;
}
Beispiel #4
0
/*
 * FAST separates two concepts: the set of padata we're using to
 * decide what pre-auth mechanisms to use and the set of padata we're
 * making available to mechanisms in order for them to respond to an
 * error.  The plugin interface in March 2009 does not permit
 * separating these concepts for the plugins.  This function makes
 * both available for future revisions to the plugin interface.  It
 * also re-encodes the padata from the current error as a encoded
 * typed-data and puts that in the e_data field.  That will allow
 * existing plugins with the old interface to find the error data.
 * The output parameter out_padata contains the padata from the error
 * whenever padata  is available (all the time with fast).
 */
krb5_error_code
krb5int_fast_process_error(krb5_context context,
                           struct krb5int_fast_request_state *state,
                           krb5_error **err_replyptr,
                           krb5_pa_data ***out_padata,
                           krb5_boolean *retry)
{
    krb5_error_code retval = 0;
    krb5_error *err_reply = *err_replyptr;

    *out_padata = NULL;
    *retry = 0;
    if (state->armor_key) {
        krb5_pa_data *fx_error_pa;
        krb5_pa_data **result = NULL;
        krb5_data scratch, *encoded_td = NULL;
        krb5_error *fx_error = NULL;
        krb5_fast_response *fast_response = NULL;

        retval = decode_krb5_padata_sequence(&err_reply->e_data, &result);
        if (retval == 0)
            retval = decrypt_fast_reply(context, state, result,
                                        &fast_response);
        if (retval) {
            /*
             * This can happen if the KDC does not understand FAST. We don't
             * expect that, but treating it as the fatal error indicated by the
             * KDC seems reasonable.
             */
            *retry = 0;
            krb5_free_pa_data(context, result);
            return 0;
        }
        krb5_free_pa_data(context, result);
        result = NULL;
        if (retval == 0) {
            fx_error_pa = krb5int_find_pa_data(context, fast_response->padata,
                                               KRB5_PADATA_FX_ERROR);
            if (fx_error_pa == NULL) {
                krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
                                       "Expecting FX_ERROR pa-data inside "
                                       "FAST container");
                retval = KRB5KDC_ERR_PREAUTH_FAILED;
            }
        }
        if (retval == 0) {
            scratch.data = (char *) fx_error_pa->contents;
            scratch.length = fx_error_pa->length;
            retval = decode_krb5_error(&scratch, &fx_error);
        }
        /*
         * krb5_pa_data and krb5_typed_data are safe to cast between:
         * they have the same type fields in the same order.
         * (krb5_preauthtype is a krb5_int32).  If krb5_typed_data is
         * ever changed then this will need to be a copy not a cast.
         */
        if (retval == 0)
            retval = encode_krb5_typed_data((const krb5_typed_data **)
                                            fast_response->padata,
                                            &encoded_td);
        if (retval == 0) {
            fx_error->e_data = *encoded_td;
            free(encoded_td); /*contents owned by fx_error*/
            encoded_td = NULL;
            krb5_free_error(context, err_reply);
            *err_replyptr = fx_error;
            fx_error = NULL;
            *out_padata = fast_response->padata;
            fast_response->padata = NULL;
            /*
             * If there is more than the fx_error padata, then we want
             * to retry the error if a cookie is present
             */
            *retry = (*out_padata)[1] != NULL;
            if (krb5int_find_pa_data(context, *out_padata,
                                     KRB5_PADATA_FX_COOKIE) == NULL)
                *retry = 0;
        }
        if (fx_error)
            krb5_free_error(context, fx_error);
        krb5_free_fast_response(context, fast_response);
    } else { /*not FAST*/
        *retry = (err_reply->e_data.length > 0);
        if ((err_reply->error == KDC_ERR_PREAUTH_REQUIRED ||
                err_reply->error == KDC_ERR_PREAUTH_FAILED) &&
                err_reply->e_data.length) {
            krb5_pa_data **result = NULL;
            retval = decode_krb5_padata_sequence(&err_reply->e_data, &result);
            if (retval == 0) {
                *out_padata = result;
                return 0;
            }
            krb5_free_pa_data(context, result);
            krb5_set_error_message(context, retval,
                                   "Error decoding padata in error reply");
            return retval;
        }
    }
    return retval;
}