Beispiel #1
0
static krb5_error_code
make_ad_signedpath_checksum(krb5_context context,
                            krb5_const_principal for_user_princ,
                            const krb5_db_entry *krbtgt,
                            krb5_keyblock *krbtgt_key,
                            krb5_enc_tkt_part *enc_tkt_part,
                            krb5_principal *deleg_path,
                            krb5_pa_data **method_data,
                            krb5_checksum *cksum)
{
    krb5_error_code                 code;
    krb5_data                      *data;
    krb5_cksumtype                  cksumtype;
    krb5_const_principal            client;

    if (for_user_princ != NULL)
        client = for_user_princ;
    else
        client = enc_tkt_part->client;

    code = make_ad_signedpath_data(context,
                                   client,
                                   enc_tkt_part->times.authtime,
                                   deleg_path,
                                   method_data,
                                   enc_tkt_part->authorization_data,
                                   &data);
    if (code != 0)
        return code;

    code = krb5int_c_mandatory_cksumtype(context,
                                         krbtgt_key->enctype,
                                         &cksumtype);
    if (code != 0) {
        krb5_free_data(context, data);
        return code;
    }

    if (!krb5_c_is_keyed_cksum(cksumtype)) {
        krb5_free_data(context, data);
        return KRB5KRB_AP_ERR_INAPP_CKSUM;
    }

    code = krb5_c_make_checksum(context, cksumtype, krbtgt_key,
                                KRB5_KEYUSAGE_AD_SIGNEDPATH, data,
                                cksum);

    krb5_free_data(context, data);

    return code;
}
Beispiel #2
0
static krb5_error_code
k5_pac_verify_kdc_checksum(krb5_context context,
                           const krb5_pac pac,
                           const krb5_keyblock *privsvr)
{
    krb5_error_code ret;
    krb5_data server_checksum, privsvr_checksum;
    krb5_checksum checksum;
    krb5_boolean valid;
    krb5_octet *p;

    ret = k5_pac_locate_buffer(context, pac,
                               PAC_PRIVSVR_CHECKSUM, &privsvr_checksum);
    if (ret != 0)
        return ret;

    if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH)
        return KRB5_BAD_MSIZE;

    ret = k5_pac_locate_buffer(context, pac,
                               PAC_SERVER_CHECKSUM, &server_checksum);
    if (ret != 0)
        return ret;

    if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH)
        return KRB5_BAD_MSIZE;

    p = (krb5_octet *)privsvr_checksum.data;
    checksum.checksum_type = load_32_le(p);
    checksum.length = privsvr_checksum.length - PAC_SIGNATURE_DATA_LENGTH;
    checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
    if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
        return KRB5KRB_AP_ERR_INAPP_CKSUM;

    server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;
    server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;

    ret = krb5_c_verify_checksum(context, privsvr,
                                 KRB5_KEYUSAGE_APP_DATA_CKSUM,
                                 &server_checksum, &checksum, &valid);
    if (ret != 0)
        return ret;

    if (valid == FALSE)
        ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;

    return ret;
}
Beispiel #3
0
static krb5_error_code
verify_ad_signedpath_checksum(krb5_context context,
                              const krb5_db_entry *krbtgt,
                              krb5_keyblock *krbtgt_key,
                              krb5_enc_tkt_part *enc_tkt_part,
                              krb5_principal *deleg_path,
                              krb5_pa_data **method_data,
                              krb5_checksum *cksum,
                              krb5_boolean *valid)
{
    krb5_error_code                 code;
    krb5_data                      *data;

    *valid = FALSE;

    if (!krb5_c_is_keyed_cksum(cksum->checksum_type))
        return KRB5KRB_AP_ERR_INAPP_CKSUM;

    code = make_ad_signedpath_data(context,
                                   enc_tkt_part->client,
                                   enc_tkt_part->times.authtime,
                                   deleg_path,
                                   method_data,
                                   enc_tkt_part->authorization_data,
                                   &data);
    if (code != 0)
        return code;

    code = krb5_c_verify_checksum(context,
                                  krbtgt_key,
                                  KRB5_KEYUSAGE_AD_SIGNEDPATH,
                                  data,
                                  cksum,
                                  valid);

    krb5_free_data(context, data);
    return code;
}
Beispiel #4
0
/*
  Formats a KRB_SAFE message into outbuf.

  userdata is formatted as the user data in the message.
  sumtype specifies the encryption type; key specifies the key which
  might be used to seed the checksum; sender_addr and recv_addr specify
  the full addresses (host and port) of the sender and receiver.
  The host portion of sender_addr is used to form the addresses used in the
  KRB_SAFE message.

  The outbuf buffer storage is allocated, and should be freed by the
  caller when finished.

  returns system errors
*/
static krb5_error_code
krb5_mk_safe_basic(krb5_context context, const krb5_data *userdata,
                   krb5_key key, krb5_replay_data *replaydata,
                   krb5_address *local_addr, krb5_address *remote_addr,
                   krb5_cksumtype sumtype, krb5_data *outbuf)
{
    krb5_error_code retval;
    krb5_safe safemsg;
    krb5_octet zero_octet = 0;
    krb5_checksum safe_checksum;
    krb5_data *scratch1, *scratch2;

    if (!krb5_c_valid_cksumtype(sumtype))
        return KRB5_PROG_SUMTYPE_NOSUPP;
    if (!krb5_c_is_coll_proof_cksum(sumtype)
        || !krb5_c_is_keyed_cksum(sumtype))
        return KRB5KRB_AP_ERR_INAPP_CKSUM;

    safemsg.user_data = *userdata;
    safemsg.s_address = (krb5_address *) local_addr;
    safemsg.r_address = (krb5_address *) remote_addr;

    /* We should check too make sure one exists. */
    safemsg.timestamp  = replaydata->timestamp;
    safemsg.usec       = replaydata->usec;
    safemsg.seq_number = replaydata->seq;

    /*
     * To do the checksum stuff, we need to encode the message with a
     * zero-length zero-type checksum, then checksum the encoding, then
     * re-encode with the checksum.
     */

    safe_checksum.length = 0;
    safe_checksum.checksum_type = 0;
    safe_checksum.contents = &zero_octet;

    safemsg.checksum = &safe_checksum;

    if ((retval = encode_krb5_safe(&safemsg, &scratch1)))
        return retval;

    if ((retval = krb5_k_make_checksum(context, sumtype, key,
                                       KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
                                       scratch1, &safe_checksum)))
        goto cleanup_checksum;

    safemsg.checksum = &safe_checksum;
    if ((retval = encode_krb5_safe(&safemsg, &scratch2))) {
        goto cleanup_checksum;
    }
    *outbuf = *scratch2;
    free(scratch2);
    retval = 0;

cleanup_checksum:
    free(safe_checksum.contents);

    memset(scratch1->data, 0, scratch1->length);
    krb5_free_data(context, scratch1);
    return retval;
}
Beispiel #5
0
static krb5_error_code
sam2_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;
    krb5_sam_challenge_2 *sc2 = NULL;
    krb5_sam_challenge_2_body *sc2b = NULL;
    krb5_data tmp_data;
    krb5_data response_data;
    char name[100], banner[100], prompt[100], response[100];
    krb5_prompt kprompt;
    krb5_prompt_type prompt_type;
    krb5_data defsalt, *salt;
    krb5_checksum **cksum;
    krb5_data *scratch = NULL;
    krb5_boolean valid_cksum = 0;
    krb5_enc_sam_response_enc_2 enc_sam_response_enc_2;
    krb5_sam_response_2 sr2;
    size_t ciph_len;
    krb5_pa_data **sam_padata;

    if (prompter == NULL)
        return KRB5_LIBOS_CANTREADPWD;

    tmp_data.length = padata->length;
    tmp_data.data = (char *)padata->contents;

    if ((retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2)))
        return(retval);

    retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b);

    if (retval) {
        krb5_free_sam_challenge_2(context, sc2);
        return(retval);
    }

    if (!sc2->sam_cksum || ! *sc2->sam_cksum) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        return(KRB5_SAM_NO_CHECKSUM);
    }

    if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        return(KRB5_SAM_UNSUPPORTED);
    }

    if (!krb5_c_valid_enctype(sc2b->sam_etype)) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        return(KRB5_SAM_INVALID_ETYPE);
    }

    /* All of the above error checks are KDC-specific, that is, they     */
    /* assume a failure in the KDC reply.  By returning anything other   */
    /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED,               */
    /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will   */
    /* most likely go on to try the AS_REQ against master KDC            */

    if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
        /* We will need the password to obtain the key used for */
        /* the checksum, and encryption of the sam_response.    */
        /* Go ahead and get it now, preserving the ordering of  */
        /* prompts for the user.                                */

        retval = (*rock->gak_fct)(context, request->client, sc2b->sam_etype,
				  prompter, prompter_data, rock->salt,
				  rock->s2kparams, rock->as_key,
				  *rock->gak_data);
        if (retval) {
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            return(retval);
        }
    }

    snprintf(name, sizeof(name), "%.*s",
             SAMDATA(sc2b->sam_type_name, _("SAM Authentication"),
                     sizeof(name) - 1));

    snprintf(banner, sizeof(banner), "%.*s",
             SAMDATA(sc2b->sam_challenge_label,
                     sam_challenge_banner(sc2b->sam_type),
                     sizeof(banner)-1));

    snprintf(prompt, sizeof(prompt), "%s%.*s%s%.*s",
             sc2b->sam_challenge.length?"Challenge is [":"",
             SAMDATA(sc2b->sam_challenge, "", 20),
             sc2b->sam_challenge.length?"], ":"",
             SAMDATA(sc2b->sam_response_prompt, "passcode", 55));

    response_data.data = response;
    response_data.length = sizeof(response);
    kprompt.prompt = prompt;
    kprompt.hidden = 1;
    kprompt.reply = &response_data;

    prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
    krb5int_set_prompt_types(context, &prompt_type);

    if ((retval = ((*prompter)(context, prompter_data, name,
                               banner, 1, &kprompt)))) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        krb5int_set_prompt_types(context, 0);
        return(retval);
    }

    krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL);

    /* Generate salt used by string_to_key() */
    salt = rock->salt;
    if (((int) salt->length == -1) && (salt->data == NULL)) {
        if ((retval =
             krb5_principal2salt(context, request->client, &defsalt))) {
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            return(retval);
        }
        salt = &defsalt;
    } else {
        defsalt.length = 0;
    }

    /* Get encryption key to be used for checksum and sam_response */
    if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
        /* as_key = string_to_key(password) */

        if (rock->as_key->length) {
            krb5_free_keyblock_contents(context, rock->as_key);
            rock->as_key->length = 0;
        }

        /* generate a key using the supplied password */
        retval = krb5_c_string_to_key(context, sc2b->sam_etype,
				      (krb5_data *)*rock->gak_data, salt,
				      rock->as_key);

        if (retval) {
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            if (defsalt.length) free(defsalt.data);
            return(retval);
        }

        if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) {
            /* as_key = combine_key (as_key, string_to_key(SAD)) */
            krb5_keyblock tmp_kb;

            retval = krb5_c_string_to_key(context, sc2b->sam_etype,
                                          &response_data, salt, &tmp_kb);

            if (retval) {
                krb5_free_sam_challenge_2(context, sc2);
                krb5_free_sam_challenge_2_body(context, sc2b);
                if (defsalt.length) free(defsalt.data);
                return(retval);
            }

            /* This should be a call to the crypto library some day */
            /* key types should already match the sam_etype */
            retval = krb5int_c_combine_keys(context, rock->as_key, &tmp_kb,
					    rock->as_key);

            if (retval) {
                krb5_free_sam_challenge_2(context, sc2);
                krb5_free_sam_challenge_2_body(context, sc2b);
                if (defsalt.length) free(defsalt.data);
                return(retval);
            }
            krb5_free_keyblock_contents(context, &tmp_kb);
        }

        if (defsalt.length)
            free(defsalt.data);

    } else {
        /* as_key = string_to_key(SAD) */

        if (rock->as_key->length) {
            krb5_free_keyblock_contents(context, rock->as_key);
            rock->as_key->length = 0;
        }

        /* generate a key using the supplied password */
        retval = krb5_c_string_to_key(context, sc2b->sam_etype,
                                      &response_data, salt, rock->as_key);

        if (defsalt.length)
            free(defsalt.data);

        if (retval) {
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            return(retval);
        }
    }

    /* Now we have a key, verify the checksum on the sam_challenge */

    cksum = sc2->sam_cksum;

    for (; *cksum; cksum++) {
        if (!krb5_c_is_keyed_cksum((*cksum)->checksum_type))
            continue;
        /* Check this cksum */
        retval = krb5_c_verify_checksum(context, rock->as_key,
                                        KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
                                        &sc2->sam_challenge_2_body,
                                        *cksum, &valid_cksum);
        if (retval) {
            krb5_free_data(context, scratch);
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            return(retval);
        }
        if (valid_cksum)
            break;
    }

    if (!valid_cksum) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        /*
         * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
         * can interpret that as "password incorrect", which is probably
         * the best error we can return in this situation.
         */
        return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
    }

    /* fill in enc_sam_response_enc_2 */
    enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
    enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce;
    if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
        enc_sam_response_enc_2.sam_sad = response_data;
    } else {
        enc_sam_response_enc_2.sam_sad.data = NULL;
        enc_sam_response_enc_2.sam_sad.length = 0;
    }

    /* encode and encrypt enc_sam_response_enc_2 with as_key */
    retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2,
                                                &scratch);
    if (retval) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        return(retval);
    }

    /* Fill in sam_response_2 */
    memset(&sr2, 0, sizeof(sr2));
    sr2.sam_type = sc2b->sam_type;
    sr2.sam_flags = sc2b->sam_flags;
    sr2.sam_track_id = sc2b->sam_track_id;
    sr2.sam_nonce = sc2b->sam_nonce;

    /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded   */
    /* enc_sam_response_enc_2 from above */

    retval = krb5_c_encrypt_length(context, rock->as_key->enctype,
				   scratch->length, &ciph_len);
    if (retval) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        krb5_free_data(context, scratch);
        return(retval);
    }
    sr2.sam_enc_nonce_or_sad.ciphertext.length = ciph_len;

    sr2.sam_enc_nonce_or_sad.ciphertext.data =
        (char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length);

    if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        krb5_free_data(context, scratch);
        return(ENOMEM);
    }

    retval = krb5_c_encrypt(context, rock->as_key,
			    KRB5_KEYUSAGE_PA_SAM_RESPONSE, NULL, scratch,
			    &sr2.sam_enc_nonce_or_sad);
    if (retval) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        krb5_free_data(context, scratch);
        krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
        return(retval);
    }
    krb5_free_data(context, scratch);
    scratch = NULL;

    /* Encode the sam_response_2 */
    retval = encode_krb5_sam_response_2(&sr2, &scratch);
    krb5_free_sam_challenge_2(context, sc2);
    krb5_free_sam_challenge_2_body(context, sc2b);
    krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);

    if (retval) {
        return (retval);
    }

    /* Almost there, just need to make padata !  */
    sam_padata = malloc(2 * sizeof(*sam_padata));
    if (sam_padata == NULL) {
        krb5_free_data(context, scratch);
        return(ENOMEM);
    }
    sam_padata[0] = malloc(sizeof(krb5_pa_data));
    if (sam_padata[0] == NULL) {
        krb5_free_data(context, scratch);
	free(sam_padata);
        return(ENOMEM);
    }

    sam_padata[0]->magic = KV5M_PA_DATA;
    sam_padata[0]->pa_type = KRB5_PADATA_SAM_RESPONSE_2;
    sam_padata[0]->length = scratch->length;
    sam_padata[0]->contents = (krb5_octet *) scratch->data;
    free(scratch);
    sam_padata[1] = NULL;

    *out_padata = sam_padata;

    return(0);
}
Beispiel #6
0
krb5_error_code
kdc_find_fast(krb5_kdc_req **requestptr,
              krb5_data *checksummed_data,
              krb5_keyblock *tgs_subkey,
              krb5_keyblock *tgs_session,
              struct kdc_request_state *state,
              krb5_data **inner_body_out)
{
    krb5_error_code retval = 0;
    krb5_pa_data *fast_padata, *cookie_padata = NULL;
    krb5_data scratch, *inner_body = NULL;
    krb5_fast_req * fast_req = NULL;
    krb5_kdc_req *request = *requestptr;
    krb5_fast_armored_req *fast_armored_req = NULL;
    krb5_checksum *cksum;
    krb5_boolean cksum_valid;
    krb5_keyblock empty_keyblock;
    kdc_realm_t *kdc_active_realm = state->realm_data;

    if (inner_body_out != NULL)
        *inner_body_out = NULL;
    scratch.data = NULL;
    krb5_clear_error_message(kdc_context);
    memset(&empty_keyblock, 0, sizeof(krb5_keyblock));
    fast_padata = krb5int_find_pa_data(kdc_context,
                                       request->padata, KRB5_PADATA_FX_FAST);
    if (fast_padata !=  NULL){
        scratch.length = fast_padata->length;
        scratch.data = (char *) fast_padata->contents;
        retval = decode_krb5_pa_fx_fast_request(&scratch, &fast_armored_req);
        if (retval == 0 &&fast_armored_req->armor) {
            switch (fast_armored_req->armor->armor_type) {
            case KRB5_FAST_ARMOR_AP_REQUEST:
                if (tgs_subkey) {
                    retval = KRB5KDC_ERR_PREAUTH_FAILED;
                    krb5_set_error_message(kdc_context, retval,
                                           _("Ap-request armor not permitted "
                                             "with TGS"));
                    break;
                }
                retval = armor_ap_request(state, fast_armored_req->armor);
                break;
            default:
                krb5_set_error_message(kdc_context, KRB5KDC_ERR_PREAUTH_FAILED,
                                       _("Unknown FAST armor type %d"),
                                       fast_armored_req->armor->armor_type);
                retval = KRB5KDC_ERR_PREAUTH_FAILED;
            }
        }
        if (retval == 0 && !state->armor_key) {
            if (tgs_subkey)
                retval = krb5_c_fx_cf2_simple(kdc_context,
                                              tgs_subkey, "subkeyarmor",
                                              tgs_session, "ticketarmor",
                                              &state->armor_key);
            else {
                retval = KRB5KDC_ERR_PREAUTH_FAILED;
                krb5_set_error_message(kdc_context, retval,
                                       _("No armor key but FAST armored "
                                         "request present"));
            }
        }
        if (retval == 0) {
            krb5_data plaintext;
            plaintext.length = fast_armored_req->enc_part.ciphertext.length;
            plaintext.data = malloc(plaintext.length);
            if (plaintext.data == NULL)
                retval = ENOMEM;
            retval = krb5_c_decrypt(kdc_context,
                                    state->armor_key,
                                    KRB5_KEYUSAGE_FAST_ENC, NULL,
                                    &fast_armored_req->enc_part,
                                    &plaintext);
            if (retval == 0)
                retval = decode_krb5_fast_req(&plaintext, &fast_req);
            if (retval == 0 && inner_body_out != NULL) {
                retval = fetch_asn1_field((unsigned char *)plaintext.data,
                                          1, 2, &scratch);
                if (retval == 0) {
                    retval = krb5_copy_data(kdc_context, &scratch,
                                            &inner_body);
                }
            }
            if (plaintext.data)
                free(plaintext.data);
        }
        cksum = &fast_armored_req->req_checksum;
        if (retval == 0)
            retval = krb5_c_verify_checksum(kdc_context, state->armor_key,
                                            KRB5_KEYUSAGE_FAST_REQ_CHKSUM,
                                            checksummed_data, cksum,
                                            &cksum_valid);
        if (retval == 0 && !cksum_valid) {
            retval = KRB5KRB_AP_ERR_MODIFIED;
            krb5_set_error_message(kdc_context, retval,
                                   _("FAST req_checksum invalid; request "
                                     "modified"));
        }
        if (retval == 0) {
            if (!krb5_c_is_keyed_cksum(cksum->checksum_type)) {
                retval = KRB5KDC_ERR_POLICY;
                krb5_set_error_message(kdc_context, retval,
                                       _("Unkeyed checksum used in fast_req"));
            }
        }
        if (retval == 0) {
            if ((fast_req->fast_options & UNSUPPORTED_CRITICAL_FAST_OPTIONS) != 0)
                retval = KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION;
        }
        if (retval == 0)
            cookie_padata = krb5int_find_pa_data(kdc_context,
                                                 fast_req->req_body->padata,
                                                 KRB5_PADATA_FX_COOKIE);
        if (retval == 0) {
            state->fast_options = fast_req->fast_options;
            krb5_free_kdc_req( kdc_context, request);
            *requestptr = fast_req->req_body;
            fast_req->req_body = NULL;
        }
    }
    else {
        cookie_padata = krb5int_find_pa_data(kdc_context,
                                             request->padata,
                                             KRB5_PADATA_FX_COOKIE);
    }
    if (retval == 0 && cookie_padata != NULL) {
        krb5_pa_data *new_padata = malloc(sizeof (krb5_pa_data));
        if (new_padata == NULL) {
            retval = ENOMEM;
        } else {
            new_padata->pa_type = KRB5_PADATA_FX_COOKIE;
            new_padata->length = cookie_padata->length;
            new_padata->contents = malloc(new_padata->length);
            if (new_padata->contents == NULL) {
                retval = ENOMEM;
                free(new_padata);
            } else {
                memcpy(new_padata->contents, cookie_padata->contents,
                       new_padata->length);
                state->cookie = new_padata;
            }
        }
    }
    if (retval == 0 && inner_body_out != NULL) {
        *inner_body_out = inner_body;
        inner_body = NULL;
    }
    krb5_free_data(kdc_context, inner_body);
    if (fast_req)
        krb5_free_fast_req( kdc_context, fast_req);
    if (fast_armored_req)
        krb5_free_fast_armored_req(kdc_context, fast_armored_req);
    return retval;
}
Beispiel #7
0
/*
  parses a KRB_SAFE message from inbuf, placing the integrity-protected user
  data in *outbuf.

  key specifies the key to be used for decryption of the message.

  outbuf points to allocated storage which the caller should free when finished.

  returns system errors, integrity errors
*/
static krb5_error_code
rd_safe_basic(krb5_context context, krb5_auth_context ac,
              const krb5_data *inbuf, krb5_key key,
              krb5_replay_data *replaydata, krb5_data *outbuf)
{
    krb5_error_code       retval;
    krb5_safe           * message;
    krb5_data safe_body;
    krb5_checksum our_cksum, *his_cksum;
    krb5_octet zero_octet = 0;
    krb5_data *scratch;
    krb5_boolean valid;
    struct krb5_safe_with_body swb;

    if (!krb5_is_krb_safe(inbuf))
        return KRB5KRB_AP_ERR_MSG_TYPE;

    if ((retval = decode_krb5_safe_with_body(inbuf, &message, &safe_body)))
        return retval;

    if (!krb5_c_valid_cksumtype(message->checksum->checksum_type)) {
        retval = KRB5_PROG_SUMTYPE_NOSUPP;
        goto cleanup;
    }
    if (!krb5_c_is_coll_proof_cksum(message->checksum->checksum_type) ||
        !krb5_c_is_keyed_cksum(message->checksum->checksum_type)) {
        retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
        goto cleanup;
    }

    retval = k5_privsafe_check_addrs(context, ac, message->s_address,
                                     message->r_address);
    if (retval)
        goto cleanup;

    /* verify the checksum */
    /*
     * In order to recreate what was checksummed, we regenerate the message
     * without checksum and then have the cryptographic subsystem verify
     * the checksum for us.  This is because some checksum methods have
     * a confounder encrypted as part of the checksum.
     */
    his_cksum = message->checksum;

    our_cksum.length = 0;
    our_cksum.checksum_type = 0;
    our_cksum.contents = &zero_octet;

    message->checksum = &our_cksum;

    swb.body = &safe_body;
    swb.safe = message;
    retval = encode_krb5_safe_with_body(&swb, &scratch);
    message->checksum = his_cksum;
    if (retval)
        goto cleanup;

    retval = krb5_k_verify_checksum(context, key,
                                    KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
                                    scratch, his_cksum, &valid);

    (void) memset(scratch->data, 0, scratch->length);
    krb5_free_data(context, scratch);

    if (!valid) {
        /*
         * Checksum over only the KRB-SAFE-BODY, like RFC 1510 says, in
         * case someone actually implements it correctly.
         */
        retval = krb5_k_verify_checksum(context, key,
                                        KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
                                        &safe_body, his_cksum, &valid);
        if (!valid) {
            retval = KRB5KRB_AP_ERR_MODIFIED;
            goto cleanup;
        }
    }

    replaydata->timestamp = message->timestamp;
    replaydata->usec = message->usec;
    replaydata->seq = message->seq_number;

    *outbuf = message->user_data;
    message->user_data.data = NULL;
    retval = 0;

cleanup:
    krb5_free_safe(context, message);
    return retval;
}
Beispiel #8
0
static krb5_error_code
k5_pac_verify_server_checksum(krb5_context context,
                              const krb5_pac pac,
                              const krb5_keyblock *server)
{
    krb5_error_code ret;
    krb5_data pac_data; /* PAC with zeroed checksums */
    krb5_checksum checksum;
    krb5_data checksum_data;
    krb5_boolean valid;
    krb5_octet *p;

    ret = k5_pac_locate_buffer(context, pac,
                               PAC_SERVER_CHECKSUM, &checksum_data);
    if (ret != 0)
        return ret;

    if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH)
        return KRB5_BAD_MSIZE;

    p = (krb5_octet *)checksum_data.data;
    checksum.checksum_type = load_32_le(p);
    checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
    checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
    if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
        return KRB5KRB_AP_ERR_INAPP_CKSUM;

    pac_data.length = pac->data.length;
    pac_data.data = malloc(pac->data.length);
    if (pac_data.data == NULL)
        return ENOMEM;

    memcpy(pac_data.data, pac->data.data, pac->data.length);

    /* Zero out both checksum buffers */
    ret = k5_pac_zero_signature(context, pac,
                                PAC_SERVER_CHECKSUM, &pac_data);
    if (ret != 0) {
        free(pac_data.data);
        return ret;
    }

    ret = k5_pac_zero_signature(context, pac,
                                PAC_PRIVSVR_CHECKSUM, &pac_data);
    if (ret != 0) {
        free(pac_data.data);
        return ret;
    }

    ret = krb5_c_verify_checksum(context, server,
                                 KRB5_KEYUSAGE_APP_DATA_CKSUM,
                                 &pac_data, &checksum, &valid);

    free(pac_data.data);

    if (ret != 0) {
        return ret;
    }

    if (valid == FALSE)
        ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;

    return ret;
}
Beispiel #9
0
int
ksm_process_in_msg(struct snmp_secmod_incoming_params *parms)
{
    long            temp;
    krb5_cksumtype  cksumtype;
    krb5_auth_context auth_context = NULL;
    krb5_error_code retcode;
    krb5_checksum   checksum;
    krb5_data       ap_req, ivector;
    krb5_flags      flags;
    krb5_keyblock  *subkey = NULL;
#ifdef MIT_NEW_CRYPTO
    krb5_data       input, output;
    krb5_boolean    valid;
    krb5_enc_data   in_crypt;
#else                           /* MIT_NEW_CRYPTO */
    krb5_encrypt_block eblock;
#endif                          /* MIT_NEW_CRYPTO */
    krb5_ticket    *ticket = NULL;
    int             retval = SNMPERR_SUCCESS, response = 0;
    size_t          length =
        parms->wholeMsgLen - (u_int) (parms->secParams - parms->wholeMsg);
    u_char         *current = parms->secParams, type;
    size_t          cksumlength, blocksize;
    long            hint;
    char           *cname;
    struct ksm_secStateRef *ksm_state;
    struct ksm_cache_entry *entry;

    DEBUGMSGTL(("ksm", "Processing has begun\n"));

    checksum.contents = NULL;
    ap_req.data = NULL;
    ivector.length = 0;
    ivector.data = NULL;

    /*
     * First, parse the security parameters (because we need the subkey inside
     * of the ticket to do anything
     */

    if ((current = asn_parse_sequence(current, &length, &type,
                                      (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                       ASN_OCTET_STR),
                                      "ksm first octet")) == NULL) {
        DEBUGMSGTL(("ksm", "Initial security paramter parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    if ((current = asn_parse_sequence(current, &length, &type,
                                      (ASN_SEQUENCE | ASN_CONSTRUCTOR),
                                      "ksm sequence")) == NULL) {
        DEBUGMSGTL(("ksm",
                    "Security parameter sequence parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    if ((current = asn_parse_int(current, &length, &type, &temp,
                                 sizeof(temp))) == NULL) {
        DEBUGMSGTL(("ksm", "Security parameter checksum type parsing"
                    "failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    cksumtype = temp;

#ifdef MIT_NEW_CRYPTO
    if (!krb5_c_valid_cksumtype(cksumtype)) {
        DEBUGMSGTL(("ksm", "Invalid checksum type (%d)\n", cksumtype));

        retval = SNMPERR_KRB5;
        snmp_set_detail("Invalid checksum type");
        goto error;
    }

    if (!krb5_c_is_keyed_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
                    cksumtype));
        snmp_set_detail("Checksum is not a keyed checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (!krb5_c_is_coll_proof_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
                    "checksum\n", cksumtype));
        snmp_set_detail("Checksum is not a collision-proof checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }
#else /* ! MIT_NEW_CRYPTO */
    if (!valid_cksumtype(cksumtype)) {
        DEBUGMSGTL(("ksm", "Invalid checksum type (%d)\n", cksumtype));

        retval = SNMPERR_KRB5;
        snmp_set_detail("Invalid checksum type");
        goto error;
    }

    if (!is_keyed_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
                    cksumtype));
        snmp_set_detail("Checksum is not a keyed checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (!is_coll_proof_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
                    "checksum\n", cksumtype));
        snmp_set_detail("Checksum is not a collision-proof checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }
#endif /* MIT_NEW_CRYPTO */

    checksum.checksum_type = cksumtype;

    cksumlength = length;

    if ((current = asn_parse_sequence(current, &cksumlength, &type,
                                      (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                       ASN_OCTET_STR), "ksm checksum")) ==
        NULL) {
        DEBUGMSGTL(("ksm",
                    "Security parameter checksum parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    checksum.contents = malloc(cksumlength);
    if (!checksum.contents) {
        DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum.\n",
                    cksumlength));
        retval = SNMPERR_MALLOC;
        goto error;
    }

    memcpy(checksum.contents, current, cksumlength);

    checksum.length = cksumlength;
    checksum.checksum_type = cksumtype;

    /*
     * Zero out the checksum so the validation works correctly
     */

    memset(current, 0, cksumlength);

    current += cksumlength;
    length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);

    if ((current = asn_parse_sequence(current, &length, &type,
                                      (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                       ASN_OCTET_STR), "ksm ap_req")) ==
        NULL) {
        DEBUGMSGTL(("ksm", "KSM security parameter AP_REQ/REP parsing "
                    "failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    ap_req.length = length;
    ap_req.data = malloc(length);
    if (!ap_req.data) {
        DEBUGMSGTL(("ksm",
                    "KSM unable to malloc %d bytes for AP_REQ/REP.\n",
                    length));
        retval = SNMPERR_MALLOC;
        goto error;
    }

    memcpy(ap_req.data, current, length);

    current += length;
    length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);

    if ((current = asn_parse_int(current, &length, &type, &hint,
                                 sizeof(hint))) == NULL) {
        DEBUGMSGTL(("ksm",
                    "KSM security parameter hint parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    /*
     * Okay!  We've got it all!  Now try decoding the damn ticket.
     *
     * But of course there's a WRINKLE!  We need to figure out if we're
     * processing a AP_REQ or an AP_REP.  How do we do that?  We're going
     * to cheat, and look at the first couple of bytes (which is what
     * the Kerberos library routines do anyway).
     *
     * If there are ever new Kerberos message formats, we'll need to fix
     * this here.
     *
     * If it's a _response_, then we need to get the auth_context
     * from our cache.
     */

    if (ap_req.length
        && (ap_req.data[0] == 0x6e || ap_req.data[0] == 0x4e)) {

        /*
         * We need to initalize the authorization context, and set the
         * replay cache in it (and initialize the replay cache if we
         * haven't already
         */

        retcode = krb5_auth_con_init(kcontext, &auth_context);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_auth_con_init failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

        if (!rcache) {
            krb5_data       server;
            server.data = "host";
            server.length = strlen(server.data);

            retcode = krb5_get_server_rcache(kcontext, &server, &rcache);

            if (retcode) {
                DEBUGMSGTL(("ksm", "krb5_get_server_rcache failed: %s\n",
                            error_message(retcode)));
                retval = SNMPERR_KRB5;
                snmp_set_detail(error_message(retcode));
                goto error;
            }
        }

        retcode = krb5_auth_con_setrcache(kcontext, auth_context, rcache);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_auth_con_setrcache failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

        retcode = krb5_rd_req(kcontext, &auth_context, &ap_req, NULL,
                              keytab, &flags, &ticket);

        krb5_auth_con_setrcache(kcontext, auth_context, NULL);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_rd_req() failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

        retcode =
            krb5_unparse_name(kcontext, ticket->enc_part2->client, &cname);

        if (retcode == 0) {
            DEBUGMSGTL(("ksm", "KSM authenticated principal name: %s\n",
                        cname));
            free(cname);
        }

        /*
         * Check to make sure AP_OPTS_MUTUAL_REQUIRED was set
         */

        if (!(flags & AP_OPTS_MUTUAL_REQUIRED)) {
            DEBUGMSGTL(("ksm",
                        "KSM MUTUAL_REQUIRED not set in request!\n"));
            retval = SNMPERR_KRB5;
            snmp_set_detail("MUTUAL_REQUIRED not set in message");
            goto error;
        }

        retcode =
            krb5_auth_con_getremotesubkey(kcontext, auth_context, &subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM remote subkey retrieval failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

    } else if (ap_req.length && (ap_req.data[0] == 0x6f ||
                                 ap_req.data[0] == 0x4f)) {
        /*
         * Looks like a response; let's see if we've got that auth_context
         * in our cache.
         */

        krb5_ap_rep_enc_part *repl = NULL;

        response = 1;

        entry = ksm_get_cache(parms->pdu->msgid);

        if (!entry) {
            DEBUGMSGTL(("ksm",
                        "KSM: Unable to find auth_context for PDU with "
                        "message ID of %ld\n", parms->pdu->msgid));
            retval = SNMPERR_KRB5;
            goto error;
        }

        auth_context = entry->auth_context;

        /*
         * In that case, let's call the rd_rep function
         */

        retcode = krb5_rd_rep(kcontext, auth_context, &ap_req, &repl);

        if (repl)
            krb5_free_ap_rep_enc_part(kcontext, repl);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            goto error;
        }

        DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() decoded successfully.\n"));

        retcode =
            krb5_auth_con_getlocalsubkey(kcontext, auth_context, &subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "Unable to retrieve local subkey: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail("Unable to retrieve local subkey");
            goto error;
        }

    } else {
        DEBUGMSGTL(("ksm", "Unknown Kerberos message type (%02x)\n",
                    ap_req.data[0]));
        retval = SNMPERR_KRB5;
        snmp_set_detail("Unknown Kerberos message type");
        goto error;
    }

#ifdef MIT_NEW_CRYPTO
    input.data = (char *) parms->wholeMsg;
    input.length = parms->wholeMsgLen;

    retcode =
        krb5_c_verify_checksum(kcontext, subkey, KSM_KEY_USAGE_CHECKSUM,
                               &input, &checksum, &valid);
#else                           /* MIT_NEW_CRYPTO */
    retcode = krb5_verify_checksum(kcontext, cksumtype, &checksum,
                                   parms->wholeMsg, parms->wholeMsgLen,
                                   (krb5_pointer) subkey->contents,
                                   subkey->length);
#endif                          /* MIT_NEW_CRYPTO */

    if (retcode) {
        DEBUGMSGTL(("ksm", "KSM checksum verification failed: %s\n",
                    error_message(retcode)));
        retval = SNMPERR_KRB5;
        snmp_set_detail(error_message(retcode));
        goto error;
    }

    /*
     * Don't ask me why they didn't simply return an error, but we have
     * to check to see if "valid" is false.
     */

#ifdef MIT_NEW_CRYPTO
    if (!valid) {
        DEBUGMSGTL(("ksm", "Computed checksum did not match supplied "
                    "checksum!\n"));
        retval = SNMPERR_KRB5;
        snmp_set_detail
            ("Computed checksum did not match supplied checksum");
        goto error;
    }
#endif                          /* MIT_NEW_CRYPTO */

    /*
     * Handle an encrypted PDU.  Note that it's an OCTET_STRING of the
     * output of whatever Kerberos cryptosystem you're using (defined by
     * the encryption type).  Note that this is NOT the EncryptedData
     * sequence - it's what goes in the "cipher" field of EncryptedData.
     */

    if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {

        if ((current = asn_parse_sequence(current, &length, &type,
                                          (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                           ASN_OCTET_STR), "ksm pdu")) ==
            NULL) {
            DEBUGMSGTL(("ksm", "KSM sPDU octet decoding failed\n"));
            retval = SNMPERR_ASN_PARSE_ERR;
            goto error;
        }

        /*
         * The PDU is now pointed at by "current", and the length is in
         * "length".
         */

        DEBUGMSGTL(("ksm", "KSM starting sPDU decode\n"));

        /*
         * We need to set up a blank initialization vector for the decryption.
         * Use a block of all zero's (which is dependent on the block size
         * of the encryption method).
         */

#ifdef MIT_NEW_CRYPTO

        retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize);

        if (retcode) {
            DEBUGMSGTL(("ksm",
                        "Unable to determine crypto block size: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#else                           /* MIT_NEW_CRYPTO */

        blocksize =
            krb5_enctype_array[subkey->enctype]->system->block_length;

#endif                          /* MIT_NEW_CRYPTO */

        ivector.data = malloc(blocksize);

        if (!ivector.data) {
            DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivector\n",
                        blocksize));
            retval = SNMPERR_MALLOC;
            goto error;
        }

        ivector.length = blocksize;
        memset(ivector.data, 0, blocksize);

#ifndef MIT_NEW_CRYPTO

        krb5_use_enctype(kcontext, &eblock, subkey->enctype);

        retcode = krb5_process_key(kcontext, &eblock, subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM key post-processing failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#endif                          /* !MIT_NEW_CRYPTO */

        if (length > *parms->scopedPduLen) {
            DEBUGMSGTL(("ksm", "KSM not enough room - have %d bytes to "
                        "decrypt but only %d bytes available\n", length,
                        *parms->scopedPduLen));
            retval = SNMPERR_TOO_LONG;
#ifndef MIT_NEW_CRYPTO
            krb5_finish_key(kcontext, &eblock);
#endif                          /* ! MIT_NEW_CRYPTO */
            goto error;
        }
#ifdef MIT_NEW_CRYPTO
        in_crypt.ciphertext.data = (char *) current;
        in_crypt.ciphertext.length = length;
        in_crypt.enctype = subkey->enctype;
        output.data = (char *) *parms->scopedPdu;
        output.length = *parms->scopedPduLen;

        retcode =
            krb5_c_decrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION,
                           &ivector, &in_crypt, &output);
#else                           /* MIT_NEW_CRYPTO */

        retcode = krb5_decrypt(kcontext, (krb5_pointer) current,
                               *parms->scopedPdu, length, &eblock,
                               ivector.data);

        krb5_finish_key(kcontext, &eblock);

#endif                          /* MIT_NEW_CRYPTO */

        if (retcode) {
            DEBUGMSGTL(("ksm", "Decryption failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        *parms->scopedPduLen = length;

    } else {
        /*
         * Clear PDU
         */

        *parms->scopedPdu = current;
        *parms->scopedPduLen =
            parms->wholeMsgLen - (current - parms->wholeMsg);
    }

    /*
     * A HUGE GROSS HACK
     */

    *parms->maxSizeResponse = parms->maxMsgSize - 200;

    DEBUGMSGTL(("ksm", "KSM processing complete\n"));

    /*
     * Set the secName to the right value (a hack for now).  But that's
     * only used for when we're processing a request, not a response.
     */

    if (!response) {

        retcode = krb5_unparse_name(kcontext, ticket->enc_part2->client,
                                    &cname);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM krb5_unparse_name failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        if (strlen(cname) > *parms->secNameLen + 1) {
            DEBUGMSGTL(("ksm",
                        "KSM: Principal length (%d) is too long (%d)\n",
                        strlen(cname), parms->secNameLen));
            retval = SNMPERR_TOO_LONG;
            free(cname);
            goto error;
        }

        strcpy(parms->secName, cname);
        *parms->secNameLen = strlen(cname);

        free(cname);

        /*
         * Also, if we're not a response, keep around our auth_context so we
         * can encode the reply message correctly
         */

        ksm_state = SNMP_MALLOC_STRUCT(ksm_secStateRef);

        if (!ksm_state) {
            DEBUGMSGTL(("ksm", "KSM unable to malloc memory for "
                        "ksm_secStateRef\n"));
            retval = SNMPERR_MALLOC;
            goto error;
        }

        ksm_state->auth_context = auth_context;
        auth_context = NULL;
        ksm_state->cksumtype = cksumtype;

        *parms->secStateRef = ksm_state;
    } else {

        /*
         * We _still_ have to set the secName in process_in_msg().  Do
         * that now with what we were passed in before (we cached it,
         * remember?)
         */

        memcpy(parms->secName, entry->secName, entry->secNameLen);
        *parms->secNameLen = entry->secNameLen;
    }

    /*
     * Just in case
     */

    parms->secEngineID = (u_char *) "";
    *parms->secEngineIDLen = 0;

    auth_context = NULL;        /* So we don't try to free it on success */

  error:
    if (retval == SNMPERR_ASN_PARSE_ERR &&
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0)
        DEBUGMSGTL(("ksm", "Failed to increment statistics.\n"));

    if (subkey)
        krb5_free_keyblock(kcontext, subkey);

    if (checksum.contents)
        free(checksum.contents);

    if (ivector.data)
        free(ivector.data);

    if (ticket)
        krb5_free_ticket(kcontext, ticket);

    if (!response && auth_context)
        krb5_auth_con_free(kcontext, auth_context);

    if (ap_req.data)
        free(ap_req.data);

    return retval;
}