コード例 #1
0
ファイル: k5sealiov.c プロジェクト: FarazShaikh/likewise-open
OM_uint32
kg_seal_iov(OM_uint32 *minor_status,
            gss_ctx_id_t context_handle,
            int conf_req_flag,
            gss_qop_t qop_req,
            int *conf_state,
            gss_iov_buffer_desc *iov,
            int iov_count,
            int toktype)
{
    krb5_gss_ctx_id_rec *ctx;
    krb5_error_code code;
    krb5_context context;

    if (qop_req != 0) {
        *minor_status = (OM_uint32)G_UNKNOWN_QOP;
        return GSS_S_FAILURE;
    }

    if (!kg_validate_ctx_id(context_handle)) {
        *minor_status = (OM_uint32)G_VALIDATE_FAILED;
        return GSS_S_NO_CONTEXT;
    }

    ctx = (krb5_gss_ctx_id_rec *)context_handle;
    if (!ctx->established) {
        *minor_status = KG_CTX_INCOMPLETE;
        return GSS_S_NO_CONTEXT;
    }

    if (conf_req_flag && kg_integ_only_iov(iov, iov_count)) {
        /* may be more sensible to return an error here */
        conf_req_flag = FALSE;
    }

    context = ctx->k5_context;
    switch (ctx->proto) {
    case 0:
        code = make_seal_token_v1_iov(context, ctx, conf_req_flag,
                                      conf_state, iov, iov_count, toktype);
        break;
    case 1:
        code = gss_krb5int_make_seal_token_v3_iov(context, ctx, conf_req_flag,
                                                  conf_state, iov, iov_count, toktype);
        break;
    default:
        code = G_UNKNOWN_QOP;
        break;
    }

    if (code != 0) {
        *minor_status = code;
        save_error_info(*minor_status, context);
        return GSS_S_FAILURE;
    }

    *minor_status = 0;

    return GSS_S_COMPLETE;
}
コード例 #2
0
ファイル: duplicate_name.c プロジェクト: Brainiarc7/pbis
OM_uint32 krb5_gss_duplicate_name(OM_uint32  *minor_status,
                                  const gss_name_t input_name,
                                  gss_name_t *dest_name)
{
    krb5_context context;
    krb5_error_code code;
    krb5_gss_name_t princ, outprinc;

    if (minor_status)
        *minor_status = 0;

    code = krb5_gss_init_context(&context);
    if (code) {
        if (minor_status)
            *minor_status = code;
        return GSS_S_FAILURE;
    }

    if (! kg_validate_name(input_name)) {
        if (minor_status)
            *minor_status = (OM_uint32) G_VALIDATE_FAILED;
        krb5_free_context(context);
        return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
    }

    princ = (krb5_gss_name_t)input_name;
    if ((code = kg_duplicate_name(context, princ, KG_INIT_NAME_INTERN, &outprinc))) {
        *minor_status = code;
        save_error_info(*minor_status, context);
        krb5_free_context(context);
        return(GSS_S_FAILURE);
    }
    krb5_free_context(context);
    *dest_name = (gss_name_t) outprinc;
    assert(kg_validate_name(*dest_name));
    return(GSS_S_COMPLETE);

}
コード例 #3
0
ファイル: k5sealv3.c プロジェクト: apprisi/illumos-gate
OM_uint32
gss_krb5int_unseal_token_v3(krb5_context *contextptr,
			    OM_uint32 *minor_status,
			    krb5_gss_ctx_id_rec *ctx,
			    unsigned char *ptr, int bodysize,
			    gss_buffer_t message_buffer,
			    int *conf_state, int *qop_state, int toktype)
{
    krb5_context context = *contextptr;
    krb5_data plain;
    gssint_uint64 seqnum;
    size_t ec, rrc;
    int key_usage;
    unsigned char acceptor_flag;
    krb5_checksum sum;
    krb5_error_code err;
    krb5_boolean valid;
    krb5_keyblock *key;

    ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
    ASSERT(ctx->big_endian == 0);
    ASSERT(ctx->proto == 1);

    if (qop_state)
	*qop_state = GSS_C_QOP_DEFAULT;

    acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
    key_usage = (toktype == KG_TOK_WRAP_MSG
		 ? (!ctx->initiate
		    ? KG_USAGE_INITIATOR_SEAL
		    : KG_USAGE_ACCEPTOR_SEAL)
		 : (!ctx->initiate
		    ? KG_USAGE_INITIATOR_SIGN
		    : KG_USAGE_ACCEPTOR_SIGN));

    /* Oops.  I wrote this code assuming ptr would be at the start of
       the token header.  */
    ptr -= 2;
    bodysize += 2;

    if (bodysize < 16) {
    defective:
	*minor_status = 0;
	return GSS_S_DEFECTIVE_TOKEN;
    }
    if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
	*minor_status = (OM_uint32)G_BAD_DIRECTION;
	return GSS_S_BAD_SIG;
    }

    /* Two things to note here.

       First, we can't really enforce the use of the acceptor's subkey,
       if we're the acceptor; the initiator may have sent messages
       before getting the subkey.  We could probably enforce it if
       we're the initiator.

       Second, if someone tweaks the code to not set the flag telling
       the krb5 library to generate a new subkey in the AP-REP
       message, the MIT library may include a subkey anyways --
       namely, a copy of the AP-REQ subkey, if it was provided.  So
       the initiator may think we wanted a subkey, and set the flag,
       even though we weren't trying to set the subkey.  The "other"
       key, the one not asserted by the acceptor, will have the same
       value in that case, though, so we can just ignore the flag.  */
    if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
	key = ctx->acceptor_subkey;
    } else {
	key = ctx->enc;
    }

