static BOOL nla_encode_ts_credentials(rdpNla* nla)
{
	rdpSettings* settings;
	BOOL ret = FALSE;
	WinPrAsn1Encoder* enc;
	size_t length;
	wStream s;
	int credType;

	WINPR_ASSERT(nla);
	WINPR_ASSERT(nla->rdpcontext);

	settings = nla->rdpcontext->settings;
	WINPR_ASSERT(settings);

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

	/* TSCredentials */
	if (!WinPrAsn1EncSeqContainer(enc))
		goto out;

	/* credType [0] INTEGER */
	credType = settings->SmartcardLogon ? 2 : 1;
	if (!WinPrAsn1EncContextualInteger(enc, 0, credType))
		goto out;

	/* credentials [1] OCTET STRING */
	if (!WinPrAsn1EncContextualOctetStringContainer(enc, 1))
		goto out;

	if (settings->SmartcardLogon)
	{
		struct
		{
			WinPrAsn1_tagId tag;
			size_t setting_id;
		} cspData_fields[] = { { 1, FreeRDP_CardName },
			                   { 2, FreeRDP_ReaderName },
			                   { 3, FreeRDP_ContainerName },
			                   { 4, FreeRDP_CspName } };
		WinPrAsn1_OctetString octet_string = { 0 };
		char* str;
		BOOL ret;

		/* TSSmartCardCreds */
		if (!WinPrAsn1EncSeqContainer(enc))
			goto out;

		/* pin [0] OCTET STRING */
		str = freerdp_settings_get_string_writable(settings, FreeRDP_Password);
		octet_string.len =
		    ConvertToUnicode(CP_UTF8, 0, str, -1, (LPWSTR*)&octet_string.data, 0) * sizeof(WCHAR);
		ret = WinPrAsn1EncContextualOctetString(enc, 0, &octet_string);
		free(octet_string.data);
		if (!ret)
			goto out;

		/* cspData [1] SEQUENCE */
		if (!WinPrAsn1EncContextualSeqContainer(enc, 1))
			goto out;

		/* keySpec [0] INTEGER */
		if (!WinPrAsn1EncContextualInteger(enc, 0,
		                                   freerdp_settings_get_uint32(settings, FreeRDP_KeySpec)))
			goto out;

		for (int i = 0; i < ARRAYSIZE(cspData_fields); i++)
		{
			str = freerdp_settings_get_string_writable(settings, cspData_fields[i].setting_id);
			octet_string.len =
			    ConvertToUnicode(CP_UTF8, 0, str, -1, (LPWSTR*)&octet_string.data, 0) *
			    sizeof(WCHAR);
			if (octet_string.len)
			{
				ret = WinPrAsn1EncContextualOctetString(enc, cspData_fields[i].tag, &octet_string);
				free(octet_string.data);
				if (!ret)
					goto out;
			}
		}

		/* End cspData */
		if (!WinPrAsn1EncEndContainer(enc))
			goto out;

		/* End TSSmartCardCreds */
		if (!WinPrAsn1EncEndContainer(enc))
			goto out;
	}
	else
	{
		WinPrAsn1_OctetString username = { 0 };
		WinPrAsn1_OctetString domain = { 0 };
		WinPrAsn1_OctetString password = { 0 };

		/* TSPasswordCreds */
		if (!WinPrAsn1EncSeqContainer(enc))
			goto out;

		if (!settings->DisableCredentialsDelegation && nla->identity)
		{
			username.len = nla->identity->UserLength * 2;
			username.data = (BYTE*)nla->identity->User;

			domain.len = nla->identity->DomainLength * 2;
			domain.data = (BYTE*)nla->identity->Domain;

			password.len = nla->identity->PasswordLength * 2;
			password.data = (BYTE*)nla->identity->Password;
		}

		if (!WinPrAsn1EncContextualOctetString(enc, 0, &domain))
			goto out;
		if (!WinPrAsn1EncContextualOctetString(enc, 1, &username))
			goto out;
		if (!WinPrAsn1EncContextualOctetString(enc, 2, &password))
			goto out;

		/* End TSPasswordCreds */
		if (!WinPrAsn1EncEndContainer(enc))
			goto out;
	}

	/* End credentials | End TSCredentials */
	if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
		goto out;

	if (!WinPrAsn1EncStreamSize(enc, &length))
		goto out;

	if (!nla_sec_buffer_alloc(&nla->tsCredentials, length))
	{
		WLog_ERR(TAG, "sspi_SecBufferAlloc failed!");
		goto out;
	}

	Stream_StaticInit(&s, (BYTE*)nla->tsCredentials.pvBuffer, length);
	if (WinPrAsn1EncToStream(enc, &s))
		ret = TRUE;

out:
	WinPrAsn1Encoder_Free(&enc);
	return ret;
}
static BOOL nla_encode_ts_credentials(rdpNla* nla)
{
	rdpSettings* settings;
	BOOL ret = FALSE;
	WinPrAsn1Encoder* enc;
	size_t length;
	wStream s;
	int credType;

	WINPR_ASSERT(nla);
	WINPR_ASSERT(nla->rdpcontext);

	settings = nla->rdpcontext->settings;
	WINPR_ASSERT(settings);

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

	 
	if (!WinPrAsn1EncSeqContainer(enc))
		goto out;

	 
	credType = settings->SmartcardLogon ? 2 : 1;
	if (!WinPrAsn1EncContextualInteger(enc, 0, credType))
		goto out;

	 
	if (!WinPrAsn1EncContextualOctetStringContainer(enc, 1))
		goto out;

	if (settings->SmartcardLogon)
	{
		struct
		{
			WinPrAsn1_tagId tag;
			size_t setting_id;
		} cspData_fields[] = { { 1, FreeRDP_CardName },
			                   { 2, FreeRDP_ReaderName },
			                   { 3, FreeRDP_ContainerName },
			                   { 4, FreeRDP_CspName } };
		WinPrAsn1_OctetString octet_string = { 0 };
		char* str;
		BOOL ret;

		 
		if (!WinPrAsn1EncSeqContainer(enc))
			goto out;

		 
		str = freerdp_settings_get_string_writable(settings, FreeRDP_Password);
		octet_string.len =
		    ConvertToUnicode(CP_UTF8, 0, str, -1, (LPWSTR*)&octet_string.data, 0) * sizeof(WCHAR);
		ret = WinPrAsn1EncContextualOctetString(enc, 0, &octet_string);
		free(octet_string.data);
		if (!ret)
			goto out;

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

		 
		if (!WinPrAsn1EncContextualInteger(enc, 0,
		                                   freerdp_settings_get_uint32(settings, FreeRDP_KeySpec)))
			goto out;

		for (int i = 0; i < ARRAYSIZE(cspData_fields); i++)
		{
			str = freerdp_settings_get_string_writable(settings, cspData_fields[i].setting_id);
			octet_string.len =
			    ConvertToUnicode(CP_UTF8, 0, str, -1, (LPWSTR*)&octet_string.data, 0) *
			    sizeof(WCHAR);
			if (octet_string.len)
			{
				ret = WinPrAsn1EncContextualOctetString(enc, cspData_fields[i].tag, &octet_string);
				free(octet_string.data);
				if (!ret)
					goto out;
			}
		}

		 
		if (!WinPrAsn1EncEndContainer(enc))
			goto out;

		 
		if (!WinPrAsn1EncEndContainer(enc))
			goto out;
	}
	else
	{
		WinPrAsn1_OctetString username = { 0 };
		WinPrAsn1_OctetString domain = { 0 };
		WinPrAsn1_OctetString password = { 0 };

		 
		if (!WinPrAsn1EncSeqContainer(enc))
			goto out;

		if (!settings->DisableCredentialsDelegation && nla->identity)
		{
			username.len = nla->identity->UserLength * 2;
			username.data = (BYTE*)nla->identity->User;

			domain.len = nla->identity->DomainLength * 2;
			domain.data = (BYTE*)nla->identity->Domain;

			password.len = nla->identity->PasswordLength * 2;
			password.data = (BYTE*)nla->identity->Password;
		}

		if (!WinPrAsn1EncContextualOctetString(enc, 0, &domain))
			goto out;
		if (!WinPrAsn1EncContextualOctetString(enc, 1, &username))
			goto out;
		if (!WinPrAsn1EncContextualOctetString(enc, 2, &password))
			goto out;

		 
		if (!WinPrAsn1EncEndContainer(enc))
			goto out;
	}

	 
	if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
		goto out;

	if (!WinPrAsn1EncStreamSize(enc, &length))
		goto out;

	if (!nla_sec_buffer_alloc(&nla->tsCredentials, length))
	{
		WLog_ERR(TAG, "sspi_SecBufferAlloc failed!");
		goto out;
	}

	Stream_StaticInit(&s, (BYTE*)nla->tsCredentials.pvBuffer, length);
	if (WinPrAsn1EncToStream(enc, &s))
		ret = TRUE;

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