From 5f3bc5842ab6620227f923eb9862d9cb848dba5c Mon Sep 17 00:00:00 2001 From: fifthdegree Date: Thu, 14 Jul 2022 16:19:38 -0400 Subject: [PATCH] nla: use winpr asn1 library --- libfreerdp/core/CMakeLists.txt | 2 - libfreerdp/core/credssp.asn1 | 48 -- libfreerdp/core/nla.c | 682 +++++++++------------ libfreerdp/core/tscredentials.c | 982 ------------------------------- libfreerdp/core/tscredentials.h | 132 ----- tools/asn_parser_generator.py | 620 ------------------- winpr/include/winpr/asn1.h | 4 + winpr/libwinpr/utils/asn1/asn1.c | 26 + 8 files changed, 323 insertions(+), 2173 deletions(-) delete mode 100644 libfreerdp/core/credssp.asn1 delete mode 100644 libfreerdp/core/tscredentials.c delete mode 100644 libfreerdp/core/tscredentials.h delete mode 100755 tools/asn_parser_generator.py diff --git a/libfreerdp/core/CMakeLists.txt b/libfreerdp/core/CMakeLists.txt index c51f90340..b3c072456 100644 --- a/libfreerdp/core/CMakeLists.txt +++ b/libfreerdp/core/CMakeLists.txt @@ -62,8 +62,6 @@ set(${MODULE_PREFIX}_SRCS nla.c nla.h smartcardlogon.c - tscredentials.c - tscredentials.h nego.c nego.h info.c diff --git a/libfreerdp/core/credssp.asn1 b/libfreerdp/core/credssp.asn1 deleted file mode 100644 index 084c8cc3a..000000000 --- a/libfreerdp/core/credssp.asn1 +++ /dev/null @@ -1,48 +0,0 @@ -TSCredentials ::= SEQUENCE { - credType [0] INTEGER, - credentials [1] OCTET STRING -} - -TSPasswordCreds ::= SEQUENCE { - domainName [0] OCTET STRING, - userName [1] OCTET STRING, - password [2] OCTET STRING -} - -TSCspDataDetail ::= SEQUENCE { - keySpec [0] INTEGER, - cardName [1] OCTET STRING OPTIONAL, - readerName [2] OCTET STRING OPTIONAL, - containerName [3] OCTET STRING OPTIONAL, - cspName [4] OCTET STRING OPTIONAL -} - - -TSSmartCardCreds ::= SEQUENCE { - pin [0] OCTET STRING, - cspData [1] TSCspDataDetail, - userHint [2] OCTET STRING OPTIONAL, - domainHint [3] OCTET STRING OPTIONAL -} - -TSRemoteGuardPackageCred ::= SEQUENCE { - packageName [0] OCTET STRING, - credBuffer [1] OCTET STRING, -} - -TSRemoteGuardCreds ::= SEQUENCE { - logonCred [0] TSRemoteGuardPackageCred, - supplementalCreds [1] SEQUENCE OF TSRemoteGuardPackageCred OPTIONAL, -} - -%options { - fieldOption TSCspDataDetail.cardName charInMemorySerializeToUnicode - fieldOption TSCspDataDetail.readerName charInMemorySerializeToUnicode - fieldOption TSCspDataDetail.containerName charInMemorySerializeToUnicode - fieldOption TSCspDataDetail.cspName charInMemorySerializeToUnicode - - fieldOption TSSmartCardCreds.pin charInMemorySerializeToUnicode - fieldOption TSSmartCardCreds.userHint charInMemorySerializeToUnicode - fieldOption TSSmartCardCreds.domainHint charInMemorySerializeToUnicode - prefix nla_ -} \ No newline at end of file diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index e17e39fa2..db218bd01 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -44,10 +44,10 @@ #include #include #include +#include #include "nla.h" #include "utils.h" -#include "tscredentials.h" #include #define TAG FREERDP_TAG("core.nla") @@ -153,7 +153,6 @@ static SECURITY_STATUS nla_decrypt_public_key_echo(rdpNla* nla); static SECURITY_STATUS nla_decrypt_public_key_hash(rdpNla* nla); static SECURITY_STATUS nla_encrypt_ts_credentials(rdpNla* nla); static SECURITY_STATUS nla_decrypt_ts_credentials(rdpNla* nla); -static BOOL nla_read_ts_password_creds(rdpNla* nla, wStream* s); static BOOL nla_Digest_Update_From_SecBuffer(WINPR_DIGEST_CTX* ctx, const SecBuffer* buffer) { @@ -192,21 +191,6 @@ static BOOL nla_sec_buffer_alloc_from_buffer(SecBuffer* buffer, const SecBuffer* return nla_sec_buffer_alloc_from_data(buffer, data->pvBuffer, offset, data->cbBuffer); } -static BOOL nla_decode_to_buffer(wStream* s, SecBuffer* buffer) -{ - BOOL rc = FALSE; - size_t length; - if (!s || !buffer) - return FALSE; - if (!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */ - !Stream_CheckAndLogRequiredLength(TAG, s, length)) - return FALSE; - - rc = nla_sec_buffer_alloc_from_data(buffer, Stream_Pointer(s), 0, length); - Stream_Seek(s, length); - return rc; -} - static BOOL nla_set_package_name(rdpNla* nla, const TCHAR* name) { if (!nla) @@ -467,27 +451,6 @@ static SECURITY_STATUS nla_encrypt(rdpNla* nla, SecBuffer* buffer, size_t header return status; } -static size_t ber_sizeof_sequence_octet_string(size_t length) -{ - size_t rc = ber_sizeof_contextual_tag(ber_sizeof_octet_string(length)); - rc += ber_sizeof_octet_string(length); - return rc; -} - -static size_t ber_write_sequence_octet_string(wStream* stream, BYTE context, const BYTE* value, - size_t length) -{ - size_t rc = ber_write_contextual_tag(stream, context, ber_sizeof_octet_string(length), TRUE); - rc += ber_write_octet_string(stream, value, length); - return rc; -} - -static size_t ber_write_sequence_octet_string_from_secbuffer(wStream* stream, BYTE context, - const SecBuffer* buffer) -{ - return ber_write_sequence_octet_string(stream, context, buffer->pvBuffer, buffer->cbBuffer); -} - /* CredSSP Client-To-Server Binding Hash\0 */ static const BYTE ClientServerHashMagic[] = { 0x43, 0x72, 0x65, 0x64, 0x53, 0x53, 0x50, 0x20, 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x2D, 0x54, @@ -1936,110 +1899,66 @@ fail: return status; } -BOOL nla_read_ts_password_creds(rdpNla* nla, wStream* s) -{ - size_t length; - size_t userLen = 0; - size_t domainLen = 0; - size_t passwordLen = 0; - const WCHAR* user = NULL; - const WCHAR* domain = NULL; - const WCHAR* password = NULL; - - WINPR_ASSERT(nla); - WINPR_ASSERT(s); - - if (!nla->identity) - { - WLog_ERR(TAG, "nla->identity is NULL!"); - return FALSE; - } - - /* TSPasswordCreds (SEQUENCE) - * Initialise to default values. */ - - sspi_FreeAuthIdentity(nla->identity); - - if (!ber_read_sequence_tag(s, &length)) - return FALSE; - - /* The sequence is empty, return early, - * TSPasswordCreds (SEQUENCE) is optional. */ - if (length == 0) - return TRUE; - - /* [0] domainName (OCTET STRING) */ - if (!ber_read_contextual_tag(s, 0, &length, TRUE) || !ber_read_octet_string_tag(s, &length)) - { - return FALSE; - } - - domainLen = length / sizeof(WCHAR); - if (length > 0) - domain = Stream_PointerAs(s, const WCHAR); - - if (!Stream_SafeSeek(s, length)) - return FALSE; - - /* [1] userName (OCTET STRING) */ - if (!ber_read_contextual_tag(s, 1, &length, TRUE) || !ber_read_octet_string_tag(s, &length)) - return FALSE; - - userLen = length / sizeof(WCHAR); - if (length > 0) - user = Stream_PointerAs(s, const WCHAR); - - if (!Stream_SafeSeek(s, length)) - return FALSE; - - /* [2] password (OCTET STRING) */ - if (!ber_read_contextual_tag(s, 2, &length, TRUE) || !ber_read_octet_string_tag(s, &length)) - return FALSE; - - passwordLen = length / sizeof(WCHAR); - if (length > 0) - password = Stream_PointerAs(s, const WCHAR); - - if (!Stream_SafeSeek(s, length)) - return FALSE; - - return sspi_SetAuthIdentityWithLengthW(nla->identity, user, userLen, domain, domainLen, - password, passwordLen) > 0; -} - static BOOL nla_read_ts_credentials(rdpNla* nla, SecBuffer* data, size_t offset) { - wStream* s; - size_t length; - size_t ts_password_creds_length = 0; - BOOL ret = FALSE; + WinPrAsn1Decoder dec, dec2; + WinPrAsn1_OctetString credentials; + BOOL error; + WinPrAsn1_INTEGER credType; WINPR_ASSERT(nla); - if (!data) + WINPR_ASSERT(data); + WINPR_ASSERT(data->cbBuffer >= offset); + + WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, (BYTE*)data->pvBuffer + offset, + data->cbBuffer - offset); + + /* TSCredentials */ + if (!WinPrAsn1DecReadSequence(&dec, &dec2)) + return FALSE; + dec = dec2; + + /* credType [0] INTEGER */ + if (!WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &credType)) return FALSE; - s = Stream_New(data->pvBuffer, data->cbBuffer); + /* credentials [1] OCTET STRING */ + if (!WinPrAsn1DecReadContextualOctetString(&dec, 1, &error, &credentials, FALSE)) + return FALSE; - if (!s) + WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, credentials.data, credentials.len); + + if (credType == 1) { - WLog_ERR(TAG, "Stream_New failed!"); - return FALSE; + WinPrAsn1_OctetString domain; + WinPrAsn1_OctetString username; + WinPrAsn1_OctetString password; + + /* TSPasswordCreds */ + if (!WinPrAsn1DecReadSequence(&dec, &dec2)) + return FALSE; + dec = dec2; + + /* domainName [0] OCTET STRING */ + if (!WinPrAsn1DecReadContextualOctetString(&dec, 0, &error, &domain, FALSE) && error) + return FALSE; + + /* userName [1] OCTET STRING */ + if (!WinPrAsn1DecReadContextualOctetString(&dec, 1, &error, &username, FALSE) && error) + return FALSE; + + /* password [2] OCTET STRING */ + if (!WinPrAsn1DecReadContextualOctetString(&dec, 2, &error, &password, FALSE)) + return FALSE; + + if (sspi_SetAuthIdentityWithLengthW(nla->identity, (WCHAR*)username.data, + username.len / sizeof(WCHAR), (WCHAR*)domain.data, + domain.len / sizeof(WCHAR), (WCHAR*)password.data, + password.len / sizeof(WCHAR)) < 0) + return FALSE; } - if (!Stream_SafeSeek(s, offset)) - goto fail; - - /* TSCredentials (SEQUENCE) */ - ret = ber_read_sequence_tag(s, &length) && - /* [0] credType (INTEGER) */ - ber_read_contextual_tag(s, 0, &length, TRUE) && ber_read_integer(s, NULL) && - /* [1] credentials (OCTET STRING) */ - ber_read_contextual_tag(s, 1, &length, TRUE) && - ber_read_octet_string_tag(s, &ts_password_creds_length) && - nla_read_ts_password_creds(nla, s); -fail: - Stream_Free(s, FALSE); - return ret; + return TRUE; } /** @@ -2049,13 +1968,12 @@ fail: static BOOL nla_encode_ts_credentials(rdpNla* nla) { - wStream* credsContentStream; - wStream staticRetStream; - wStream* s; - size_t length; rdpSettings* settings; BOOL ret = FALSE; - TSCredentials_t cr = { 0 }; + WinPrAsn1Encoder* enc; + size_t length; + wStream s; + int credType; WINPR_ASSERT(nla); WINPR_ASSERT(nla->rdpcontext); @@ -2063,77 +1981,135 @@ static BOOL nla_encode_ts_credentials(rdpNla* nla) 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) { - TSSmartCardCreds_t smartcardCreds = { 0 }; - TSCspDataDetail_t cspData = { 0 }; - char* Password = freerdp_settings_get_string_writable(settings, FreeRDP_Password); + 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; - smartcardCreds.pin = Password ? Password : ""; + /* TSSmartCardCreds */ + if (!WinPrAsn1EncSeqContainer(enc)) + goto out; - /*smartcardCreds.userHint = settings->UserHint; - smartcardCreds.domainHint = settings->DomainHint;*/ - smartcardCreds.cspData = &cspData; + /* 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.keySpec = freerdp_settings_get_uint32(settings, FreeRDP_KeySpec); - cspData.cspName = freerdp_settings_get_string_writable(settings, FreeRDP_CspName); - cspData.readerName = freerdp_settings_get_string_writable(settings, FreeRDP_ReaderName); - cspData.cardName = freerdp_settings_get_string_writable(settings, FreeRDP_CardName); - cspData.containerName = - freerdp_settings_get_string_writable(settings, FreeRDP_ContainerName); + /* cspData [1] SEQUENCE */ + if (!WinPrAsn1EncContextualSeqContainer(enc, 1)) + goto out; - length = ber_sizeof_nla_TSSmartCardCreds(&smartcardCreds); - credsContentStream = Stream_New(NULL, length); - if (!credsContentStream) - return FALSE; + /* keySpec [0] INTEGER */ + if (!WinPrAsn1EncContextualInteger(enc, 0, + freerdp_settings_get_uint32(settings, FreeRDP_KeySpec))) + goto out; - if (ber_write_nla_TSSmartCardCreds(credsContentStream, &smartcardCreds) == 0) - return FALSE; + 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; + } + } - cr.credType = 2; + /* End cspData */ + if (!WinPrAsn1EncEndContainer(enc)) + goto out; + + /* End TSSmartCardCreds */ + if (!WinPrAsn1EncEndContainer(enc)) + goto out; } else { - TSPasswordCreds_t passCreds = { 0 }; + WinPrAsn1_OctetString username = { 0 }; + WinPrAsn1_OctetString domain = { 0 }; + WinPrAsn1_OctetString password = { 0 }; + + /* TSPasswordCreds */ + if (!WinPrAsn1EncSeqContainer(enc)) + goto out; if (!settings->DisableCredentialsDelegation && nla->identity) { - passCreds.userNameLen = nla->identity->UserLength * 2; - passCreds.userName = (BYTE*)nla->identity->User; + username.len = nla->identity->UserLength * 2; + username.data = (BYTE*)nla->identity->User; - passCreds.domainNameLen = nla->identity->DomainLength * 2; - passCreds.domainName = (BYTE*)nla->identity->Domain; + domain.len = nla->identity->DomainLength * 2; + domain.data = (BYTE*)nla->identity->Domain; - passCreds.passwordLen = nla->identity->PasswordLength * 2; - passCreds.password = (BYTE*)nla->identity->Password; + password.len = nla->identity->PasswordLength * 2; + password.data = (BYTE*)nla->identity->Password; } - length = ber_sizeof_nla_TSPasswordCreds(&passCreds); - credsContentStream = Stream_New(NULL, length); - if (!credsContentStream) - return FALSE; + if (!WinPrAsn1EncContextualOctetString(enc, 0, &domain)) + goto out; + if (!WinPrAsn1EncContextualOctetString(enc, 1, &username)) + goto out; + if (!WinPrAsn1EncContextualOctetString(enc, 2, &password)) + goto out; - ber_write_nla_TSPasswordCreds(credsContentStream, &passCreds); - - cr.credType = 1; + /* End TSPasswordCreds */ + if (!WinPrAsn1EncEndContainer(enc)) + goto out; } - cr.credentialsLen = length; - cr.credentials = Stream_Buffer(credsContentStream); + /* End credentials | End TSCredentials */ + if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc)) + goto out; + + if (!WinPrAsn1EncStreamSize(enc, &length)) + goto out; - length = ber_sizeof_nla_TSCredentials(&cr); if (!nla_sec_buffer_alloc(&nla->tsCredentials, length)) { WLog_ERR(TAG, "sspi_SecBufferAlloc failed!"); goto out; } - s = Stream_StaticInit(&staticRetStream, (BYTE*)nla->tsCredentials.pvBuffer, length); - ber_write_nla_TSCredentials(s, &cr); - ret = TRUE; + Stream_StaticInit(&s, (BYTE*)nla->tsCredentials.pvBuffer, length); + if (WinPrAsn1EncToStream(enc, &s)) + ret = TRUE; out: - Stream_Free(credsContentStream, TRUE); + WinPrAsn1Encoder_Free(&enc); return ret; } @@ -2179,103 +2155,6 @@ static SECURITY_STATUS nla_decrypt_ts_credentials(rdpNla* nla) return SEC_E_OK; } -static size_t nla_sizeof_nego_token(size_t length) -{ - length = ber_sizeof_octet_string(length); - length += ber_sizeof_contextual_tag(length); - return length; -} - -static size_t nla_sizeof_nego_tokens(const SecBuffer* buffer) -{ - WINPR_ASSERT(buffer); - - size_t length = buffer->cbBuffer; - if (length == 0) - return 0; - length = nla_sizeof_nego_token(length); - length += ber_sizeof_sequence_tag(length); - length += ber_sizeof_sequence_tag(length); - length += ber_sizeof_contextual_tag(length); - return length; -} - -static size_t nla_sizeof_pub_key_auth(const SecBuffer* buffer) -{ - WINPR_ASSERT(buffer); - - size_t length = buffer->cbBuffer; - if (length == 0) - return 0; - length = ber_sizeof_octet_string(length); - length += ber_sizeof_contextual_tag(length); - return length; -} - -static size_t nla_sizeof_auth_info(const SecBuffer* buffer) -{ - WINPR_ASSERT(buffer); - - size_t length = buffer->cbBuffer; - if (length == 0) - return 0; - length = ber_sizeof_octet_string(length); - length += ber_sizeof_contextual_tag(length); - return length; -} - -static size_t nla_sizeof_client_nonce(const SecBuffer* buffer) -{ - WINPR_ASSERT(buffer); - - size_t length = buffer->cbBuffer; - if (length == 0) - return 0; - length = ber_sizeof_octet_string(length); - length += ber_sizeof_contextual_tag(length); - return length; -} - -static size_t nla_sizeof_ts_request(size_t length) -{ - length += ber_sizeof_integer(2); - length += ber_sizeof_contextual_tag(3); - return length; -} - -static BOOL nla_client_write_nego_token(wStream* s, const SecBuffer* negoToken) -{ - const size_t nego_tokens_length = nla_sizeof_nego_tokens(negoToken); - - WINPR_ASSERT(s); - - if (Stream_GetRemainingCapacity(s) < nego_tokens_length) - return FALSE; - - if (nego_tokens_length > 0) - { - size_t length; - - WLog_DBG(TAG, " ----->> nego token"); - length = - ber_write_contextual_tag(s, 1, - ber_sizeof_sequence(ber_sizeof_sequence( - ber_sizeof_sequence_octet_string(negoToken->cbBuffer))), - TRUE); /* NegoData */ - length += - ber_write_sequence_tag(s, ber_sizeof_sequence(ber_sizeof_sequence_octet_string( - negoToken->cbBuffer))); /* SEQUENCE OF NegoDataItem */ - length += ber_write_sequence_tag( - s, ber_sizeof_sequence_octet_string(negoToken->cbBuffer)); /* NegoDataItem */ - length += - ber_write_sequence_octet_string_from_secbuffer(s, 0, negoToken); /* OCTET STRING */ - - if (length != nego_tokens_length) - return FALSE; - } - - return TRUE; -} /** * Send CredSSP message. * @param credssp @@ -2286,113 +2165,135 @@ BOOL nla_send(rdpNla* nla) BOOL rc = FALSE; wStream* s; size_t length; - size_t ts_request_length; - size_t error_code_context_length = 0; - size_t error_code_length = 0; + WinPrAsn1Encoder* enc; + WinPrAsn1_OctetString octet_string; WINPR_ASSERT(nla); - const size_t nego_tokens_length = nla_sizeof_nego_tokens(&nla->negoToken); - const size_t pub_key_auth_length = nla_sizeof_pub_key_auth(&nla->pubKeyAuth); - const size_t auth_info_length = nla_sizeof_auth_info(&nla->authInfo); - const size_t client_nonce_length = nla_sizeof_client_nonce(&nla->ClientNonce); - - if (nla->peerVersion >= 3 && nla->peerVersion != 5 && nla->errorCode != 0) - { - error_code_length = ber_sizeof_integer(nla->errorCode); - error_code_context_length = ber_sizeof_contextual_tag(error_code_length); - } - - length = nego_tokens_length + pub_key_auth_length + auth_info_length + - error_code_context_length + error_code_length + client_nonce_length; - ts_request_length = nla_sizeof_ts_request(length); - s = Stream_New(NULL, ber_sizeof_sequence(ts_request_length)); - - if (!s) - { - WLog_ERR(TAG, "Stream_New failed!"); + enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER); + if (!enc) return FALSE; - } - WLog_DBG(TAG, "----->> sending..."); /* TSRequest */ - ber_write_sequence_tag(s, ts_request_length); /* SEQUENCE */ - /* [0] version */ - ber_write_contextual_tag(s, 0, 3, TRUE); - - WLog_DBG(TAG, " ----->> protocol version %" PRIu32, nla->version); - ber_write_integer(s, nla->version); /* INTEGER */ - - /* [1] negoTokens (NegoData) */ - if (!nla_client_write_nego_token(s, &nla->negoToken)) + WLog_DBG(TAG, "----->> sending..."); + if (!WinPrAsn1EncSeqContainer(enc)) goto fail; - /* [2] authInfo (OCTET STRING) */ - if (auth_info_length > 0) + /* 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 (ber_write_sequence_octet_string_from_secbuffer(s, 2, &nla->authInfo) != - auth_info_length) + 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; } - /* [3] pubKeyAuth (OCTET STRING) */ - if (pub_key_auth_length > 0) + /* authInfo [2] OCTET STRING */ + if (nla->authInfo.cbBuffer > 0) { WLog_DBG(TAG, " ----->> public key auth"); - if (ber_write_sequence_octet_string_from_secbuffer(s, 3, &nla->pubKeyAuth) != - pub_key_auth_length) + octet_string.data = nla->authInfo.pvBuffer; + octet_string.len = nla->authInfo.cbBuffer; + if (!WinPrAsn1EncContextualOctetString(enc, 2, &octet_string)) goto fail; } - /* [4] errorCode (INTEGER) */ - if (error_code_length > 0) + /* 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); - ber_write_contextual_tag(s, 4, error_code_length, TRUE); - ber_write_integer(s, nla->errorCode); - } - - /* [5] clientNonce (OCTET STRING) */ - if (client_nonce_length > 0) - { - WLog_DBG(TAG, " ----->> client nonce"); - if (ber_write_sequence_octet_string_from_secbuffer(s, 5, &nla->ClientNonce) != - client_nonce_length) + if (!WinPrAsn1EncContextualInteger(enc, 4, nla->errorCode)) goto fail; } - WLog_DBG(TAG, "[%" PRIuz " bytes]", Stream_GetPosition(s)); + /* 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; } static int nla_decode_ts_request(rdpNla* nla, wStream* s) { - int rc = -1; - size_t length; + WinPrAsn1Decoder dec, dec2, dec3; + BOOL error; + WinPrAsn1_tagId tag; + WinPrAsn1_OctetString octet_string; + WinPrAsn1_INTEGER val; UINT32 version = 0; + char buffer[1024]; WINPR_ASSERT(nla); WINPR_ASSERT(s); + WinPrAsn1Decoder_Init(&dec, WINPR_ASN1_DER, s); + WLog_DBG(TAG, "<<----- receiving..."); /* TSRequest */ - if (!ber_read_sequence_tag(s, &length) || !ber_read_contextual_tag(s, 0, &length, TRUE) || - !ber_read_integer(s, &version)) - { - goto fail; - } + if (!WinPrAsn1DecReadSequence(&dec, &dec2)) + return -1; + dec = dec2; + /* version [0] INTEGER */ + if (!WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &val)) + return -1; + version = (UINT)val; WLog_DBG(TAG, " <<----- protocol version %" PRIu32, version); + if (nla->peerVersion == 0) nla->peerVersion = version; @@ -2401,66 +2302,69 @@ static int nla_decode_ts_request(rdpNla* nla, wStream* s) { WLog_ERR(TAG, "CredSSP peer changed protocol version from %" PRIu32 " to %" PRIu32, nla->peerVersion, version); - goto fail; + return -1; } - /* [1] negoTokens (NegoData) */ - if (ber_read_contextual_tag(s, 1, &length, TRUE) != FALSE) + while (WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2)) { - WLog_DBG(TAG, " <<----- nego token"); - if (!ber_read_sequence_tag(s, &length) || /* SEQUENCE OF NegoDataItem */ - !ber_read_sequence_tag(s, &length) || /* NegoDataItem */ - !ber_read_contextual_tag(s, 0, &length, TRUE)) + switch (tag) { - goto fail; - } - - if (!nla_decode_to_buffer(s, &nla->negoToken)) - goto fail; - } - - /* [2] authInfo (OCTET STRING) */ - if (ber_read_contextual_tag(s, 2, &length, TRUE) != FALSE) - { - WLog_DBG(TAG, " <<----- auth info"); - if (!nla_decode_to_buffer(s, &nla->authInfo)) - goto fail; - } - - /* [3] pubKeyAuth (OCTET STRING) */ - if (ber_read_contextual_tag(s, 3, &length, TRUE) != FALSE) - { - WLog_DBG(TAG, " <<----- public key info"); - if (!nla_decode_to_buffer(s, &nla->pubKeyAuth)) - goto fail; - } - - /* [4] errorCode (INTEGER) */ - if (nla->peerVersion >= 3) - { - if (ber_read_contextual_tag(s, 4, &length, TRUE) != FALSE) - { - char buffer[1024]; - if (!ber_read_integer(s, &nla->errorCode)) - goto fail; - WLog_DBG(TAG, " <<----- error code %s 0x%08" PRIx32, - winpr_strerror(nla->errorCode, buffer, sizeof(buffer)), nla->errorCode); - } - - if (nla->peerVersion >= 5) - { - if (ber_read_contextual_tag(s, 5, &length, TRUE) != FALSE) - { + case 1: + WLog_DBG(TAG, " <<----- nego token"); + /* negoTokens [1] SEQUENCE OF SEQUENCE */ + if (!WinPrAsn1DecReadSequence(&dec2, &dec3) || + !WinPrAsn1DecReadSequence(&dec3, &dec2)) + return -1; + /* negoToken [0] OCTET STRING */ + if (!WinPrAsn1DecReadContextualOctetString(&dec2, 0, &error, &octet_string, + FALSE) && + error) + return -1; + if (!nla_sec_buffer_alloc_from_data(&nla->negoToken, octet_string.data, 0, + octet_string.len)) + return -1; + break; + case 2: + WLog_DBG(TAG, " <<----- auth info"); + /* authInfo [2] OCTET STRING */ + if (!WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE)) + return -1; + if (!nla_sec_buffer_alloc_from_data(&nla->authInfo, octet_string.data, 0, + octet_string.len)) + return -1; + break; + case 3: + WLog_DBG(TAG, " <<----- public key info"); + /* pubKeyAuth [3] OCTET STRING */ + if (!WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE)) + return -1; + if (!nla_sec_buffer_alloc_from_data(&nla->pubKeyAuth, octet_string.data, 0, + octet_string.len)) + return -1; + break; + case 4: + /* errorCode [4] INTEGER */ + if (!WinPrAsn1DecReadInteger(&dec2, &val)) + return -1; + nla->errorCode = (UINT)val; + WLog_DBG(TAG, " <<----- error code %s 0x%08" PRIx32, + winpr_strerror(nla->errorCode, buffer, sizeof(buffer)), nla->errorCode); + break; + case 5: WLog_DBG(TAG, " <<----- client nonce"); - if (!nla_decode_to_buffer(s, &nla->ClientNonce)) - goto fail; - } + /* clientNonce [5] OCTET STRING */ + if (!WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE)) + return -1; + if (!nla_sec_buffer_alloc_from_data(&nla->ClientNonce, octet_string.data, 0, + octet_string.len)) + return -1; + break; + default: + return -1; } } - rc = 1; -fail: - return rc; + return 1; } int nla_recv_pdu(rdpNla* nla, wStream* s) diff --git a/libfreerdp/core/tscredentials.c b/libfreerdp/core/tscredentials.c deleted file mode 100644 index ac3587248..000000000 --- a/libfreerdp/core/tscredentials.c +++ /dev/null @@ -1,982 +0,0 @@ -/* ============================================================================================================ - * this file has been generated using - * ./tools/asn_parser_generator.py --input=libfreerdp/core/credssp.asn1 --output-kind=impls - * --output=libfreerdp/core/tscredentials.c - * - * /!\ If you want to modify this file you'd probably better change asn_parser_generator.py or the - * corresponding ASN1 definition file - * - * ============================================================================================================ - */ - -#include -#include - -#include "tscredentials.h" - -#include - -#define TAG FREERDP_TAG("core.tscredentials") - -size_t ber_sizeof_nla_TSCredentials_content(const TSCredentials_t* item) -{ - size_t ret = 0; - - /* [0] credType (INTEGER)*/ - ret += ber_sizeof_contextual_integer(item->credType); - - /* [1] credentials (OCTET STRING)*/ - ret += ber_sizeof_contextual_octet_string(item->credentialsLen); - - return ret; -} - -size_t ber_sizeof_nla_TSCredentials(const TSCredentials_t* item) -{ - size_t ret = ber_sizeof_nla_TSCredentials_content(item); - return ber_sizeof_sequence(ret); -} -size_t ber_sizeof_contextual_nla_TSCredentials(const TSCredentials_t* item) -{ - size_t innerSz = ber_sizeof_nla_TSCredentials(item); - return ber_sizeof_contextual_tag(innerSz) + innerSz; -} - -void nla_TSCredentials_free(TSCredentials_t** pitem) -{ - TSCredentials_t* item; - - WINPR_ASSERT(pitem); - item = *pitem; - if (!item) - return; - - free(item->credentials); - free(item); - *pitem = NULL; -} - -size_t ber_write_nla_TSCredentials(wStream* s, const TSCredentials_t* item) -{ - size_t content_size = ber_sizeof_nla_TSCredentials_content(item); - size_t ret = 0; - - ret = ber_write_sequence_tag(s, content_size); - /* [0] credType (INTEGER) */ - if (!ber_write_contextual_integer(s, 0, item->credType)) - return 0; - - /* [1] credentials (OCTET STRING) */ - if (!ber_write_contextual_octet_string(s, 1, item->credentials, item->credentialsLen)) - return 0; - - return ret + content_size; -} - -size_t ber_write_contextual_nla_TSCredentials(wStream* s, BYTE tag, const TSCredentials_t* item) -{ - size_t ret; - size_t inner = ber_sizeof_nla_TSCredentials(item); - - ret = ber_write_contextual_tag(s, tag, inner, TRUE); - ber_write_nla_TSCredentials(s, item); - return ret + inner; -} - -BOOL ber_read_nla_TSCredentials(wStream* s, TSCredentials_t** pret) -{ - wStream seqstream; - size_t seqLength; - size_t inner_size; - wStream fieldStream; - TSCredentials_t* item; - BOOL ret; - - if (!ber_read_sequence_tag(s, &seqLength) || - !Stream_CheckAndLogRequiredLength(TAG, s, seqLength)) - return FALSE; - Stream_StaticInit(&seqstream, Stream_Pointer(s), seqLength); - - item = calloc(1, sizeof(*item)); - if (!item) - return FALSE; - - /* [0] credType (INTEGER) */ - ret = ber_read_contextual_tag(&seqstream, 0, &inner_size, TRUE); - if (!ret) - goto out_fail_credType; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_integer(&fieldStream, &item->credType); - if (!ret) - goto out_fail_credType; - - /* [1] credentials (OCTET STRING) */ - ret = ber_read_contextual_tag(&seqstream, 1, &inner_size, TRUE); - if (!ret) - goto out_fail_credentials; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_octet_string(&fieldStream, &item->credentials, &item->credentialsLen); - if (!ret) - goto out_fail_credentials; - - *pret = item; - return TRUE; - -out_fail_credentials: - -out_fail_credType: - free(item); - return FALSE; -} - -size_t ber_sizeof_nla_TSPasswordCreds_content(const TSPasswordCreds_t* item) -{ - size_t ret = 0; - - /* [0] domainName (OCTET STRING)*/ - ret += ber_sizeof_contextual_octet_string(item->domainNameLen); - - /* [1] userName (OCTET STRING)*/ - ret += ber_sizeof_contextual_octet_string(item->userNameLen); - - /* [2] password (OCTET STRING)*/ - ret += ber_sizeof_contextual_octet_string(item->passwordLen); - - return ret; -} - -size_t ber_sizeof_nla_TSPasswordCreds(const TSPasswordCreds_t* item) -{ - size_t ret = ber_sizeof_nla_TSPasswordCreds_content(item); - return ber_sizeof_sequence(ret); -} -size_t ber_sizeof_contextual_nla_TSPasswordCreds(const TSPasswordCreds_t* item) -{ - size_t innerSz = ber_sizeof_nla_TSPasswordCreds(item); - return ber_sizeof_contextual_tag(innerSz) + innerSz; -} - -void nla_TSPasswordCreds_free(TSPasswordCreds_t** pitem) -{ - TSPasswordCreds_t* item; - - WINPR_ASSERT(pitem); - item = *pitem; - if (!item) - return; - - free(item->domainName); - free(item->userName); - free(item->password); - free(item); - *pitem = NULL; -} - -size_t ber_write_nla_TSPasswordCreds(wStream* s, const TSPasswordCreds_t* item) -{ - size_t content_size = ber_sizeof_nla_TSPasswordCreds_content(item); - size_t ret = 0; - - ret = ber_write_sequence_tag(s, content_size); - /* [0] domainName (OCTET STRING) */ - if (!ber_write_contextual_octet_string(s, 0, item->domainName, item->domainNameLen)) - return 0; - - /* [1] userName (OCTET STRING) */ - if (!ber_write_contextual_octet_string(s, 1, item->userName, item->userNameLen)) - return 0; - - /* [2] password (OCTET STRING) */ - if (!ber_write_contextual_octet_string(s, 2, item->password, item->passwordLen)) - return 0; - - return ret + content_size; -} - -size_t ber_write_contextual_nla_TSPasswordCreds(wStream* s, BYTE tag, const TSPasswordCreds_t* item) -{ - size_t ret; - size_t inner = ber_sizeof_nla_TSPasswordCreds(item); - - ret = ber_write_contextual_tag(s, tag, inner, TRUE); - ber_write_nla_TSPasswordCreds(s, item); - return ret + inner; -} - -BOOL ber_read_nla_TSPasswordCreds(wStream* s, TSPasswordCreds_t** pret) -{ - wStream seqstream; - size_t seqLength; - size_t inner_size; - wStream fieldStream; - TSPasswordCreds_t* item; - BOOL ret; - - if (!ber_read_sequence_tag(s, &seqLength) || - !Stream_CheckAndLogRequiredLength(TAG, s, seqLength)) - return FALSE; - Stream_StaticInit(&seqstream, Stream_Pointer(s), seqLength); - - item = calloc(1, sizeof(*item)); - if (!item) - return FALSE; - - /* [0] domainName (OCTET STRING) */ - ret = ber_read_contextual_tag(&seqstream, 0, &inner_size, TRUE); - if (!ret) - goto out_fail_domainName; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_octet_string(&fieldStream, &item->domainName, &item->domainNameLen); - if (!ret) - goto out_fail_domainName; - - /* [1] userName (OCTET STRING) */ - ret = ber_read_contextual_tag(&seqstream, 1, &inner_size, TRUE); - if (!ret) - goto out_fail_userName; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_octet_string(&fieldStream, &item->userName, &item->userNameLen); - if (!ret) - goto out_fail_userName; - - /* [2] password (OCTET STRING) */ - ret = ber_read_contextual_tag(&seqstream, 2, &inner_size, TRUE); - if (!ret) - goto out_fail_password; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_octet_string(&fieldStream, &item->password, &item->passwordLen); - if (!ret) - goto out_fail_password; - - *pret = item; - return TRUE; - -out_fail_password: - free(item->userName); -out_fail_userName: - free(item->domainName); -out_fail_domainName: - free(item); - return FALSE; -} - -size_t ber_sizeof_nla_TSCspDataDetail_content(const TSCspDataDetail_t* item) -{ - size_t ret = 0; - - /* [0] keySpec (INTEGER)*/ - ret += ber_sizeof_contextual_integer(item->keySpec); - - /* [1] cardName (OCTET STRING) OPTIONAL*/ - if (item->cardName) - { - ret += ber_sizeof_contextual_octet_string(strlen(item->cardName) * 2); - } - - /* [2] readerName (OCTET STRING) OPTIONAL*/ - if (item->readerName) - { - ret += ber_sizeof_contextual_octet_string(strlen(item->readerName) * 2); - } - - /* [3] containerName (OCTET STRING) OPTIONAL*/ - if (item->containerName) - { - ret += ber_sizeof_contextual_octet_string(strlen(item->containerName) * 2); - } - - /* [4] cspName (OCTET STRING) OPTIONAL*/ - if (item->cspName) - { - ret += ber_sizeof_contextual_octet_string(strlen(item->cspName) * 2); - } - - return ret; -} - -size_t ber_sizeof_nla_TSCspDataDetail(const TSCspDataDetail_t* item) -{ - size_t ret = ber_sizeof_nla_TSCspDataDetail_content(item); - return ber_sizeof_sequence(ret); -} -size_t ber_sizeof_contextual_nla_TSCspDataDetail(const TSCspDataDetail_t* item) -{ - size_t innerSz = ber_sizeof_nla_TSCspDataDetail(item); - return ber_sizeof_contextual_tag(innerSz) + innerSz; -} - -void nla_TSCspDataDetail_free(TSCspDataDetail_t** pitem) -{ - TSCspDataDetail_t* item; - - WINPR_ASSERT(pitem); - item = *pitem; - if (!item) - return; - - free(item->cardName); - free(item->readerName); - free(item->containerName); - free(item->cspName); - free(item); - *pitem = NULL; -} - -size_t ber_write_nla_TSCspDataDetail(wStream* s, const TSCspDataDetail_t* item) -{ - size_t content_size = ber_sizeof_nla_TSCspDataDetail_content(item); - size_t ret = 0; - - ret = ber_write_sequence_tag(s, content_size); - /* [0] keySpec (INTEGER) */ - if (!ber_write_contextual_integer(s, 0, item->keySpec)) - return 0; - - /* [1] cardName (OCTET STRING) OPTIONAL */ - if (item->cardName) - { - if (!ber_write_contextual_char_to_unicode_octet_string(s, 1, item->cardName)) - return 0; - } - - /* [2] readerName (OCTET STRING) OPTIONAL */ - if (item->readerName) - { - if (!ber_write_contextual_char_to_unicode_octet_string(s, 2, item->readerName)) - return 0; - } - - /* [3] containerName (OCTET STRING) OPTIONAL */ - if (item->containerName) - { - if (!ber_write_contextual_char_to_unicode_octet_string(s, 3, item->containerName)) - return 0; - } - - /* [4] cspName (OCTET STRING) OPTIONAL */ - if (item->cspName) - { - if (!ber_write_contextual_char_to_unicode_octet_string(s, 4, item->cspName)) - return 0; - } - - return ret + content_size; -} - -size_t ber_write_contextual_nla_TSCspDataDetail(wStream* s, BYTE tag, const TSCspDataDetail_t* item) -{ - size_t ret; - size_t inner = ber_sizeof_nla_TSCspDataDetail(item); - - ret = ber_write_contextual_tag(s, tag, inner, TRUE); - ber_write_nla_TSCspDataDetail(s, item); - return ret + inner; -} - -BOOL ber_read_nla_TSCspDataDetail(wStream* s, TSCspDataDetail_t** pret) -{ - wStream seqstream; - size_t seqLength; - size_t inner_size; - wStream fieldStream; - TSCspDataDetail_t* item; - BOOL ret; - - if (!ber_read_sequence_tag(s, &seqLength) || - !Stream_CheckAndLogRequiredLength(TAG, s, seqLength)) - return FALSE; - Stream_StaticInit(&seqstream, Stream_Pointer(s), seqLength); - - item = calloc(1, sizeof(*item)); - if (!item) - return FALSE; - - /* [0] keySpec (INTEGER) */ - ret = ber_read_contextual_tag(&seqstream, 0, &inner_size, TRUE); - if (!ret) - goto out_fail_keySpec; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_integer(&fieldStream, &item->keySpec); - if (!ret) - goto out_fail_keySpec; - - /* [1] cardName (OCTET STRING) OPTIONAL */ - ret = ber_read_contextual_tag(&seqstream, 1, &inner_size, TRUE); - if (ret) - { - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_char_from_unicode_octet_string(&fieldStream, &item->cardName); - if (!ret) - goto out_fail_cardName; - } - /* [2] readerName (OCTET STRING) OPTIONAL */ - ret = ber_read_contextual_tag(&seqstream, 2, &inner_size, TRUE); - if (ret) - { - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_char_from_unicode_octet_string(&fieldStream, &item->readerName); - if (!ret) - goto out_fail_readerName; - } - /* [3] containerName (OCTET STRING) OPTIONAL */ - ret = ber_read_contextual_tag(&seqstream, 3, &inner_size, TRUE); - if (ret) - { - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_char_from_unicode_octet_string(&fieldStream, &item->containerName); - if (!ret) - goto out_fail_containerName; - } - /* [4] cspName (OCTET STRING) OPTIONAL */ - ret = ber_read_contextual_tag(&seqstream, 4, &inner_size, TRUE); - if (ret) - { - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_char_from_unicode_octet_string(&fieldStream, &item->cspName); - if (!ret) - goto out_fail_cspName; - } - *pret = item; - return TRUE; - -out_fail_cspName: - free(item->containerName); -out_fail_containerName: - free(item->readerName); -out_fail_readerName: - free(item->cardName); -out_fail_cardName: - -out_fail_keySpec: - free(item); - return FALSE; -} - -size_t ber_sizeof_nla_TSSmartCardCreds_content(const TSSmartCardCreds_t* item) -{ - size_t ret = 0; - - /* [0] pin (OCTET STRING)*/ - ret += ber_sizeof_contextual_octet_string(strlen(item->pin) * 2); - - /* [1] cspData (TSCspDataDetail)*/ - ret += ber_sizeof_contextual_nla_TSCspDataDetail(item->cspData); - - /* [2] userHint (OCTET STRING) OPTIONAL*/ - if (item->userHint) - { - ret += ber_sizeof_contextual_octet_string(strlen(item->userHint) * 2); - } - - /* [3] domainHint (OCTET STRING) OPTIONAL*/ - if (item->domainHint) - { - ret += ber_sizeof_contextual_octet_string(strlen(item->domainHint) * 2); - } - - return ret; -} - -size_t ber_sizeof_nla_TSSmartCardCreds(const TSSmartCardCreds_t* item) -{ - size_t ret = ber_sizeof_nla_TSSmartCardCreds_content(item); - return ber_sizeof_sequence(ret); -} -size_t ber_sizeof_contextual_nla_TSSmartCardCreds(const TSSmartCardCreds_t* item) -{ - size_t innerSz = ber_sizeof_nla_TSSmartCardCreds(item); - return ber_sizeof_contextual_tag(innerSz) + innerSz; -} - -void nla_TSSmartCardCreds_free(TSSmartCardCreds_t** pitem) -{ - TSSmartCardCreds_t* item; - - WINPR_ASSERT(pitem); - item = *pitem; - if (!item) - return; - - free(item->pin); - nla_TSCspDataDetail_free(&item->cspData); - free(item->userHint); - free(item->domainHint); - free(item); - *pitem = NULL; -} - -size_t ber_write_nla_TSSmartCardCreds(wStream* s, const TSSmartCardCreds_t* item) -{ - size_t content_size = ber_sizeof_nla_TSSmartCardCreds_content(item); - size_t ret = 0; - - ret = ber_write_sequence_tag(s, content_size); - /* [0] pin (OCTET STRING) */ - if (!ber_write_contextual_char_to_unicode_octet_string(s, 0, item->pin)) - return 0; - - /* [1] cspData (TSCspDataDetail) */ - if (!ber_write_contextual_nla_TSCspDataDetail(s, 1, item->cspData)) - return 0; - - /* [2] userHint (OCTET STRING) OPTIONAL */ - if (item->userHint) - { - if (!ber_write_contextual_char_to_unicode_octet_string(s, 2, item->userHint)) - return 0; - } - - /* [3] domainHint (OCTET STRING) OPTIONAL */ - if (item->domainHint) - { - if (!ber_write_contextual_char_to_unicode_octet_string(s, 3, item->domainHint)) - return 0; - } - - return ret + content_size; -} - -size_t ber_write_contextual_nla_TSSmartCardCreds(wStream* s, BYTE tag, - const TSSmartCardCreds_t* item) -{ - size_t ret; - size_t inner = ber_sizeof_nla_TSSmartCardCreds(item); - - ret = ber_write_contextual_tag(s, tag, inner, TRUE); - ber_write_nla_TSSmartCardCreds(s, item); - return ret + inner; -} - -BOOL ber_read_nla_TSSmartCardCreds(wStream* s, TSSmartCardCreds_t** pret) -{ - wStream seqstream; - size_t seqLength; - size_t inner_size; - wStream fieldStream; - TSSmartCardCreds_t* item; - BOOL ret; - - if (!ber_read_sequence_tag(s, &seqLength) || - !Stream_CheckAndLogRequiredLength(TAG, s, seqLength)) - return FALSE; - Stream_StaticInit(&seqstream, Stream_Pointer(s), seqLength); - - item = calloc(1, sizeof(*item)); - if (!item) - return FALSE; - - /* [0] pin (OCTET STRING) */ - ret = ber_read_contextual_tag(&seqstream, 0, &inner_size, TRUE); - if (!ret) - goto out_fail_pin; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_char_from_unicode_octet_string(&fieldStream, &item->pin); - if (!ret) - goto out_fail_pin; - - /* [1] cspData (TSCspDataDetail) */ - ret = ber_read_contextual_tag(&seqstream, 1, &inner_size, TRUE); - if (!ret) - goto out_fail_cspData; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_nla_TSCspDataDetail(&fieldStream, &item->cspData); - if (!ret) - goto out_fail_cspData; - - /* [2] userHint (OCTET STRING) OPTIONAL */ - ret = ber_read_contextual_tag(&seqstream, 2, &inner_size, TRUE); - if (ret) - { - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_char_from_unicode_octet_string(&fieldStream, &item->userHint); - if (!ret) - goto out_fail_userHint; - } - /* [3] domainHint (OCTET STRING) OPTIONAL */ - ret = ber_read_contextual_tag(&seqstream, 3, &inner_size, TRUE); - if (ret) - { - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_char_from_unicode_octet_string(&fieldStream, &item->domainHint); - if (!ret) - goto out_fail_domainHint; - } - *pret = item; - return TRUE; - -out_fail_domainHint: - free(item->userHint); -out_fail_userHint: - nla_TSCspDataDetail_free(&item->cspData); -out_fail_cspData: - free(item->pin); -out_fail_pin: - free(item); - return FALSE; -} - -size_t ber_sizeof_nla_TSRemoteGuardPackageCred_content(const TSRemoteGuardPackageCred_t* item) -{ - size_t ret = 0; - - /* [0] packageName (OCTET STRING)*/ - ret += ber_sizeof_contextual_octet_string(item->packageNameLen); - - /* [1] credBuffer (OCTET STRING)*/ - ret += ber_sizeof_contextual_octet_string(item->credBufferLen); - - return ret; -} - -size_t ber_sizeof_nla_TSRemoteGuardPackageCred(const TSRemoteGuardPackageCred_t* item) -{ - size_t ret = ber_sizeof_nla_TSRemoteGuardPackageCred_content(item); - return ber_sizeof_sequence(ret); -} -size_t ber_sizeof_contextual_nla_TSRemoteGuardPackageCred(const TSRemoteGuardPackageCred_t* item) -{ - size_t innerSz = ber_sizeof_nla_TSRemoteGuardPackageCred(item); - return ber_sizeof_contextual_tag(innerSz) + innerSz; -} - -void nla_TSRemoteGuardPackageCred_free(TSRemoteGuardPackageCred_t** pitem) -{ - TSRemoteGuardPackageCred_t* item; - - WINPR_ASSERT(pitem); - item = *pitem; - if (!item) - return; - - free(item->packageName); - free(item->credBuffer); - free(item); - *pitem = NULL; -} - -size_t ber_write_nla_TSRemoteGuardPackageCred(wStream* s, const TSRemoteGuardPackageCred_t* item) -{ - size_t content_size = ber_sizeof_nla_TSRemoteGuardPackageCred_content(item); - size_t ret = 0; - - ret = ber_write_sequence_tag(s, content_size); - /* [0] packageName (OCTET STRING) */ - if (!ber_write_contextual_octet_string(s, 0, item->packageName, item->packageNameLen)) - return 0; - - /* [1] credBuffer (OCTET STRING) */ - if (!ber_write_contextual_octet_string(s, 1, item->credBuffer, item->credBufferLen)) - return 0; - - return ret + content_size; -} - -size_t ber_write_contextual_nla_TSRemoteGuardPackageCred(wStream* s, BYTE tag, - const TSRemoteGuardPackageCred_t* item) -{ - size_t ret; - size_t inner = ber_sizeof_nla_TSRemoteGuardPackageCred(item); - - ret = ber_write_contextual_tag(s, tag, inner, TRUE); - ber_write_nla_TSRemoteGuardPackageCred(s, item); - return ret + inner; -} - -BOOL ber_read_nla_TSRemoteGuardPackageCred(wStream* s, TSRemoteGuardPackageCred_t** pret) -{ - wStream seqstream; - size_t seqLength; - size_t inner_size; - wStream fieldStream; - TSRemoteGuardPackageCred_t* item; - BOOL ret; - - if (!ber_read_sequence_tag(s, &seqLength) || - !Stream_CheckAndLogRequiredLength(TAG, s, seqLength)) - return FALSE; - Stream_StaticInit(&seqstream, Stream_Pointer(s), seqLength); - - item = calloc(1, sizeof(*item)); - if (!item) - return FALSE; - - /* [0] packageName (OCTET STRING) */ - ret = ber_read_contextual_tag(&seqstream, 0, &inner_size, TRUE); - if (!ret) - goto out_fail_packageName; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_octet_string(&fieldStream, &item->packageName, &item->packageNameLen); - if (!ret) - goto out_fail_packageName; - - /* [1] credBuffer (OCTET STRING) */ - ret = ber_read_contextual_tag(&seqstream, 1, &inner_size, TRUE); - if (!ret) - goto out_fail_credBuffer; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_octet_string(&fieldStream, &item->credBuffer, &item->credBufferLen); - if (!ret) - goto out_fail_credBuffer; - - *pret = item; - return TRUE; - -out_fail_credBuffer: - free(item->packageName); -out_fail_packageName: - free(item); - return FALSE; -} - -size_t ber_sizeof_nla_TSRemoteGuardPackageCred_array_content(const TSRemoteGuardPackageCred_t* item, - size_t nitems) -{ - size_t i, ret = 0; - for (i = 0; i < nitems; i++, item++) - ret += ber_sizeof_nla_TSRemoteGuardPackageCred(item); - - return ber_sizeof_sequence(ret); -} - -size_t ber_sizeof_nla_TSRemoteGuardPackageCred_array(const TSRemoteGuardPackageCred_t* item, - size_t nitems) -{ - return ber_sizeof_sequence(ber_sizeof_nla_TSRemoteGuardPackageCred_array_content(item, nitems)); -} - -size_t -ber_sizeof_contextual_nla_TSRemoteGuardPackageCred_array(const TSRemoteGuardPackageCred_t* item, - size_t nitems) -{ - size_t inner = ber_sizeof_nla_TSRemoteGuardPackageCred_array(item, nitems); - return ber_sizeof_contextual_tag(inner) + inner; -} - -size_t ber_write_nla_TSRemoteGuardPackageCred_array(wStream* s, - const TSRemoteGuardPackageCred_t* item, - size_t nitems) -{ - size_t i, r, ret; - size_t inner_len = ber_sizeof_nla_TSRemoteGuardPackageCred_array_content(item, nitems); - - ret = ber_write_sequence_tag(s, inner_len); - - for (i = 0; i < nitems; i++, item++) - { - r = ber_write_nla_TSRemoteGuardPackageCred(s, item); - if (!r) - return 0; - ret += r; - } - - return ret; -} - -size_t ber_write_contextual_nla_TSRemoteGuardPackageCred_array( - wStream* s, BYTE tag, const TSRemoteGuardPackageCred_t* item, size_t nitems) -{ - size_t ret; - size_t inner = ber_sizeof_nla_TSRemoteGuardPackageCred_array(item, nitems); - - ret = ber_write_contextual_tag(s, tag, inner, TRUE); - ber_write_nla_TSRemoteGuardPackageCred_array(s, item, nitems); - return ret + inner; -} - -BOOL ber_read_nla_TSRemoteGuardPackageCred_array(wStream* s, TSRemoteGuardPackageCred_t** pitems, - size_t* nitems) -{ - size_t subLen; - wStream subStream; - TSRemoteGuardPackageCred_t* retItems = NULL; - size_t ret = 0; - - if (!ber_read_sequence_tag(s, &subLen) || !Stream_CheckAndLogRequiredLength(TAG, s, subLen)) - return FALSE; - - Stream_StaticInit(&subStream, Stream_Pointer(s), subLen); - while (Stream_GetRemainingLength(&subStream)) - { - TSRemoteGuardPackageCred_t* item; - TSRemoteGuardPackageCred_t* tmpRet; - - if (!ber_read_nla_TSRemoteGuardPackageCred(&subStream, &item)) - { - free(retItems); - return FALSE; - } - - tmpRet = realloc(retItems, (ret + 1) * sizeof(TSRemoteGuardPackageCred_t)); - if (!tmpRet) - { - free(retItems); - return FALSE; - } - retItems = tmpRet; - - memcpy(&retItems[ret], item, sizeof(*item)); - free(item); - ret++; - } - - *pitems = retItems; - *nitems = ret; - return TRUE; -} - -size_t ber_sizeof_nla_TSRemoteGuardCreds_content(const TSRemoteGuardCreds_t* item) -{ - size_t ret = 0; - - /* [0] logonCred (TSRemoteGuardPackageCred)*/ - ret += ber_sizeof_contextual_nla_TSRemoteGuardPackageCred(item->logonCred); - - /* [1] supplementalCreds (SEQUENCE OF) OPTIONAL*/ - if (item->supplementalCreds) - { - ret += ber_sizeof_contextual_nla_TSRemoteGuardPackageCred_array( - item->supplementalCreds, item->supplementalCredsItems); - } - - return ret; -} - -size_t ber_sizeof_nla_TSRemoteGuardCreds(const TSRemoteGuardCreds_t* item) -{ - size_t ret = ber_sizeof_nla_TSRemoteGuardCreds_content(item); - return ber_sizeof_sequence(ret); -} -size_t ber_sizeof_contextual_nla_TSRemoteGuardCreds(const TSRemoteGuardCreds_t* item) -{ - size_t innerSz = ber_sizeof_nla_TSRemoteGuardCreds(item); - return ber_sizeof_contextual_tag(innerSz) + innerSz; -} - -void nla_TSRemoteGuardCreds_free(TSRemoteGuardCreds_t** pitem) -{ - TSRemoteGuardCreds_t* item; - - WINPR_ASSERT(pitem); - item = *pitem; - if (!item) - return; - - nla_TSRemoteGuardPackageCred_free(&item->logonCred); - free(item); - *pitem = NULL; -} - -size_t ber_write_nla_TSRemoteGuardCreds(wStream* s, const TSRemoteGuardCreds_t* item) -{ - size_t content_size = ber_sizeof_nla_TSRemoteGuardCreds_content(item); - size_t ret = 0; - - ret = ber_write_sequence_tag(s, content_size); - /* [0] logonCred (TSRemoteGuardPackageCred) */ - if (!ber_write_contextual_nla_TSRemoteGuardPackageCred(s, 0, item->logonCred)) - return 0; - - /* [1] supplementalCreds (SEQUENCE OF) OPTIONAL */ - if (item->supplementalCreds) - { - if (!ber_write_contextual_nla_TSRemoteGuardPackageCred_array(s, 1, item->supplementalCreds, - item->supplementalCredsItems)) - return 0; - } - - return ret + content_size; -} - -size_t ber_write_contextual_nla_TSRemoteGuardCreds(wStream* s, BYTE tag, - const TSRemoteGuardCreds_t* item) -{ - size_t ret; - size_t inner = ber_sizeof_nla_TSRemoteGuardCreds(item); - - ret = ber_write_contextual_tag(s, tag, inner, TRUE); - ber_write_nla_TSRemoteGuardCreds(s, item); - return ret + inner; -} - -BOOL ber_read_nla_TSRemoteGuardCreds(wStream* s, TSRemoteGuardCreds_t** pret) -{ - wStream seqstream; - size_t seqLength; - size_t inner_size; - wStream fieldStream; - TSRemoteGuardCreds_t* item; - BOOL ret; - - if (!ber_read_sequence_tag(s, &seqLength) || - !Stream_CheckAndLogRequiredLength(TAG, s, seqLength)) - return FALSE; - Stream_StaticInit(&seqstream, Stream_Pointer(s), seqLength); - - item = calloc(1, sizeof(*item)); - if (!item) - return FALSE; - - /* [0] logonCred (TSRemoteGuardPackageCred) */ - ret = ber_read_contextual_tag(&seqstream, 0, &inner_size, TRUE); - if (!ret) - goto out_fail_logonCred; - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_nla_TSRemoteGuardPackageCred(&fieldStream, &item->logonCred); - if (!ret) - goto out_fail_logonCred; - - /* [1] supplementalCreds (SEQUENCE OF) OPTIONAL */ - ret = ber_read_contextual_tag(&seqstream, 1, &inner_size, TRUE); - if (ret) - { - Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size); - Stream_Seek(&seqstream, inner_size); - - ret = ber_read_nla_TSRemoteGuardPackageCred_array(&fieldStream, &item->supplementalCreds, - &item->supplementalCredsItems); - if (!ret) - goto out_fail_supplementalCreds; - } - *pret = item; - return TRUE; - -out_fail_supplementalCreds: - nla_TSRemoteGuardPackageCred_free(&item->logonCred); -out_fail_logonCred: - free(item); - return FALSE; -} diff --git a/libfreerdp/core/tscredentials.h b/libfreerdp/core/tscredentials.h deleted file mode 100644 index aa973450c..000000000 --- a/libfreerdp/core/tscredentials.h +++ /dev/null @@ -1,132 +0,0 @@ -/* ============================================================================================================ - * this file has been generated using - * ./tools/asn_parser_generator.py --input=libfreerdp/core/credssp.asn1 --output-kind=headers - * --output=libfreerdp/core/tscredentials.h - * - * /!\ If you want to modify this file you'd probably better change asn_parser_generator.py or the - * corresponding ASN1 definition file - * - * ============================================================================================================ - */ -#ifndef LIBFREERDP_CORE_CREDSSP_ASN1_H -#define LIBFREERDP_CORE_CREDSSP_ASN1_H - -#include - -typedef struct -{ - UINT32 credType; - size_t credentialsLen; - BYTE* credentials; -} TSCredentials_t; - -typedef struct -{ - size_t domainNameLen; - BYTE* domainName; - size_t userNameLen; - BYTE* userName; - size_t passwordLen; - BYTE* password; -} TSPasswordCreds_t; - -typedef struct -{ - UINT32 keySpec; - char* cardName; - char* readerName; - char* containerName; - char* cspName; -} TSCspDataDetail_t; - -typedef struct -{ - char* pin; - TSCspDataDetail_t* cspData; - char* userHint; - char* domainHint; -} TSSmartCardCreds_t; - -typedef struct -{ - size_t packageNameLen; - BYTE* packageName; - size_t credBufferLen; - BYTE* credBuffer; -} TSRemoteGuardPackageCred_t; - -typedef struct -{ - TSRemoteGuardPackageCred_t* logonCred; - size_t supplementalCredsItems; - TSRemoteGuardPackageCred_t* supplementalCreds; -} TSRemoteGuardCreds_t; - -size_t ber_sizeof_nla_TSCredentials_content(const TSCredentials_t* item); -size_t ber_sizeof_nla_TSCredentials(const TSCredentials_t* item); -size_t ber_sizeof_contextual_nla_TSCredentials(const TSCredentials_t* item); -void nla_TSCredentials_free(TSCredentials_t** pitem); -size_t ber_write_nla_TSCredentials(wStream* s, const TSCredentials_t* item); -size_t ber_write_contextual_nla_TSCredentials(wStream* s, BYTE tag, const TSCredentials_t* item); -BOOL ber_read_nla_TSCredentials(wStream* s, TSCredentials_t** pret); - -size_t ber_sizeof_nla_TSPasswordCreds_content(const TSPasswordCreds_t* item); -size_t ber_sizeof_nla_TSPasswordCreds(const TSPasswordCreds_t* item); -size_t ber_sizeof_contextual_nla_TSPasswordCreds(const TSPasswordCreds_t* item); -void nla_TSPasswordCreds_free(TSPasswordCreds_t** pitem); -size_t ber_write_nla_TSPasswordCreds(wStream* s, const TSPasswordCreds_t* item); -size_t ber_write_contextual_nla_TSPasswordCreds(wStream* s, BYTE tag, - const TSPasswordCreds_t* item); -BOOL ber_read_nla_TSPasswordCreds(wStream* s, TSPasswordCreds_t** pret); - -size_t ber_sizeof_nla_TSCspDataDetail_content(const TSCspDataDetail_t* item); -size_t ber_sizeof_nla_TSCspDataDetail(const TSCspDataDetail_t* item); -size_t ber_sizeof_contextual_nla_TSCspDataDetail(const TSCspDataDetail_t* item); -void nla_TSCspDataDetail_free(TSCspDataDetail_t** pitem); -size_t ber_write_nla_TSCspDataDetail(wStream* s, const TSCspDataDetail_t* item); -size_t ber_write_contextual_nla_TSCspDataDetail(wStream* s, BYTE tag, - const TSCspDataDetail_t* item); -BOOL ber_read_nla_TSCspDataDetail(wStream* s, TSCspDataDetail_t** pret); - -size_t ber_sizeof_nla_TSSmartCardCreds_content(const TSSmartCardCreds_t* item); -size_t ber_sizeof_nla_TSSmartCardCreds(const TSSmartCardCreds_t* item); -size_t ber_sizeof_contextual_nla_TSSmartCardCreds(const TSSmartCardCreds_t* item); -void nla_TSSmartCardCreds_free(TSSmartCardCreds_t** pitem); -size_t ber_write_nla_TSSmartCardCreds(wStream* s, const TSSmartCardCreds_t* item); -size_t ber_write_contextual_nla_TSSmartCardCreds(wStream* s, BYTE tag, - const TSSmartCardCreds_t* item); -BOOL ber_read_nla_TSSmartCardCreds(wStream* s, TSSmartCardCreds_t** pret); - -size_t ber_sizeof_nla_TSRemoteGuardPackageCred_content(const TSRemoteGuardPackageCred_t* item); -size_t ber_sizeof_nla_TSRemoteGuardPackageCred(const TSRemoteGuardPackageCred_t* item); -size_t ber_sizeof_contextual_nla_TSRemoteGuardPackageCred(const TSRemoteGuardPackageCred_t* item); -void nla_TSRemoteGuardPackageCred_free(TSRemoteGuardPackageCred_t** pitem); -size_t ber_write_nla_TSRemoteGuardPackageCred(wStream* s, const TSRemoteGuardPackageCred_t* item); -size_t ber_write_contextual_nla_TSRemoteGuardPackageCred(wStream* s, BYTE tag, - const TSRemoteGuardPackageCred_t* item); -BOOL ber_read_nla_TSRemoteGuardPackageCred(wStream* s, TSRemoteGuardPackageCred_t** pret); -size_t ber_sizeof_nla_TSRemoteGuardPackageCred_array_content(const TSRemoteGuardPackageCred_t* item, - size_t nitems); -size_t ber_sizeof_nla_TSRemoteGuardPackageCred_array(const TSRemoteGuardPackageCred_t* item, - size_t nitems); -size_t -ber_sizeof_contextual_nla_TSRemoteGuardPackageCred_array(const TSRemoteGuardPackageCred_t* item, - size_t nitems); -size_t ber_write_nla_TSRemoteGuardPackageCred_array(wStream* s, - const TSRemoteGuardPackageCred_t* item, - size_t nitems); -size_t ber_write_contextual_nla_TSRemoteGuardPackageCred_array( - wStream* s, BYTE tag, const TSRemoteGuardPackageCred_t* item, size_t nitems); -BOOL ber_read_nla_TSRemoteGuardPackageCred_array(wStream* s, TSRemoteGuardPackageCred_t** item, - size_t* nitems); - -size_t ber_sizeof_nla_TSRemoteGuardCreds_content(const TSRemoteGuardCreds_t* item); -size_t ber_sizeof_nla_TSRemoteGuardCreds(const TSRemoteGuardCreds_t* item); -size_t ber_sizeof_contextual_nla_TSRemoteGuardCreds(const TSRemoteGuardCreds_t* item); -void nla_TSRemoteGuardCreds_free(TSRemoteGuardCreds_t** pitem); -size_t ber_write_nla_TSRemoteGuardCreds(wStream* s, const TSRemoteGuardCreds_t* item); -size_t ber_write_contextual_nla_TSRemoteGuardCreds(wStream* s, BYTE tag, - const TSRemoteGuardCreds_t* item); -BOOL ber_read_nla_TSRemoteGuardCreds(wStream* s, TSRemoteGuardCreds_t** pret); - -#endif /* LIBFREERDP_CORE_CREDSSP_ASN1_H */ diff --git a/tools/asn_parser_generator.py b/tools/asn_parser_generator.py deleted file mode 100755 index bd42bef02..000000000 --- a/tools/asn_parser_generator.py +++ /dev/null @@ -1,620 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import getopt -import os.path - - -def compressTokens(tokens): - ret = [] - for t in tokens: - if t: - ret.append(t) - return ret - -class AsnField(object): - ''' - ''' - def __init__(self, name, seqIndex, optional, asnType, subType): - self.name = name - self.seqIndex = seqIndex - self.optional = optional - self.asnType = asnType - self.asnTypePointer = None - self.subType = subType - self.outputType = None - self.lenFunc = None - self.writeFunc = None - self.readFunc = None - self.cleanupFunc = None - self.freeFunc = None - self.options = [] - - if asnType.upper() in ['OCTET STRING', 'INTEGER']: - self.asnTypePointer = self.asnType - - def __str__(self): - return "{0} [{1}] {2}{3}".format(self.name, self.seqIndex, self.asnType, self.optional and " OPTIONAL" or "") - -class AsnSequence(object): - ''' - ''' - - def __init__(self, name): - self.name = name - self.fields = [] - - -FIELD_OPTION = 'fieldOption' -CHAR_TO_UNICODE = 'charInMemorySerializeToUnicode' -UNICODE = "unicode" -KNOWN_FIELD_OPTIONS = (CHAR_TO_UNICODE, UNICODE,) - -class AsnParser(object): - KNOWN_OPTIONS = (FIELD_OPTION, 'prefix', ) - - STATE_ROOT, STATE_IN_ITEM, STATE_IN_OPTIONS = range(0, 3) - - def __init__(self): - self.state = AsnParser.STATE_ROOT - self.defs = {} - self.currentItem = None - self.currentName = None - self.emitArraycode = [] - - # options - self.options = { - 'prefix': '', - 'octetStringLen': { - 'char': 'strlen(item->{fieldName})', - 'WCHAR': '_wcslen(item->{fieldName}) * 2', - CHAR_TO_UNICODE: 'strlen(item->{fieldName}) * 2', - } - } - - - def parse(self, content): - for l in content.split("\n"): - if l.startswith('#'): - continue - - tokens = compressTokens(l.lstrip().rstrip().split(' ')) - - if self.state == AsnParser.STATE_ROOT: - if not len(tokens): - continue - - if tokens[0] == "%options" and tokens[1] == "{": - self.state = AsnParser.STATE_IN_OPTIONS - continue - - if tokens[1] != "::=": - continue - - if tokens[2] != "SEQUENCE": - raise Exception("ERROR: not handling non sequence items for now") - - self.currentName = tokens[0] - self.currentItem = AsnSequence(tokens[0]) - self.state = AsnParser.STATE_IN_ITEM - - elif self.state == AsnParser.STATE_IN_ITEM: - if tokens[0] == '}': - self.defs[self.currentName] = self.currentItem - self.state = AsnParser.STATE_ROOT - continue - - optional = tokens[-1] in ["OPTIONAL", "OPTIONAL,"] - fieldIndex = int(tokens[1][1:-1]) - - if optional: - typeTokens = tokens[2:-1] - else: - typeTokens = tokens[2:] - - asnType = " ".join(typeTokens) - if asnType[-1] == ',': - asnType = asnType[0:-1] - - subType = None - if asnType.startswith("SEQUENCE OF"): - subType = typeTokens[-1] - asnType = "SEQUENCE OF" - - self.currentItem.fields.append(AsnField(tokens[0], fieldIndex, optional, asnType, subType)) - - elif self.state == AsnParser.STATE_IN_OPTIONS: - if not len(tokens) or l.startswith("#"): - continue - - if tokens[0] == "}": - self.state == AsnParser.STATE_ROOT - continue - - option = tokens[0] - if option not in AsnParser.KNOWN_OPTIONS: - raise Exception("unknown option '{0}'".format(option)) - - if option == FIELD_OPTION: - target = tokens[1] - objName, fieldName = target.split(".", 2) - - obj = self.defs.get(objName, None) - if not obj: - raise Exception("object type {0} unknown".format(objName)) - - found = False - for field in obj.fields: - if field.name == fieldName: - found = True - break - if not found: - raise Exception("object {0} has no field {1}".format(objName, fieldName)) - - if tokens[2] not in KNOWN_FIELD_OPTIONS: - raise Exception("unknown field option {0}".format(objName, tokens[2])) - - field.options.append(tokens[2]) - - elif option == "prefix": - self.options['prefix'] = tokens[1] - - - - # try to resolve custom types in fields - for typeDef in self.defs.values(): - for field in typeDef.fields: - if field.asnTypePointer is None: - field.asnTypePointer = self.defs.get(field.asnType, None) - - if field.asnType == "SEQUENCE OF": - self.emitArraycode.append(field.subType) - - # adjust AsnField fields - for typeDef in self.defs.values(): - for field in typeDef.fields: - if field.asnType == "OCTET STRING": - fieldType = field.outputType - if not fieldType: - fieldType = "WCHAR" - - if CHAR_TO_UNICODE in field.options: - fieldType = "char" - field.outputType = "char" - field.writeFunc = "ber_write_contextual_char_to_unicode_octet_string(s, {fieldIndex}, item->{fieldName})" - field.lenFunc = "ber_sizeof_contextual_octet_string(strlen(item->{fieldName}) * 2)" - field.readFunc = "ber_read_char_from_unicode_octet_string({stream}, &item->{fieldName})" - elif UNICODE in field.options: - fieldType = "WCHAR" - field.outputType = "WCHAR" - field.writeFunc = "ber_write_contextual_unicode_octet_string(s, {fieldIndex}, item->{fieldName})" - field.lenFunc = "ber_sizeof_contextual_octet_string(" + self.options['octetStringLen'][fieldType] + ")" - field.readFunc = "ber_read_unicode_octet_string({stream}, &item->{fieldName})" - else: - field.writeFunc = "ber_write_contextual_octet_string(s, {fieldIndex}, item->{fieldName}, item->{fieldName}Len)" - field.lenFunc = "ber_sizeof_contextual_octet_string(item->{fieldName}Len)" - field.readFunc = "ber_read_octet_string({stream}, &item->{fieldName}, &item->{fieldName}Len)" - field.cleanupFunc = "free(item->{fieldName});" - - - elif field.asnType == "INTEGER": - field.lenFunc = "ber_sizeof_contextual_integer(item->{fieldName})" - field.writeFunc = "ber_write_contextual_integer(s, {fieldIndex}, item->{fieldName})" - field.readFunc = "ber_read_integer({stream}, &item->{fieldName})" - field.cleanupFunc = "" - - elif field.asnType == "SEQUENCE OF": - field.lenFunc = "ber_sizeof_contextual_{prefix}{fieldSubType}_array(item->{fieldName}, item->{fieldName}Items)" - field.writeFunc = "ber_write_contextual_{prefix}{fieldSubType}_array(s, {fieldIndex}, item->{fieldName}, item->{fieldName}Items)" - field.readFunc = "ber_read_{prefix}{fieldSubType}_array({stream}, &item->{fieldName}, &item->{fieldName}Items)" - field.cleanupFunc = "" - - else: - field.lenFunc = "ber_sizeof_contextual_{prefix}{fieldType}(item->{fieldName})" - field.writeFunc = "ber_write_contextual_{prefix}{fieldType}(s, {fieldIndex}, item->{fieldName})" - field.readFunc = "ber_read_{prefix}{fieldType}({stream}, &item->{fieldName})" - field.cleanupFunc = "{prefix}{fieldType}_free(&item->{fieldName});" - - return True - - - def emitStructDefs(self): - ret = '' - for defName, seq in self.defs.items(): - h = { 'prefix': self.options['prefix'], 'defName': defName } - - ret += 'typedef struct {\n' - for field in seq.fields: - if field.asnType == "INTEGER": - ret += "\tUINT32 {fieldName};\n".format(fieldName=field.name) - - elif field.asnType == "OCTET STRING": - fieldType = field.outputType - if CHAR_TO_UNICODE in field.options: - fieldType = 'char' - elif fieldType == 'WCHAR': - pass - else: - fieldType = 'BYTE' - ret += "\tsize_t {fieldName}Len;\n".format(fieldName=field.name, fieldType=fieldType) - - ret += "\t{fieldType}* {fieldName};\n".format(fieldName=field.name, fieldType=fieldType) - - elif field.asnType == "SEQUENCE OF": - ret += "\tsize_t {fieldName}Items;\n".format(fieldName=field.name, fieldType=field.subType) - ret += "\t{fieldType}_t* {fieldName};\n".format(fieldName=field.name, fieldType=field.subType) - else: - ret += "\t{typeName}_t* {fieldName};\n".format(fieldName=field.name, typeName=field.asnType) - ret += '}} {defName}_t;\n\n'.format(**h) - - return ret - - - def emitPrototypes(self): - ret = '' - for defName, seq in self.defs.items(): - h = { 'prefix': self.options['prefix'], 'defName': defName } - - ret += "size_t ber_sizeof_{prefix}{defName}_content(const {defName}_t* item);\n".format(**h) - ret += "size_t ber_sizeof_{prefix}{defName}(const {defName}_t* item);\n".format(**h) - ret += "size_t ber_sizeof_contextual_{prefix}{defName}(const {defName}_t* item);\n".format(**h) - ret += "void {prefix}{defName}_free({defName}_t** pitem);\n".format(**h) - ret += "size_t ber_write_{prefix}{defName}(wStream *s, const {defName}_t* item);\n".format(**h) - ret += "size_t ber_write_contextual_{prefix}{defName}(wStream *s, BYTE tag, const {defName}_t* item);\n".format(**h) - ret += 'BOOL ber_read_{prefix}{defName}(wStream *s, {defName}_t** pret);\n'.format(**h) - - if defName in self.emitArraycode: - ret += "size_t ber_sizeof_{prefix}{defName}_array_content(const {defName}_t* item, size_t nitems);\n".format(**h) - ret += "size_t ber_sizeof_{prefix}{defName}_array(const {defName}_t* item, size_t nitems);\n".format(**h) - ret += "size_t ber_sizeof_contextual_{prefix}{defName}_array(const {defName}_t* item, size_t nitems);\n".format(**h) - ret += "size_t ber_write_{prefix}{defName}_array(wStream* s, const {defName}_t* item, size_t nitems);\n".format(**h) - ret += "size_t ber_write_contextual_{prefix}{defName}_array(wStream* s, BYTE tag, const {defName}_t* item, size_t nitems);\n".format(**h) - ret += "BOOL ber_read_{prefix}{defName}_array(wStream* s, {defName}_t** item, size_t* nitems);\n".format(**h) - ret += '\n' - - return ret - - - def emitImpl(self): - ret = '' - for defName, seq in self.defs.items(): - h = { 'prefix': self.options['prefix'], 'defName': defName } - - # ================= ber_sizeof_ ========================================= - ret += "size_t ber_sizeof_{prefix}{defName}_content(const {defName}_t* item) {{\n".format(**h) - ret += "\tsize_t ret = 0;\n\n" - - for field in seq.fields: - h2 = {'fieldName': field.name, 'fieldIndex': field.seqIndex, 'fieldType':field.asnType, - 'fieldSubType': field.subType } - shift = '\t' - - ret += shift + "/* [{fieldIndex}] {fieldName} ({fieldType}){optional}*/\n".format(**h2, optional=field.optional and " OPTIONAL" or "") - if field.optional: - ret += shift + "if (item->{fieldName}) {{\n".format(fieldName=field.name) - shift = '\t\t' - - ret += shift + "ret += " + field.lenFunc.format(**h2, **h) + ";\n" - - if field.optional: - ret += "\t}\n" - ret += '\n' - - ret += '\treturn ret;\n' - ret += '}\n\n' - - ret += '''size_t ber_sizeof_{prefix}{defName}(const {defName}_t* item) -{{ - size_t ret = ber_sizeof_{prefix}{defName}_content(item); - return ber_sizeof_sequence(ret); -}} -'''.format(**h) - - ret += "size_t ber_sizeof_contextual_{prefix}{defName}(const {defName}_t* item) {{\n".format(**h) - ret += "\tsize_t innerSz = ber_sizeof_{prefix}{defName}(item);\n".format(**h) - ret += "\treturn ber_sizeof_contextual_tag(innerSz) + innerSz;\n" - ret += "}\n\n" - - - # ================= free_ ========================================= - ret += "void {prefix}{defName}_free({defName}_t** pitem) {{\n".format(**h) - ret += "\t{defName}_t* item;\n\n".format(**h) - ret += "\tWINPR_ASSERT(pitem);\n" - ret += "\titem = *pitem;\n" - ret += "\tif (!item)\n" - ret += "\t\treturn;\n\n" - - for field in seq.fields: - if field.cleanupFunc: - h2 = { 'fieldName': field.name, 'fieldIndex': field.seqIndex, 'fieldType':field.asnType } - ret += "\t" + field.cleanupFunc.format(**h2, **h) + "\n" - ret += "\tfree(item);\n" - ret += "\t*pitem = NULL;\n" - ret += "}\n\n" - - # ================= ber_write_ ========================================= - ret += '''size_t ber_write_{prefix}{defName}(wStream *s, const {defName}_t* item) -{{ - size_t content_size = ber_sizeof_{prefix}{defName}_content(item); - size_t ret = 0; - - ret = ber_write_sequence_tag(s, content_size); -'''.format(**h) - - for field in seq.fields: - h2 = { 'fieldName': field.name, 'fieldIndex': field.seqIndex, 'fieldType':field.asnType, - 'fieldSubType': field.subType } - shift = " " - - ret += shift + "/* [{fieldIndex}] {fieldName} ({fieldType}){optional} */\n".format(**h2, optional=field.optional and " OPTIONAL" or "") - if field.optional: - ret += shift + "if (item->{fieldName}) {{\n" .format(**h2) - shift += ' ' - - ret += shift + "if (!" + field.writeFunc.format(**h2, **h) + ")\n" - ret += shift + ' return 0;\n' - - if field.optional: - ret += " }\n" - ret += "\n" - - ret += ' return ret + content_size;\n' - ret += '}\n\n' - - ret += '''size_t ber_write_contextual_{prefix}{defName}(wStream *s, BYTE tag, const {defName}_t* item) -{{ - size_t ret; - size_t inner = ber_sizeof_{prefix}{defName}(item); - - ret = ber_write_contextual_tag(s, tag, inner, TRUE); - ber_write_{prefix}{defName}(s, item); - return ret + inner; -}} - -'''.format(**h) - - - # ================= ber_read_ ========================================= - ret += '''BOOL ber_read_{prefix}{defName}(wStream *s, {defName}_t** pret) {{ - wStream seqstream; - size_t seqLength; - size_t inner_size; - wStream fieldStream; - {defName}_t* item; - BOOL ret; - - if (!ber_read_sequence_tag(s, &seqLength) || !Stream_CheckAndLogRequiredLength(TAG,s, seqLength)) - return FALSE; - Stream_StaticInit(&seqstream, Stream_Pointer(s), seqLength); - - item = calloc(1, sizeof(*item)); - if (!item) - return FALSE; - -'''.format(**h) - shiftLevel = 1 - shift = ' ' * 4 * shiftLevel - - cleanupLabels = [] - for field in seq.fields: - h2 = { 'fieldName': field.name, 'fieldIndex': field.seqIndex, 'fieldType':field.asnType, - 'stream': '&fieldStream', 'fieldSubType': field.subType } - - cleanupLabels.insert(0, "\t" + field.cleanupFunc.format(**h2, **h)) - cleanupLabels.insert(1, "out_fail_{fieldName}:".format(**h2, **h)) - - ret += shift + "/* [{fieldIndex}] {fieldName} ({fieldType}){optional} */\n".format(**h2, optional=field.optional and " OPTIONAL" or "") - ret += shift + 'ret = ber_read_contextual_tag(&seqstream, {fieldIndex}, &inner_size, TRUE);\n'.format(**h2) - - if not field.optional: - ret += shift + "if (!ret) \n" - ret += shift + '\tgoto out_fail_{fieldName};\n'.format(**h2) - else: - ret += shift + "if (ret) { \n" - shiftLevel += 1 - shift = ' ' * 4 * shiftLevel - - ret += shift + "Stream_StaticInit(&fieldStream, Stream_Pointer(&seqstream), inner_size);\n" - ret += shift + "Stream_Seek(&seqstream, inner_size);\n" - ret += '\n' - ret += shift + "ret = " + field.readFunc.format(**h2, **h) + ";\n" - ret += shift + "if (!ret)\n" - ret += shift + '\tgoto out_fail_{fieldName};\n'.format(**h2) - - if field.optional: - shiftLevel -= 1 - shift = ' ' * 4 * shiftLevel - ret += shift + '}' - - ret += '\n' - - ret += shift + "*pret = item;\n" - ret += shift + "return TRUE;\n" - ret += '\n' - - cleanupLabels = cleanupLabels[1:] - ret += "\n".join(cleanupLabels) - - ret += '\n' - ret += shift + 'free(item);\n' - ret += shift + 'return FALSE;\n' - ret += '}\n\n' - - # ====================== code for handling arrays ==================================== - if defName in self.emitArraycode: - ret += '''size_t ber_sizeof_{prefix}{defName}_array_content(const {defName}_t* item, size_t nitems) -{{ - size_t i, ret = 0; - for (i = 0; i < nitems; i++, item++) - ret += ber_sizeof_{prefix}{defName}(item); - - return ber_sizeof_sequence(ret); -}} - -size_t ber_sizeof_{prefix}{defName}_array(const {defName}_t* item, size_t nitems) -{{ - return ber_sizeof_sequence( ber_sizeof_{prefix}{defName}_array_content(item, nitems) ); -}} - -size_t ber_sizeof_contextual_{prefix}{defName}_array(const {defName}_t* item, size_t nitems) -{{ - size_t inner = ber_sizeof_{prefix}{defName}_array(item, nitems); - return ber_sizeof_contextual_tag(inner) + inner; -}} - -size_t ber_write_{prefix}{defName}_array(wStream* s, const {defName}_t* item, size_t nitems) -{{ - size_t i, r, ret; - size_t inner_len = ber_sizeof_{prefix}{defName}_array_content(item, nitems); - - ret = ber_write_sequence_tag(s, inner_len); - - for (i = 0; i < nitems; i++, item++) - {{ - r = ber_write_{prefix}{defName}(s, item); - if (!r) - return 0; - ret += r; - }} - - return ret; -}} - -size_t ber_write_contextual_{prefix}{defName}_array(wStream* s, BYTE tag, const {defName}_t* item, size_t nitems) -{{ - size_t ret; - size_t inner = ber_sizeof_{prefix}{defName}_array(item, nitems); - - ret = ber_write_contextual_tag(s, tag, inner, TRUE); - ber_write_{prefix}{defName}_array(s, item, nitems); - return ret + inner; -}} - - - -BOOL ber_read_{prefix}{defName}_array(wStream* s, {defName}_t** pitems, size_t* nitems) -{{ - size_t subLen; - wStream subStream; - {defName}_t* retItems = NULL; - size_t ret = 0; - - if (!ber_read_sequence_tag(s, &subLen) || !Stream_CheckAndLogRequiredLength(TAG,s, subLen)) - return FALSE; - - Stream_StaticInit(&subStream, Stream_Pointer(s), subLen); - while (Stream_GetRemainingLength(&subStream)) - {{ - {defName}_t *item; - {defName}_t* tmpRet; - - if (!ber_read_{prefix}{defName}(&subStream, &item)) - {{ - free(retItems); - return FALSE; - }} - - tmpRet = realloc(retItems, (ret+1) * sizeof({defName}_t)); - if (!tmpRet) - {{ - free(retItems); - return FALSE; - }} - retItems = tmpRet; - - memcpy(&retItems[ret], item, sizeof(*item)); - free(item); - ret++; - }} - - *pitems = retItems; - *nitems = ret; - return TRUE; -}} - -'''.format(**h) - - - return ret - - -if __name__ == '__main__': - opts, extraArgs = getopt.getopt(sys.argv[1:], "hi:o:t:", ['input=', 'output=', 'output-kind=', 'help']) - - - ALLOWED_OUTPUTS = ('headers', 'impls',) - - inputStream = sys.stdin - outputStream = sys.stdout - outputs = ALLOWED_OUTPUTS - inputHeaderName = "ASN1_HEADER_H" - headerName = "tscredentials" - - for option, value in opts: - if option in ('-h', '--help',): - print("usage: {0} [-i|--input]= [-o|--output]=") - print("\t[-i|--input] : input file") - print("\t[-o|--output] : output file") - print("\t[-t|--output-kind] [header|impl]: the kind of output") - elif option in ('-o', '--output',): - outputStream = open(value, "w") - - # libfreerdp/core/credssp.c => credssp.h - headerName = os.path.splitext(os.path.basename(value))[0] - elif option in ('-i', '--input',): - inputStream = open(value, "r") - - # libfreerdp/core/credssp.asn1 => LIBFREERDP_CORE_CREDSSP_ASN1_H - inputHeaderName = os.path.normpath(value).replace(os.path.sep, '_').replace('.', '_').upper() + '_H' - - elif option in ('-t', '--output-kind',): - if value not in ALLOWED_OUTPUTS: - raise Exception("unknown output kind '{0}'".format(value)) - outputs = value - else: - raise Exception("unknown option {0}".format(option)) - - input = inputStream.read() - - parser = AsnParser() - parser.parse(input) - - h = {'programName': os.path.basename(sys.argv[0]), 'cmdLine': ' '.join(sys.argv), 'programPath': sys.argv[0], - 'inputHeaderName': inputHeaderName, 'headerName': headerName } - - outputStream.write('''/* ============================================================================================================ - * this file has been generated using - * {cmdLine} - * - * /!\\ If you want to modify this file you'd probably better change {programName} or the corresponding ASN1 - * definition file - * - * ============================================================================================================ - */ -'''.format(**h)) - - if outputs == 'headers': - outputStream.write('''#ifndef {inputHeaderName} -#define {inputHeaderName} - -#include - -'''.format(**h)) - outputStream.write(parser.emitStructDefs()) - outputStream.write(parser.emitPrototypes()) - outputStream.write('#endif /* {inputHeaderName} */\n'.format(**h)) - - elif outputs == "impls": - outputStream.write(''' -#include -#include - -#include "{headerName}.h" - -#include - -#define TAG FREERDP_TAG("core.{headerName}") - -'''.format(**h)) - outputStream.write(parser.emitImpl()) - diff --git a/winpr/include/winpr/asn1.h b/winpr/include/winpr/asn1.h index 084796b2f..5b07e339c 100644 --- a/winpr/include/winpr/asn1.h +++ b/winpr/include/winpr/asn1.h @@ -146,6 +146,10 @@ extern "C" WINPR_API size_t WinPrAsn1DecReadContextualOID(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error, WinPrAsn1_OID* target, BOOL allocate); + WINPR_API size_t WinPrAsn1DecReadContextualOctetString(WinPrAsn1Decoder* dec, + WinPrAsn1_tagId tagId, BOOL* error, + WinPrAsn1_OctetString* target, + BOOL allocate); WINPR_API size_t WinPrAsn1DecReadContextualSequence(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error, WinPrAsn1Decoder* target); diff --git a/winpr/libwinpr/utils/asn1/asn1.c b/winpr/libwinpr/utils/asn1/asn1.c index 009692bdf..28bd80d2c 100644 --- a/winpr/libwinpr/utils/asn1/asn1.c +++ b/winpr/libwinpr/utils/asn1/asn1.c @@ -1390,6 +1390,32 @@ size_t WinPrAsn1DecReadContextualOID(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagI return ret; } +size_t WinPrAsn1DecReadContextualOctetString(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, + BOOL* error, WinPrAsn1_OctetString* target, + BOOL allocate) +{ + size_t ret, ret2; + WinPrAsn1_tag ftag; + WinPrAsn1Decoder content; + + WINPR_ASSERT(error); + + ret = WinPrAsn1DecPeekContextualTag(dec, &ftag, &content); + if (!ret || ftag != tagId) + return 0; + + ret2 = WinPrAsn1DecReadOctetString(&content, target, allocate); + if (!ret2) + { + *error = TRUE; + return 0; + } + + *error = FALSE; + Stream_Seek(&dec->source, ret); + return ret; +} + size_t WinPrAsn1DecReadContextualSequence(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error, WinPrAsn1Decoder* target) {