#ifdef _KERNEL
    context->kef_cipher_mt = get_cipher_mech_type(context, key);
    context->kef_hash_mt = get_hash_mech_type(context, key);

    if ((err = init_key_kef(context->kef_cipher_mt, key))) {
	return (GSS_S_FAILURE);
    }
#endif /* _KERNEL */

    if (toktype == KG_TOK_WRAP_MSG) {
	if (load_16_be(ptr) != 0x0504)
	    goto defective;
	if (ptr[3] != 0xff)
	    goto defective;
	ec = load_16_be(ptr+4);
	rrc = load_16_be(ptr+6);
	seqnum = load_64_be(ptr+8);
	if (!rotate_left(ptr+16, bodysize-16, rrc)) {
	no_mem:
	    *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	}
	if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
	    /* confidentiality */
	    krb5_enc_data cipher;
	    unsigned char *althdr;
            size_t plainlen;

	    if (conf_state)
		*conf_state = 1;
	    /* Do we have no decrypt_size function?

	       For all current cryptosystems, the ciphertext size will
	       be larger than the plaintext size.  */
	    cipher.enctype = key->enctype;
	    cipher.ciphertext.length = bodysize - 16;
	    cipher.ciphertext.data = (char *)ptr + 16;
	    plain.length = plainlen = bodysize - 16;
	    plain.data = MALLOC(plain.length);
	    if (plain.data == NULL)
		goto no_mem;
	    err = krb5_c_decrypt(context, key, key_usage, 0,
				 &cipher, &plain);
	    if (err) {
		goto error;
	    }
	    /* Don't use bodysize here!  Use the fact that
	       plain.length has been adjusted to the
	       correct length.  */
	    althdr = (uchar_t *)plain.data + plain.length - 16;
	    if (load_16_be(althdr) != 0x0504
		|| althdr[2] != ptr[2]
		|| althdr[3] != ptr[3]
		|| memcmp(althdr+8, ptr+8, 8)) {
		FREE(plain.data, plainlen);
		goto defective;
	    }
	    message_buffer->length = plain.length - ec - 16;
	    message_buffer->value = MALLOC(message_buffer->length);
	    if (message_buffer->value == NULL) {
		FREE(plain.data, plainlen);
		goto no_mem;
	    }
	    (void) memcpy(message_buffer->value, plain.data,
			message_buffer->length);
	    FREE(plain.data, plainlen);
	} else {
	    /* no confidentiality */
	    if (conf_state)
		*conf_state = 0;
	    if (ec + 16 < ec)
		/* overflow check */
		goto defective;
	    if (ec + 16 > bodysize)
		goto defective;
	    /* We have: header | msg | cksum.
	       We need cksum(msg | header).
	       Rotate the first two.  */
	    store_16_be(0, ptr+4);
	    store_16_be(0, ptr+6);
	    plain.length = bodysize-ec;
	    plain.data = (char *)ptr;
	    if (!rotate_left(ptr, bodysize-ec, 16))
		goto no_mem;
	    sum.length = ec;
	    if (sum.length != ctx->cksum_size) {
		*minor_status = 0;
		return GSS_S_BAD_SIG;
	    }
	    sum.contents = ptr+bodysize-ec;
	    sum.checksum_type = ctx->cksumtype;
	    err = krb5_c_verify_checksum(context, key, key_usage,
					 &plain, &sum, &valid);
	    if (err) {
		*minor_status = err;
		return GSS_S_BAD_SIG;
	    }
	    if (!valid) {
		*minor_status = 0;
		return GSS_S_BAD_SIG;
	    }
	    message_buffer->length = plain.length - 16;
	    message_buffer->value = MALLOC(message_buffer->length);
	    if (message_buffer->value == NULL)
		goto no_mem;
	    (void) memcpy(message_buffer->value,
		plain.data, message_buffer->length);

		/*
		 * Solaris Kerberos: Restore the original token.
		 * This allows the token to be detected as a duplicate if it
		 * is passed in to gss_unwrap() again.
		 */
		if (!rotate_left(ptr, bodysize-ec, bodysize - ec - 16))
			goto no_mem;
		store_16_be(ec, ptr+4);
		store_16_be(rrc, ptr+6);
	}
	err = g_order_check(&ctx->seqstate, seqnum);
	*minor_status = 0;
	return err;
    } else if (toktype == KG_TOK_MIC_MSG) {
	/* wrap token, no confidentiality */
	if (load_16_be(ptr) != 0x0404)
	    goto defective;
    verify_mic_1:
	if (ptr[3] != 0xff)
	    goto defective;
	if (load_32_be(ptr+4) != (ulong_t)0xffffffffU)
	    goto defective;
	seqnum = load_64_be(ptr+8);
	plain.length = message_buffer->length + 16;
	plain.data = MALLOC(plain.length);
	if (plain.data == NULL)
	    goto no_mem;
	if (message_buffer->length)
	    (void) memcpy(plain.data,
		message_buffer->value, message_buffer->length);
	(void) memcpy(plain.data + message_buffer->length, ptr, 16);
	sum.length = bodysize - 16;
	sum.contents = ptr + 16;
	sum.checksum_type = ctx->cksumtype;
	err = krb5_c_verify_checksum(context, key, key_usage,
				     &plain, &sum, &valid);
	if (err) {
	error:
	    FREE(plain.data, plain.length);
	    *minor_status = err;
	    save_error_info(*minor_status, context);
	    return GSS_S_BAD_SIG; /* XXX */
	}
	FREE(plain.data, plain.length);
	if (!valid) {
	    *minor_status = 0;
	    return GSS_S_BAD_SIG;
	}
	err = g_order_check(&ctx->seqstate, seqnum);
	*minor_status = 0;
	return err;
    } else if (toktype == KG_TOK_DEL_CTX) {
	if (load_16_be(ptr) != 0x0405)
	    goto defective;
	message_buffer = (gss_buffer_t)&empty_message;
	goto verify_mic_1;
    } else {
	goto defective;
    }
}
コード例 #4
0
ファイル: export_name.c プロジェクト: OPSF/uClinux
OM_uint32 krb5_gss_export_name(OM_uint32  *minor_status,
                               const gss_name_t input_name,
                               gss_buffer_t exported_name)
{
    krb5_context context;
    krb5_error_code code;
    size_t length;
    char *str;
    unsigned char *cp;

    if (minor_status)
        *minor_status = 0;

    code = krb5_gss_init_context(&context);
    if (code) {
        if (minor_status)
            *minor_status = code;
        return GSS_S_FAILURE;
    }

    exported_name->length = 0;
    exported_name->value = NULL;

    if (! kg_validate_name(input_name)) {
        if (minor_status)
            *minor_status = (OM_uint32) G_VALIDATE_FAILED;
        krb5_free_context(context);
        return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
    }

    if ((code = krb5_unparse_name(context, (krb5_principal) input_name,
                                  &str))) {
        if (minor_status)
            *minor_status = code;
        save_error_info((OM_uint32)code, context);
        krb5_free_context(context);
        return(GSS_S_FAILURE);
    }

    krb5_free_context(context);
    length = strlen(str);
    exported_name->length = 10 + length + gss_mech_krb5->length;
    exported_name->value = malloc(exported_name->length);
    if (!exported_name->value) {
        free(str);
        if (minor_status)
            *minor_status = ENOMEM;
        return(GSS_S_FAILURE);
    }
    cp = exported_name->value;

    /* Note: we assume the OID will be less than 128 bytes... */
    *cp++ = 0x04; *cp++ = 0x01;
    store_16_be(gss_mech_krb5->length+2, cp);
    cp += 2;
    *cp++ = 0x06;
    *cp++ = (gss_mech_krb5->length) & 0xFF;
    memcpy(cp, gss_mech_krb5->elements, gss_mech_krb5->length);
    cp += gss_mech_krb5->length;
    store_32_be(length, cp);
    cp += 4;
    memcpy(cp, str, length);

    free(str);

    return(GSS_S_COMPLETE);
}
コード例 #5
0
OM_uint32 KRB5_CALLCONV
gss_krb5int_copy_ccache(OM_uint32 *minor_status,
                        gss_cred_id_t cred_handle,
                        const gss_OID desired_object,
                        const gss_buffer_t value)
{
    krb5_gss_cred_id_t k5creds;
    krb5_cc_cursor cursor;
    krb5_creds creds;
    krb5_error_code code;
    krb5_context context;
    krb5_ccache out_ccache;

    assert(value->length == sizeof(out_ccache));

    if (value->length != sizeof(out_ccache))
        return GSS_S_FAILURE;

    out_ccache = (krb5_ccache)value->value;

    /* cred handle will have been validated by gssspi_set_cred_option() */

    k5creds = (krb5_gss_cred_id_t) cred_handle;
    code = k5_mutex_lock(&k5creds->lock);
    if (code) {
        *minor_status = code;
        return GSS_S_FAILURE;
    }
    if (k5creds->usage == GSS_C_ACCEPT) {
        k5_mutex_unlock(&k5creds->lock);
        *minor_status = (OM_uint32) G_BAD_USAGE;
        return(GSS_S_FAILURE);
    }

    code = krb5_gss_init_context(&context);
    if (code) {
        k5_mutex_unlock(&k5creds->lock);
        *minor_status = code;
        return GSS_S_FAILURE;
    }

    code = krb5_cc_start_seq_get(context, k5creds->ccache, &cursor);
    if (code) {
        k5_mutex_unlock(&k5creds->lock);
        *minor_status = code;
        save_error_info(*minor_status, context);
        krb5_free_context(context);
        return(GSS_S_FAILURE);
    }
    while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor,
                                       &creds)) {
        code = krb5_cc_store_cred(context, out_ccache, &creds);
        krb5_free_cred_contents(context, &creds);
    }
    krb5_cc_end_seq_get(context, k5creds->ccache, &cursor);
    k5_mutex_unlock(&k5creds->lock);
    *minor_status = code;
    if (code)
        save_error_info(*minor_status, context);
    krb5_free_context(context);
    return code ? GSS_S_FAILURE : GSS_S_COMPLETE;
}
コード例 #6
0
ファイル: k5unsealiov.c プロジェクト: WeiY/krb5
/*
 * Caller must provide TOKEN | DATA | PADDING | TRAILER, except
 * for DCE in which case it can just provide TOKEN | DATA (must
 * guarantee that DATA is padded)
 */
