diff --git a/include/freerdp/crypto/ber.h b/include/freerdp/crypto/ber.h index e6035c8df..072517c41 100644 --- a/include/freerdp/crypto/ber.h +++ b/include/freerdp/crypto/ber.h @@ -74,16 +74,30 @@ extern "C" FREERDP_API size_t ber_sizeof_sequence(size_t length); FREERDP_API size_t ber_sizeof_sequence_tag(size_t length); FREERDP_API BOOL ber_read_bit_string(wStream* s, size_t* length, BYTE* padding); - FREERDP_API size_t ber_write_octet_string(wStream* s, const BYTE* oct_str, size_t length); + FREERDP_API BOOL ber_read_octet_string_tag(wStream* s, size_t* length); + FREERDP_API BOOL ber_read_octet_string(wStream* s, BYTE** content, size_t* length); FREERDP_API size_t ber_write_octet_string_tag(wStream* s, size_t length); FREERDP_API size_t ber_sizeof_octet_string(size_t length); + FREERDP_API size_t ber_sizeof_contextual_octet_string(size_t length); + FREERDP_API size_t ber_write_char_to_unicode_octet_string(wStream* s, const char* str); + FREERDP_API size_t ber_write_contextual_char_to_unicode_octet_string(wStream* s, BYTE tag, + const char* oct_str); + FREERDP_API size_t ber_write_octet_string(wStream* s, const BYTE* oct_str, size_t length); + FREERDP_API BOOL ber_read_char_from_unicode_octet_string(wStream* s, char** str); + FREERDP_API BOOL ber_read_unicode_octet_string(wStream* s, LPWSTR* str); + FREERDP_API size_t ber_write_contextual_octet_string(wStream* s, BYTE tag, const BYTE* oct_str, + size_t length); + FREERDP_API size_t ber_write_contextual_unicode_octet_string(wStream* s, BYTE tag, LPWSTR str); + FREERDP_API BOOL ber_read_BOOL(wStream* s, BOOL* value); FREERDP_API void ber_write_BOOL(wStream* s, BOOL value); FREERDP_API BOOL ber_read_integer(wStream* s, UINT32* value); FREERDP_API size_t ber_write_integer(wStream* s, UINT32 value); + FREERDP_API size_t ber_write_contextual_integer(wStream* s, BYTE tag, UINT32 value); FREERDP_API BOOL ber_read_integer_length(wStream* s, size_t* length); FREERDP_API size_t ber_sizeof_integer(UINT32 value); + FREERDP_API size_t ber_sizeof_contextual_integer(UINT32 value); #ifdef __cplusplus } diff --git a/libfreerdp/core/credssp.asn1 b/libfreerdp/core/credssp.asn1 new file mode 100644 index 000000000..084c8cc3a --- /dev/null +++ b/libfreerdp/core/credssp.asn1 @@ -0,0 +1,48 @@ +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/tscredentials.c b/libfreerdp/core/tscredentials.c new file mode 100644 index 000000000..c871c72b2 --- /dev/null +++ b/libfreerdp/core/tscredentials.c @@ -0,0 +1,914 @@ +/* ============================================================================================================ + * 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" + +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_GetRemainingLength(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_GetRemainingLength(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_GetRemainingLength(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_GetRemainingLength(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_GetRemainingLength(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_GetRemainingLength(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; + } + + 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_GetRemainingLength(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 new file mode 100644 index 000000000..72e503548 --- /dev/null +++ b/libfreerdp/core/tscredentials.h @@ -0,0 +1,112 @@ +/* ============================================================================================================ + * 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/libfreerdp/crypto/ber.c b/libfreerdp/crypto/ber.c index 33813f907..1093115e7 100644 --- a/libfreerdp/crypto/ber.c +++ b/libfreerdp/crypto/ber.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -322,11 +323,128 @@ size_t ber_write_octet_string(wStream* s, const BYTE* oct_str, size_t length) return size; } +size_t ber_write_contextual_octet_string(wStream* s, BYTE tag, const BYTE* oct_str, size_t length) +{ + size_t inner = ber_sizeof_octet_string(length); + size_t ret, r; + + ret = ber_write_contextual_tag(s, tag, inner, TRUE); + if (!ret) + return 0; + + r = ber_write_octet_string(s, oct_str, length); + if (!r) + return 0; + return ret + r; +} + +size_t ber_write_char_to_unicode_octet_string(wStream* s, const char* str) +{ + size_t size = 0; + size_t length = strlen(str) + 1; + size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE); + size += ber_write_length(s, length * 2); + MultiByteToWideChar(CP_UTF8, 0, str, length, (LPWSTR)Stream_Pointer(s), length * 2); + Stream_Seek(s, length * 2); + return size + length * 2; +} + +size_t ber_write_contextual_unicode_octet_string(wStream* s, BYTE tag, LPWSTR str) +{ + size_t len = _wcslen(str) * 2; + size_t inner_len = ber_sizeof_octet_string(len); + size_t ret; + + if (!Stream_EnsureRemainingCapacity(s, inner_len + 5)) + return 0; + + ret = ber_write_contextual_tag(s, tag, inner_len, TRUE); + return ret + ber_write_octet_string(s, (const BYTE*)str, len); +} + +size_t ber_write_contextual_char_to_unicode_octet_string(wStream* s, BYTE tag, const char* str) +{ + size_t ret; + size_t len = strlen(str) * 2; + size_t inner_len = ber_sizeof_octet_string(len); + + if (!Stream_EnsureRemainingCapacity(s, inner_len + 10)) + return 0; + + ret = ber_write_contextual_tag(s, tag, inner_len, TRUE); + ret += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE); + ret += ber_write_length(s, len); + MultiByteToWideChar(CP_UTF8, 0, str, len, (LPWSTR)Stream_Pointer(s), len); + Stream_Seek(s, len); + + return ret + len; +} + +BOOL ber_read_unicode_octet_string(wStream* s, LPWSTR* str) +{ + LPWSTR ret = NULL; + size_t length; + + if (!ber_read_octet_string_tag(s, &length)) + return FALSE; + + if (Stream_GetRemainingLength(s) < length) + return FALSE; + + ret = calloc(1, length + 2); + if (!ret) + return FALSE; + + memcpy(ret, Stream_Pointer(s), length); + ret[length / 2] = 0; + Stream_Seek(s, length); + *str = ret; + return TRUE; +} + +BOOL ber_read_char_from_unicode_octet_string(wStream* s, char** str) +{ + size_t length, outLen; + char* ptr; + + if (!ber_read_octet_string_tag(s, &length)) + return FALSE; + + if (Stream_GetRemainingLength(s) < length) + return FALSE; + + outLen = (length / 2) + 1; + ptr = malloc(outLen); + if (!ptr) + return FALSE; + ptr[outLen - 1] = 0; + + WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)Stream_Pointer(s), length, ptr, outLen, NULL, FALSE); + Stream_Seek(s, length); + *str = ptr; + return TRUE; +} + BOOL ber_read_octet_string_tag(wStream* s, size_t* length) { return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length); } +BOOL ber_read_octet_string(wStream* s, BYTE** content, size_t* length) +{ + BYTE* ret; + if (!ber_read_octet_string_tag(s, length) || Stream_GetRemainingLength(s) < *length) + return FALSE; + + ret = malloc(*length); + if (!ret) + return FALSE; + + Stream_Read(s, ret, *length); + *content = ret; + return TRUE; +} + size_t ber_write_octet_string_tag(wStream* s, size_t length) { ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE); @@ -339,6 +457,12 @@ size_t ber_sizeof_octet_string(size_t length) return 1 + _ber_sizeof_length(length) + length; } +size_t ber_sizeof_contextual_octet_string(size_t length) +{ + size_t ret = ber_sizeof_octet_string(length); + return ber_sizeof_contextual_tag(ret) + ret; +} + /** * Read a BER BOOLEAN * @param s @@ -470,6 +594,17 @@ size_t ber_write_integer(wStream* s, UINT32 value) return 0; } +size_t ber_write_contextual_integer(wStream* s, BYTE tag, UINT32 value) +{ + size_t len = ber_sizeof_integer(value); + if (!Stream_EnsureRemainingCapacity(s, len + 5)) + return 0; + + len += ber_write_contextual_tag(s, tag, len, TRUE); + ber_write_integer(s, value); + return len; +} + size_t ber_sizeof_integer(UINT32 value) { if (value < 0x80) @@ -497,6 +632,12 @@ size_t ber_sizeof_integer(UINT32 value) return 0; } +size_t ber_sizeof_contextual_integer(UINT32 value) +{ + size_t intSize = ber_sizeof_integer(value); + return ber_sizeof_contextual_tag(intSize) + intSize; +} + BOOL ber_read_integer_length(wStream* s, size_t* length) { return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length); diff --git a/tools/asn_parser_generator.py b/tools/asn_parser_generator.py new file mode 100644 index 000000000..fe882b1fa --- /dev/null +++ b/tools/asn_parser_generator.py @@ -0,0 +1,613 @@ +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_GetRemainingLength(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_GetRemainingLength(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; + }} + + 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" + headerFileName = "tscredentials.h" + + 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 + headerFileName = '.'.join( [os.path.splitext(os.path.basename(value))[0], 'h' ]) + 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, 'headerFileName': headerFileName } + + 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 "{headerFileName}" + +'''.format(**h)) + outputStream.write(parser.emitImpl()) +