BOOL nla_send(rdpNla* nla)
{
	BOOL rc = FALSE;
	wStream* s = NULL;
	size_t length;
	WinPrAsn1Encoder* enc;
	WinPrAsn1_OctetString octet_string;

	WINPR_ASSERT(nla);

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

	/* TSRequest */
	WLog_DBG(TAG, "----->> sending...");
	if (!WinPrAsn1EncSeqContainer(enc))
		goto fail;

	/* version [0] INTEGER */
	WLog_DBG(TAG, "   ----->> protocol version %" PRIu32, nla->version);
	if (!WinPrAsn1EncContextualInteger(enc, 0, nla->version))
		goto fail;

	/* negoTokens [1] SEQUENCE OF SEQUENCE */
	if (nla->negoToken.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> auth info");
		if (!WinPrAsn1EncContextualSeqContainer(enc, 1) || !WinPrAsn1EncSeqContainer(enc))
			goto fail;

		/* negoToken [0] OCTET STRING */
		octet_string.data = nla->negoToken.pvBuffer;
		octet_string.len = nla->negoToken.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 0, &octet_string))
			goto fail;

		/* End negoTokens (SEQUENCE OF SEQUENCE) */
		if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
			goto fail;
	}

	/* authInfo [2] OCTET STRING */
	if (nla->authInfo.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> public key auth");
		octet_string.data = nla->authInfo.pvBuffer;
		octet_string.len = nla->authInfo.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 2, &octet_string))
			goto fail;
	}

	/* pubKeyAuth [3] OCTET STRING */
	if (nla->pubKeyAuth.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> public key auth");
		octet_string.data = nla->pubKeyAuth.pvBuffer;
		octet_string.len = nla->pubKeyAuth.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 3, &octet_string))
			goto fail;
	}

	/* errorCode [4] INTEGER */
	if (nla->errorCode && nla->peerVersion >= 3 && nla->peerVersion != 5)
	{
		char buffer[1024];
		WLog_DBG(TAG, "   ----->> error code %s 0x%08" PRIx32,
		         winpr_strerror(nla->errorCode, buffer, sizeof(buffer)), nla->errorCode);
		if (!WinPrAsn1EncContextualInteger(enc, 4, nla->errorCode))
			goto fail;
	}

	/* clientNonce [5] OCTET STRING */
	if (nla->ClientNonce.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> client nonce");
		octet_string.data = nla->ClientNonce.pvBuffer;
		octet_string.len = nla->ClientNonce.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 5, &octet_string))
			goto fail;
	}

	/* End TSRequest */
	if (!WinPrAsn1EncEndContainer(enc))
		goto fail;

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

	s = Stream_New(NULL, length);
	if (!s)
		goto fail;

	if (!WinPrAsn1EncToStream(enc, s))
		goto fail;

	WLog_DBG(TAG, "[%" PRIuz " bytes]", length);
	if (transport_write(nla->transport, s) < 0)
		goto fail;
	rc = TRUE;

fail:
	Stream_Free(s, TRUE);
	WinPrAsn1Encoder_Free(&enc);
	return rc;
}
BOOL nla_send(rdpNla* nla)
{
	BOOL rc = FALSE;
	wStream* s = NULL;
	size_t length;
	WinPrAsn1Encoder* enc;
	WinPrAsn1_OctetString octet_string;

	WINPR_ASSERT(nla);

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

	 
	WLog_DBG(TAG, "----->> sending...");
	if (!WinPrAsn1EncSeqContainer(enc))
		goto fail;

	 
	WLog_DBG(TAG, "   ----->> protocol version %" PRIu32, nla->version);
	if (!WinPrAsn1EncContextualInteger(enc, 0, nla->version))
		goto fail;

	 
	if (nla->negoToken.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> auth info");
		if (!WinPrAsn1EncContextualSeqContainer(enc, 1) || !WinPrAsn1EncSeqContainer(enc))
			goto fail;

		 
		octet_string.data = nla->negoToken.pvBuffer;
		octet_string.len = nla->negoToken.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 0, &octet_string))
			goto fail;

		 
		if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
			goto fail;
	}

	 
	if (nla->authInfo.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> public key auth");
		octet_string.data = nla->authInfo.pvBuffer;
		octet_string.len = nla->authInfo.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 2, &octet_string))
			goto fail;
	}

	 
	if (nla->pubKeyAuth.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> public key auth");
		octet_string.data = nla->pubKeyAuth.pvBuffer;
		octet_string.len = nla->pubKeyAuth.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 3, &octet_string))
			goto fail;
	}

	 
	if (nla->errorCode && nla->peerVersion >= 3 && nla->peerVersion != 5)
	{
		char buffer[1024];
		WLog_DBG(TAG, "   ----->> error code %s 0x%08" PRIx32,
		         winpr_strerror(nla->errorCode, buffer, sizeof(buffer)), nla->errorCode);
		if (!WinPrAsn1EncContextualInteger(enc, 4, nla->errorCode))
			goto fail;
	}

	 
	if (nla->ClientNonce.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> client nonce");
		octet_string.data = nla->ClientNonce.pvBuffer;
		octet_string.len = nla->ClientNonce.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 5, &octet_string))
			goto fail;
	}

	 
	if (!WinPrAsn1EncEndContainer(enc))
		goto fail;

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

	s = Stream_New(NULL, length);
	if (!s)
		goto fail;

	if (!WinPrAsn1EncToStream(enc, s))
		goto fail;

	WLog_DBG(TAG, "[%" PRIuz " bytes]", length);
	if (transport_write(nla->transport, s) < 0)
		goto fail;
	rc = TRUE;

fail:
	Stream_Free(s, TRUE);
	WinPrAsn1Encoder_Free(&enc);
	return rc;
}