static OM_uint32
kg_unseal_iov_token(OM_uint32 *minor_status,
                    krb5_gss_ctx_id_rec *ctx,
                    int *conf_state,
                    gss_qop_t *qop_state,
                    gss_iov_buffer_desc *iov,
                    int iov_count,
                    int toktype)
{
    krb5_error_code code;
    krb5_context context = ctx->k5_context;
    unsigned char *ptr;
    gss_iov_buffer_t header;
    gss_iov_buffer_t padding;
    gss_iov_buffer_t trailer;
    size_t input_length;
    unsigned int bodysize;
    int toktype2;

    header = kg_locate_header_iov(iov, iov_count, toktype);
    if (header == NULL) {
        *minor_status = EINVAL;
        return GSS_S_FAILURE;
    }

    padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
    trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);

    ptr = (unsigned char *)header->buffer.value;
    input_length = header->buffer.length;

    if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
        toktype == KG_TOK_WRAP_MSG) {
        size_t data_length, assoc_data_length;

        kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);

        input_length += data_length - assoc_data_length;

        if (padding != NULL)
            input_length += padding->buffer.length;

        if (trailer != NULL)
            input_length += trailer->buffer.length;
    }

    code = g_verify_token_header(ctx->mech_used,
                                 &bodysize, &ptr, -1,
                                 input_length, 0);
    if (code != 0) {
        *minor_status = code;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if (bodysize < 2) {
        *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    toktype2 = load_16_be(ptr);

    ptr += 2;
    bodysize -= 2;

    switch (toktype2) {
    case KG2_TOK_MIC_MSG:
    case KG2_TOK_WRAP_MSG:
    case KG2_TOK_DEL_CTX:
        code = gss_krb5int_unseal_v3_iov(context, minor_status, ctx, iov, iov_count,
                                         conf_state, qop_state, toktype);
        break;
    case KG_TOK_MIC_MSG:
    case KG_TOK_WRAP_MSG:
    case KG_TOK_DEL_CTX:
        code = kg_unseal_v1_iov(context, minor_status, ctx, iov, iov_count,
                                (size_t)(ptr - (unsigned char *)header->buffer.value),
                                conf_state, qop_state, toktype);
        break;
    default:
        *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
        code = GSS_S_DEFECTIVE_TOKEN;
        break;
    }

    if (code != 0)
        save_error_info(*minor_status, context);

    return code;
}
コード例 #7
0
ファイル: k5sealv3.c プロジェクト: gladiac/krb5
OM_uint32
gss_krb5int_unseal_token_v3(krb5_context *contextptr,
                            OM_uint32 *minor_status,
                            krb5_gss_ctx_id_rec *ctx,
                            unsigned char *ptr, unsigned int bodysize,
                            gss_buffer_t message_buffer,
                            int *conf_state, gss_qop_t *qop_state, int toktype)
{
    krb5_context context = *contextptr;
    krb5_data plain;
    uint64_t seqnum;
    size_t ec, rrc;
    int key_usage;
    unsigned char acceptor_flag;
    krb5_checksum sum;
    krb5_error_code err;
    krb5_boolean valid;
    krb5_key key;
    krb5_cksumtype cksumtype;

    if (qop_state)
        *qop_state = GSS_C_QOP_DEFAULT;

    acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
    key_usage = (toktype == KG_TOK_WRAP_MSG
                 ? (!ctx->initiate
                    ? KG_USAGE_INITIATOR_SEAL
                    : KG_USAGE_ACCEPTOR_SEAL)
                 : (!ctx->initiate
                    ? KG_USAGE_INITIATOR_SIGN
                    : KG_USAGE_ACCEPTOR_SIGN));

    /* Oops.  I wrote this code assuming ptr would be at the start of
       the token header.  */
    ptr -= 2;
    bodysize += 2;

    if (bodysize < 16) {
    defective:
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }
    if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
        *minor_status = (OM_uint32)G_BAD_DIRECTION;
        return GSS_S_BAD_SIG;
    }

    /* Two things to note here.

       First, we can't really enforce the use of the acceptor's subkey,
       if we're the acceptor; the initiator may have sent messages
       before getting the subkey.  We could probably enforce it if
       we're the initiator.

       Second, if someone tweaks the code to not set the flag telling
       the krb5 library to generate a new subkey in the AP-REP
       message, the MIT library may include a subkey anyways --
       namely, a copy of the AP-REQ subkey, if it was provided.  So
       the initiator may think we wanted a subkey, and set the flag,
       even though we weren't trying to set the subkey.  The "other"
       key, the one not asserted by the acceptor, will have the same
       value in that case, though, so we can just ignore the flag.  */
    if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
        key = ctx->acceptor_subkey;
        cksumtype = ctx->acceptor_subkey_cksumtype;
    } else {
        key = ctx->subkey;
        cksumtype = ctx->cksumtype;
    }
    assert(key != NULL);

    if (toktype == KG_TOK_WRAP_MSG) {
        if (load_16_be(ptr) != KG2_TOK_WRAP_MSG)
            goto defective;
        if (ptr[3] != 0xff)
            goto defective;
        ec = load_16_be(ptr+4);
        rrc = load_16_be(ptr+6);
        seqnum = load_64_be(ptr+8);
        if (!gss_krb5int_rotate_left(ptr+16, bodysize-16, rrc)) {
        no_mem:
            *minor_status = ENOMEM;
            return GSS_S_FAILURE;
        }
        if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
            /* confidentiality */
            krb5_enc_data cipher;
            unsigned char *althdr;

            if (conf_state)
                *conf_state = 1;
            /* Do we have no decrypt_size function?

               For all current cryptosystems, the ciphertext size will
               be larger than the plaintext size.  */
            cipher.enctype = key->keyblock.enctype;
            cipher.ciphertext.length = bodysize - 16;
            cipher.ciphertext.data = (char *)ptr + 16;
            plain.length = bodysize - 16;
            plain.data = gssalloc_malloc(plain.length);
            if (plain.data == NULL)
                goto no_mem;
            err = krb5_k_decrypt(context, key, key_usage, 0,
                                 &cipher, &plain);
            if (err) {
                gssalloc_free(plain.data);
                goto error;
            }
            /* Don't use bodysize here!  Use the fact that
               cipher.ciphertext.length has been adjusted to the
               correct length.  */
            althdr = (unsigned char *)plain.data + plain.length - 16;
            if (load_16_be(althdr) != KG2_TOK_WRAP_MSG
                || althdr[2] != ptr[2]
                || althdr[3] != ptr[3]
                || memcmp(althdr+8, ptr+8, 8)) {
                free(plain.data);
                goto defective;
            }
            message_buffer->value = plain.data;
            message_buffer->length = plain.length - ec - 16;
            if(message_buffer->length == 0) {
                gssalloc_free(message_buffer->value);
                message_buffer->value = NULL;
            }
        } else {
            size_t cksumsize;

            err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
            if (err)
                goto error;

            /* no confidentiality */
            if (conf_state)
                *conf_state = 0;
            if (ec + 16 < ec)
                /* overflow check */
                goto defective;
            if (ec + 16 > bodysize)
                goto defective;
            /* We have: header | msg | cksum.
               We need cksum(msg | header).
               Rotate the first two.  */
            store_16_be(0, ptr+4);
            store_16_be(0, ptr+6);
            plain = make_data(ptr, bodysize - ec);
            if (!gss_krb5int_rotate_left(ptr, bodysize-ec, 16))
                goto no_mem;
            sum.length = ec;
            if (sum.length != cksumsize) {
                *minor_status = 0;
                return GSS_S_BAD_SIG;
            }
            sum.contents = ptr+bodysize-ec;
            sum.checksum_type = cksumtype;
            err = krb5_k_verify_checksum(context, key, key_usage,
                                         &plain, &sum, &valid);
            if (err)
                goto error;
            if (!valid) {
                *minor_status = 0;
                return GSS_S_BAD_SIG;
            }
            message_buffer->length = plain.length - 16;
            message_buffer->value = gssalloc_malloc(message_buffer->length);
            if (message_buffer->value == NULL)
                goto no_mem;
            memcpy(message_buffer->value, plain.data, message_buffer->length);
        }
        err = g_seqstate_check(ctx->seqstate, seqnum);
        *minor_status = 0;
        return err;
    } else if (toktype == KG_TOK_MIC_MSG) {
        /* wrap token, no confidentiality */
        if (load_16_be(ptr) != KG2_TOK_MIC_MSG)
            goto defective;
    verify_mic_1:
        if (ptr[3] != 0xff)
            goto defective;
        if (load_32_be(ptr+4) != 0xffffffffL)
            goto defective;
        seqnum = load_64_be(ptr+8);
        plain.length = message_buffer->length + 16;
        plain.data = malloc(plain.length);
        if (plain.data == NULL)
            goto no_mem;
        if (message_buffer->length)
            memcpy(plain.data, message_buffer->value, message_buffer->length);
        memcpy(plain.data + message_buffer->length, ptr, 16);
        sum.length = bodysize - 16;
        sum.contents = ptr + 16;
        sum.checksum_type = cksumtype;
        err = krb5_k_verify_checksum(context, key, key_usage,
                                     &plain, &sum, &valid);
        free(plain.data);
        plain.data = NULL;
        if (err) {
        error:
            *minor_status = err;
            save_error_info(*minor_status, context);
            return GSS_S_BAD_SIG; /* XXX */
        }
        if (!valid) {
            *minor_status = 0;
            return GSS_S_BAD_SIG;
        }
        err = g_seqstate_check(ctx->seqstate, seqnum);
        *minor_status = 0;
        return err;
    } else if (toktype == KG_TOK_DEL_CTX) {
        if (load_16_be(ptr) != KG2_TOK_DEL_CTX)
            goto defective;
        message_buffer = (gss_buffer_t)&empty_message;
        goto verify_mic_1;
    } else {
        goto defective;
    }
}