static SECURITY_STATUS SEC_ENTRY kerberos_VerifySignature(PCtxtHandle phContext,
                                                          PSecBufferDesc pMessage,
                                                          ULONG MessageSeqNo, ULONG* pfQOP)
{
#ifdef WITH_GSSAPI
	KRB_CONTEXT* context;
	PSecBuffer sig_buffer, data_buffer;
	krb5_key key;
	krb5_keyusage usage;
	char* header;
	BYTE flags;
	uint16_t tok_id;
	uint64_t seq_no;
	krb5_boolean is_valid;
	krb5_crypto_iov iov[] = { { KRB5_CRYPTO_TYPE_DATA, { 0 } },
		                      { KRB5_CRYPTO_TYPE_DATA, { 0 } },
		                      { KRB5_CRYPTO_TYPE_CHECKSUM, { 0 } } };
	BYTE cmp_filler[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

	context = sspi_SecureHandleGetLowerPointer(phContext);
	if (!context)
		return SEC_E_INVALID_HANDLE;

	if (!(context->flags & SSPI_GSS_C_INTEG_FLAG))
		return SEC_E_UNSUPPORTED_FUNCTION;

	sig_buffer = sspi_FindSecBuffer(pMessage, SECBUFFER_TOKEN);
	data_buffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);

	if (!sig_buffer || !data_buffer || sig_buffer->cbBuffer < 16)
		return SEC_E_INVALID_TOKEN;

	/* Read in header info */
	header = sig_buffer->pvBuffer;
	Data_Read_UINT16_BE(header, tok_id);
	flags = header[2];
	Data_Read_UINT64_BE((header + 8), seq_no);

	/* Validate header */
	if (tok_id != TOK_ID_MIC)
		return SEC_E_INVALID_TOKEN;

	if ((flags & FLAG_SENDER_IS_ACCEPTOR) == context->acceptor || flags & FLAG_WRAP_CONFIDENTIAL)
		return SEC_E_INVALID_TOKEN;

	if (memcmp(header + 3, cmp_filler, sizeof(cmp_filler)))
		return SEC_E_INVALID_TOKEN;

	if (context->flags & ISC_REQ_SEQUENCE_DETECT && seq_no != context->remote_seq + MessageSeqNo)
		return SEC_E_OUT_OF_SEQUENCE;

	/* Find the proper key and usage */
	if (flags & FLAG_ACCEPTOR_SUBKEY)
		key = context->acceptor_key;
	else
		key = context->initiator_key ? context->initiator_key : context->session_key;
	if (!key)
		return SEC_E_INTERNAL_ERROR;
	usage = context->acceptor ? KG_USAGE_INITIATOR_SIGN : KG_USAGE_ACCEPTOR_SIGN;

	/* Fill in the iov array lengths */
	iov[0].data.length = data_buffer->cbBuffer;
	iov[1].data.length = 16;
	if (krb5_c_crypto_length_iov(context->ctx, krb5_k_key_enctype(context->ctx, key), iov,
	                             ARRAYSIZE(iov)))
		return SEC_E_INTERNAL_ERROR;

	if (sig_buffer->cbBuffer != iov[2].data.length + 16)
		return SEC_E_INTERNAL_ERROR;

	/* Set up the iov array */
	iov[0].data.data = data_buffer->pvBuffer;
	iov[1].data.data = header;
	iov[2].data.data = header + 16;

	if (krb5_k_verify_checksum_iov(context->ctx, 0, key, usage, iov, ARRAYSIZE(iov), &is_valid))
		return SEC_E_INTERNAL_ERROR;

	if (!is_valid)
		return SEC_E_MESSAGE_ALTERED;

	return SEC_E_OK;
#else
	return SEC_E_UNSUPPORTED_FUNCTION;
#endif
}
static SECURITY_STATUS SEC_ENTRY kerberos_VerifySignature(PCtxtHandle phContext,
                                                          PSecBufferDesc pMessage,
                                                          ULONG MessageSeqNo, ULONG* pfQOP)
{
#ifdef WITH_GSSAPI
	KRB_CONTEXT* context;
	PSecBuffer sig_buffer, data_buffer;
	krb5_key key;
	krb5_keyusage usage;
	char* header;
	BYTE flags;
	uint16_t tok_id;
	uint64_t seq_no;
	krb5_boolean is_valid;
	krb5_crypto_iov iov[] = { { KRB5_CRYPTO_TYPE_DATA, { 0 } },
		                      { KRB5_CRYPTO_TYPE_DATA, { 0 } },
		                      { KRB5_CRYPTO_TYPE_CHECKSUM, { 0 } } };
	BYTE cmp_filler[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

	context = sspi_SecureHandleGetLowerPointer(phContext);
	if (!context)
		return SEC_E_INVALID_HANDLE;

	if (!(context->flags & SSPI_GSS_C_INTEG_FLAG))
		return SEC_E_UNSUPPORTED_FUNCTION;

	sig_buffer = sspi_FindSecBuffer(pMessage, SECBUFFER_TOKEN);
	data_buffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);

	if (!sig_buffer || !data_buffer || sig_buffer->cbBuffer < 16)
		return SEC_E_INVALID_TOKEN;

	 
	header = sig_buffer->pvBuffer;
	Data_Read_UINT16_BE(header, tok_id);
	flags = header[2];
	Data_Read_UINT64_BE((header + 8), seq_no);

	 
	if (tok_id != TOK_ID_MIC)
		return SEC_E_INVALID_TOKEN;

	if ((flags & FLAG_SENDER_IS_ACCEPTOR) == context->acceptor || flags & FLAG_WRAP_CONFIDENTIAL)
		return SEC_E_INVALID_TOKEN;

	if (memcmp(header + 3, cmp_filler, sizeof(cmp_filler)))
		return SEC_E_INVALID_TOKEN;

	if (context->flags & ISC_REQ_SEQUENCE_DETECT && seq_no != context->remote_seq + MessageSeqNo)
		return SEC_E_OUT_OF_SEQUENCE;

	 
	if (flags & FLAG_ACCEPTOR_SUBKEY)
		key = context->acceptor_key;
	else
		key = context->initiator_key ? context->initiator_key : context->session_key;
	if (!key)
		return SEC_E_INTERNAL_ERROR;
	usage = context->acceptor ? KG_USAGE_INITIATOR_SIGN : KG_USAGE_ACCEPTOR_SIGN;

	 
	iov[0].data.length = data_buffer->cbBuffer;
	iov[1].data.length = 16;
	if (krb5_c_crypto_length_iov(context->ctx, krb5_k_key_enctype(context->ctx, key), iov,
	                             ARRAYSIZE(iov)))
		return SEC_E_INTERNAL_ERROR;

	if (sig_buffer->cbBuffer != iov[2].data.length + 16)
		return SEC_E_INTERNAL_ERROR;

	 
	iov[0].data.data = data_buffer->pvBuffer;
	iov[1].data.data = header;
	iov[2].data.data = header + 16;

	if (krb5_k_verify_checksum_iov(context->ctx, 0, key, usage, iov, ARRAYSIZE(iov), &is_valid))
		return SEC_E_INTERNAL_ERROR;

	if (!is_valid)
		return SEC_E_MESSAGE_ALTERED;

	return SEC_E_OK;
#else
	return SEC_E_UNSUPPORTED_FUNCTION;
#endif
}