static BOOL kerberos_mk_tgt_token(SecBuffer* buf, int msg_type, char* sname, char* host,
                                  const krb5_data* ticket)
{
	WinPrAsn1Encoder* enc;
	WinPrAsn1_MemoryChunk data;
	wStream s;
	size_t len;
	sspi_gss_data token;
	BOOL ret = FALSE;

	WINPR_ASSERT(buf);

	if (msg_type != KRB_TGT_REQ && msg_type != KRB_TGT_REP)
		return FALSE;
	if (msg_type == KRB_TGT_REP && !ticket)
		return FALSE;

	enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
	if (!enc)
		return FALSE;

	/* KERB-TGT-REQUEST (SEQUENCE) */
	if (!WinPrAsn1EncSeqContainer(enc))
		goto cleanup;

	/* pvno [0] INTEGER */
	if (!WinPrAsn1EncContextualInteger(enc, 0, 5))
		goto cleanup;

	/* msg-type [1] INTEGER */
	if (!WinPrAsn1EncContextualInteger(enc, 1, msg_type))
		goto cleanup;

	if (msg_type == KRB_TGT_REQ && sname)
	{
		/* server-name [2] PrincipalName (SEQUENCE) */
		if (!WinPrAsn1EncContextualSeqContainer(enc, 2))
			goto cleanup;

		/* name-type [0] INTEGER */
		if (!WinPrAsn1EncContextualInteger(enc, 0, KRB5_NT_SRV_HST))
			goto cleanup;

		/* name-string [1] SEQUENCE OF GeneralString */
		if (!WinPrAsn1EncContextualSeqContainer(enc, 1))
			goto cleanup;

		if (!WinPrAsn1EncGeneralString(enc, sname))
			goto cleanup;

		if (host && !WinPrAsn1EncGeneralString(enc, host))
			goto cleanup;

		if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
			goto cleanup;
	}
	else if (msg_type == KRB_TGT_REP)
	{
		/* ticket [2] Ticket */
		data.data = (BYTE*)ticket->data;
		data.len = ticket->length;
		if (!WinPrAsn1EncContextualRawContent(enc, 2, &data))
			goto cleanup;
	}

	if (!WinPrAsn1EncEndContainer(enc))
		goto cleanup;

	if (!WinPrAsn1EncStreamSize(enc, &len) || len > buf->cbBuffer)
		goto cleanup;

	Stream_StaticInit(&s, buf->pvBuffer, len);
	if (!WinPrAsn1EncToStream(enc, &s))
		goto cleanup;

	token.data = buf->pvBuffer;
	token.length = (UINT)len;
	if (sspi_gss_wrap_token(buf, &kerberos_u2u_OID,
	                        msg_type == KRB_TGT_REQ ? TOK_ID_TGT_REQ : TOK_ID_TGT_REP, &token))
		ret = TRUE;

cleanup:
	WinPrAsn1Encoder_Free(&enc);
	return ret;
}
static BOOL kerberos_mk_tgt_token(SecBuffer* buf, int msg_type, char* sname, char* host,
                                  const krb5_data* ticket)
{
	WinPrAsn1Encoder* enc;
	WinPrAsn1_MemoryChunk data;
	wStream s;
	size_t len;
	sspi_gss_data token;
	BOOL ret = FALSE;

	WINPR_ASSERT(buf);

	if (msg_type != KRB_TGT_REQ && msg_type != KRB_TGT_REP)
		return FALSE;
	if (msg_type == KRB_TGT_REP && !ticket)
		return FALSE;

	enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
	if (!enc)
		return FALSE;

	 
	if (!WinPrAsn1EncSeqContainer(enc))
		goto cleanup;

	 
	if (!WinPrAsn1EncContextualInteger(enc, 0, 5))
		goto cleanup;

	 
	if (!WinPrAsn1EncContextualInteger(enc, 1, msg_type))
		goto cleanup;

	if (msg_type == KRB_TGT_REQ && sname)
	{
		 
		if (!WinPrAsn1EncContextualSeqContainer(enc, 2))
			goto cleanup;

		 
		if (!WinPrAsn1EncContextualInteger(enc, 0, KRB5_NT_SRV_HST))
			goto cleanup;

		 
		if (!WinPrAsn1EncContextualSeqContainer(enc, 1))
			goto cleanup;

		if (!WinPrAsn1EncGeneralString(enc, sname))
			goto cleanup;

		if (host && !WinPrAsn1EncGeneralString(enc, host))
			goto cleanup;

		if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
			goto cleanup;
	}
	else if (msg_type == KRB_TGT_REP)
	{
		 
		data.data = (BYTE*)ticket->data;
		data.len = ticket->length;
		if (!WinPrAsn1EncContextualRawContent(enc, 2, &data))
			goto cleanup;
	}

	if (!WinPrAsn1EncEndContainer(enc))
		goto cleanup;

	if (!WinPrAsn1EncStreamSize(enc, &len) || len > buf->cbBuffer)
		goto cleanup;

	Stream_StaticInit(&s, buf->pvBuffer, len);
	if (!WinPrAsn1EncToStream(enc, &s))
		goto cleanup;

	token.data = buf->pvBuffer;
	token.length = (UINT)len;
	if (sspi_gss_wrap_token(buf, &kerberos_u2u_OID,
	                        msg_type == KRB_TGT_REQ ? TOK_ID_TGT_REQ : TOK_ID_TGT_REP, &token))
		ret = TRUE;

cleanup:
	WinPrAsn1Encoder_Free(&enc);
	return ret;
}