From 2a13a7bc16a41fdef85be43e44c7f7f20000d06f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 4 Jul 2011 17:05:58 -0400 Subject: [PATCH] libfreerdp-core: PER and BER encoding, along with unit tests --- cunit/CMakeLists.txt | 4 ++ cunit/test_ber.c | 95 ++++++++++++++++++++++++++++++++++++++++++ cunit/test_ber.h | 28 +++++++++++++ cunit/test_freerdp.c | 49 +++++++++++++++++++++- cunit/test_freerdp.h | 10 ++++- cunit/test_per.c | 63 ++++++++++++++++++++++++++++ cunit/test_per.h | 27 ++++++++++++ include/freerdp/utils/stream.h | 2 + libfreerdp-core/CMakeLists.txt | 4 ++ libfreerdp-core/ber.c | 18 +++++--- libfreerdp-core/gcc.c | 54 ++++++++++++++++++++++++ libfreerdp-core/gcc.h | 29 +++++++++++++ libfreerdp-core/per.c | 41 ++++++++++++++++++ libfreerdp-core/per.h | 30 +++++++++++++ 14 files changed, 447 insertions(+), 7 deletions(-) create mode 100644 cunit/test_ber.c create mode 100644 cunit/test_ber.h create mode 100644 cunit/test_per.c create mode 100644 cunit/test_per.h create mode 100644 libfreerdp-core/gcc.c create mode 100644 libfreerdp-core/gcc.h create mode 100644 libfreerdp-core/per.c create mode 100644 libfreerdp-core/per.h diff --git a/cunit/CMakeLists.txt b/cunit/CMakeLists.txt index 3c1ef1a..769199c 100644 --- a/cunit/CMakeLists.txt +++ b/cunit/CMakeLists.txt @@ -23,6 +23,10 @@ include_directories(../libfreerdp-core) include_directories(../libfreerdp-gdi) add_executable(test_freerdp + test_per.c + test_per.h + test_ber.c + test_ber.h test_color.c test_color.h test_libgdi.c diff --git a/cunit/test_ber.c b/cunit/test_ber.c new file mode 100644 index 0000000..719f79f --- /dev/null +++ b/cunit/test_ber.c @@ -0,0 +1,95 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Basic Encoding Rules (BER) Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "test_ber.h" + +int init_ber_suite(void) +{ + return 0; +} + +int clean_ber_suite(void) +{ + return 0; +} + +int add_ber_suite(void) +{ + add_test_suite(ber); + + add_test_function(ber_write_length); + add_test_function(ber_write_universal_tag); + add_test_function(ber_write_application_tag); + + return 0; +} + +uint8 ber_length_expected_1[1] = "\x40"; /* 64 */ +uint8 ber_length_expected_2[3] = "\x82\x01\x94"; /* 404 */ + +void test_ber_write_length(void) +{ + STREAM *s1, *s2; + + s1 = stream_new(sizeof(ber_length_expected_1)); + s2 = stream_new(sizeof(ber_length_expected_2)); + + ber_write_length(s1, 64); + ASSERT_STREAM(s1, (uint8*) ber_length_expected_1, sizeof(ber_length_expected_1)); + + ber_write_length(s2, 404); + ASSERT_STREAM(s2, (uint8*) ber_length_expected_2, sizeof(ber_length_expected_2)); + + stream_free(s1); + stream_free(s2); +} + +/* BOOLEAN, length 1, without value */ +uint8 ber_universal_tag_expected[2] = "\x01\x01"; + +void test_ber_write_universal_tag(void) +{ + STREAM* s; + + s = stream_new(sizeof(ber_universal_tag_expected)); + ber_write_universal_tag(s, 1, 1); + + ASSERT_STREAM(s, (uint8*) ber_universal_tag_expected, sizeof(ber_universal_tag_expected)); + + stream_free(s); +} + +/* T.125 MCS Application 101 (Connect-Initial), length 404 */ +uint8 ber_application_tag_expected[5] = "\x7F\x65\x82\x01\x94"; + +void test_ber_write_application_tag(void) +{ + STREAM* s; + + s = stream_new(sizeof(ber_application_tag_expected)); + ber_write_application_tag(s, 101, 404); + + ASSERT_STREAM(s, (uint8*) ber_application_tag_expected, sizeof(ber_application_tag_expected)); + + stream_free(s); +} diff --git a/cunit/test_ber.h b/cunit/test_ber.h new file mode 100644 index 0000000..0cc9228 --- /dev/null +++ b/cunit/test_ber.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Basic Encoding Rules (BER) Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "test_freerdp.h" + +int init_ber_suite(void); +int clean_ber_suite(void); +int add_ber_suite(void); + +void test_ber_write_length(void); +void test_ber_write_universal_tag(void); +void test_ber_write_application_tag(void); diff --git a/cunit/test_freerdp.c b/cunit/test_freerdp.c index 23ba54c..0e22a01 100644 --- a/cunit/test_freerdp.c +++ b/cunit/test_freerdp.c @@ -17,8 +17,10 @@ * limitations under the License. */ -#include "CUnit/Basic.h" +#include +#include "test_per.h" +#include "test_ber.h" #include "test_color.h" #include "test_libgdi.h" #include "test_stream.h" @@ -51,6 +53,41 @@ void dump_data(unsigned char * p, int len, int width, char* name) printf("\n"); } +void assert_stream(STREAM* s, uint8* data, int length, const char* func, int line) +{ + int i; + char* str; + int actual_length; + uint8* actual_data; + + actual_length = stream_get_length(s); + + if (actual_length != length) + { + printf("\n %s (%d): length mismatch, actual:%d, expected:%d", func, line, actual_length, length); + CU_FAIL("assert_stream, length mismatch"); + return; + } + + actual_data = s->buffer; + for (i = 0; i < length; i++) + { + if (actual_data[i] != data[i]) + { + printf("\n %s (%d): buffer mismatch:\n", func, line); + + printf("\nActual:\n"); + freerdp_hexdump(actual_data, length); + + printf("Expected:\n"); + freerdp_hexdump(data, length); + + CU_FAIL("assert_stream, buffer mismatch"); + return; + } + } +} + int main(int argc, char* argv[]) { int index = 1; @@ -61,6 +98,8 @@ int main(int argc, char* argv[]) if (argc < *pindex + 1) { + add_per_suite(); + add_ber_suite(); add_color_suite(); add_libgdi_suite(); add_stream_suite(); @@ -86,6 +125,14 @@ int main(int argc, char* argv[]) { add_transport_suite(); } + else if (strcmp("per", argv[*pindex]) == 0) + { + add_per_suite(); + } + else if (strcmp("ber", argv[*pindex]) == 0) + { + add_ber_suite(); + } *pindex = *pindex + 1; } diff --git a/cunit/test_freerdp.h b/cunit/test_freerdp.h index ca8e029..f1068f4 100644 --- a/cunit/test_freerdp.h +++ b/cunit/test_freerdp.h @@ -18,7 +18,12 @@ */ #include -#include "CUnit/Basic.h" +#include +#include +#include +#include +#include +#include #define add_test_suite(name) \ CU_pSuite pSuite; \ @@ -33,3 +38,6 @@ } void dump_data(unsigned char * p, int len, int width, char* name); +void assert_stream(STREAM* s, uint8* data, int length, const char* func, int line); + +#define ASSERT_STREAM(_s, _data, _length) assert_stream(_s, _data, _length, __FUNCTION__, __LINE__) diff --git a/cunit/test_per.c b/cunit/test_per.c new file mode 100644 index 0000000..ad8392b --- /dev/null +++ b/cunit/test_per.c @@ -0,0 +1,63 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Packed Encoding Rules (PER) Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "test_per.h" + +int init_per_suite(void) +{ + return 0; +} + +int clean_per_suite(void) +{ + return 0; +} + +int add_per_suite(void) +{ + add_test_suite(per); + + add_test_function(per_write_length); + add_test_function(per_write_object_identifier); + + return 0; +} + +uint8 per_length_expected[2] = "\x81\x2A"; + +void test_per_write_length(void) +{ + STREAM* s = stream_new(2); + per_write_length(s, 298); + ASSERT_STREAM(s, (uint8*) per_length_expected, sizeof(per_length_expected)); +} + +uint8 per_oid[6] = { 0, 0, 20, 124, 0, 1 }; +uint8 per_oid_expected[6] = "\x05\x00\x14\x7C\x00\x01"; + +void test_per_write_object_identifier(void) +{ + STREAM* s = stream_new(6); + per_write_object_identifier(s, per_oid); + ASSERT_STREAM(s, (uint8*) per_oid_expected, sizeof(per_oid_expected)); +} diff --git a/cunit/test_per.h b/cunit/test_per.h new file mode 100644 index 0000000..30f8d6f --- /dev/null +++ b/cunit/test_per.h @@ -0,0 +1,27 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Packed Encoding Rules (PER) Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "test_freerdp.h" + +int init_per_suite(void); +int clean_per_suite(void); +int add_per_suite(void); + +void test_per_write_length(void); +void test_per_write_object_identifier(void); diff --git a/include/freerdp/utils/stream.h b/include/freerdp/utils/stream.h index e8f06c8..d4a5617 100644 --- a/include/freerdp/utils/stream.h +++ b/include/freerdp/utils/stream.h @@ -45,10 +45,12 @@ stream_extend(STREAM * stream); #define stream_get_pos(_s) (_s->ptr - _s->buffer) #define stream_set_pos(_s,_m) _s->ptr = _s->buffer + (_m) #define stream_seek(_s,_offset) _s->ptr += (_offset) +#define stream_rewind(_s,_offset) _s->ptr -= (_offset) #define stream_get_mark(_s,_mark) _mark = _s->ptr #define stream_set_mark(_s,_mark) _s->ptr = _mark #define stream_get_head(_s) _s->buffer #define stream_get_tail(_s) _s->ptr +#define stream_get_length(_s) (_s->ptr - _s->buffer) #define stream_read_uint8(_s, _v) do { _v = *_s->ptr++; } while (0) #define stream_read_uint16(_s, _v) do { _v = \ diff --git a/libfreerdp-core/CMakeLists.txt b/libfreerdp-core/CMakeLists.txt index e6bb1a2..9209a74 100644 --- a/libfreerdp-core/CMakeLists.txt +++ b/libfreerdp-core/CMakeLists.txt @@ -22,6 +22,8 @@ add_definitions(-DEXT_PATH="/usr/lib/freerdp/extensions") set(LIBFREERDP_CORE_SRCS ber.c ber.h + gcc.c + gcc.h mcs.c mcs.h nego.c @@ -30,6 +32,8 @@ set(LIBFREERDP_CORE_SRCS # credssp.h # ntlmssp.c # ntlmssp.h + per.c + per.h tcp.c tcp.h tls.c diff --git a/libfreerdp-core/ber.c b/libfreerdp-core/ber.c index cc5c756..ac1bae7 100644 --- a/libfreerdp-core/ber.c +++ b/libfreerdp-core/ber.c @@ -22,7 +22,7 @@ void ber_write_length(STREAM* s, int length) { - if (length > 0xFF) + if (length > 0x7F) { stream_write_uint8(s, 0x82); stream_write_uint16_be(s, length); @@ -36,14 +36,22 @@ ber_write_length(STREAM* s, int length) void ber_write_universal_tag(STREAM* s, uint8 tag, int length) { - stream_write_uint8(s, (BER_CLASS_UNIV | BER_PRIMITIVE) & (BER_TAG_MASK & tag)); + stream_write_uint8(s, (BER_CLASS_UNIV | BER_PRIMITIVE) | (BER_TAG_MASK & tag)); ber_write_length(s, length); } void ber_write_application_tag(STREAM* s, uint8 tag, int length) { - stream_write_uint8(s, (BER_CLASS_APPL | BER_CONSTRUCT) & BER_TAG_MASK); - stream_write_uint8(s, tag); - ber_write_length(s, length); + if (tag > 30) + { + stream_write_uint8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK); + stream_write_uint8(s, tag); + ber_write_length(s, length); + } + else + { + stream_write_uint8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag)); + ber_write_length(s, length); + } } diff --git a/libfreerdp-core/gcc.c b/libfreerdp-core/gcc.c new file mode 100644 index 0000000..3a117bc --- /dev/null +++ b/libfreerdp-core/gcc.c @@ -0,0 +1,54 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * T.124 Generic Conference Control (GCC) + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gcc.h" + +/** + * T.124 GCC is defined in: + * + * http://www.itu.int/rec/T-REC-T.124-199802-S/en + * ITU-T T.124 (02/98): Generic Conference Control + */ + +/** + * ConnectData ::= SEQUENCE + * { + * t124Identifier Key, + * connectPDU OCTET_STRING + * } + * + * ConnectGCCPDU ::= CHOICE + * { + * conferenceCreateRequest ConferenceCreateRequest, + * conferenceCreateResponse ConferenceCreateResponse, + * conferenceQueryRequest ConferenceQueryRequest, + * conferenceQueryResponse ConferenceQueryResponse, + * conferenceJoinRequest ConferenceJoinRequest, + * conferenceJoinResponse ConferenceJoinResponse, + * conferenceInviteRequest ConferenceInviteRequest, + * conferenceInviteResponse ConferenceInviteResponse, + * ... + * } + */ + +/* http://msdn.microsoft.com/en-us/library/cc240836/ */ + +uint8 t124_oid[6] = { 0, 0, 20, 124, 0, 1 }; + + diff --git a/libfreerdp-core/gcc.h b/libfreerdp-core/gcc.h new file mode 100644 index 0000000..69714b9 --- /dev/null +++ b/libfreerdp-core/gcc.h @@ -0,0 +1,29 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * T.124 Generic Conference Control (GCC) + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __GCC_H +#define __GCC_H + +#include "per.h" + +#include + + + +#endif /* __GCC_H */ diff --git a/libfreerdp-core/per.c b/libfreerdp-core/per.c new file mode 100644 index 0000000..8228ab1 --- /dev/null +++ b/libfreerdp-core/per.c @@ -0,0 +1,41 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * ASN.1 Packed Encoding Rules (BER) + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "per.h" + +void +per_write_length(STREAM* s, int length) +{ + if (length > 0x7F) + stream_write_uint16_be(s, (length | 0x8000)); + else + stream_write_uint8(s, length); +} + +void +per_write_object_identifier(STREAM* s, uint8 oid[6]) +{ + uint8 t12 = (oid[0] << 4) & (oid[1] & 0x0F); + stream_write_uint8(s, 5); /* length */ + stream_write_uint8(s, t12); /* first two tuples */ + stream_write_uint8(s, oid[2]); /* tuple 3 */ + stream_write_uint8(s, oid[3]); /* tuple 4 */ + stream_write_uint8(s, oid[4]); /* tuple 5 */ + stream_write_uint8(s, oid[5]); /* tuple 6 */ +} diff --git a/libfreerdp-core/per.h b/libfreerdp-core/per.h new file mode 100644 index 0000000..cbb8261 --- /dev/null +++ b/libfreerdp-core/per.h @@ -0,0 +1,30 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * ASN.1 Packed Encoding Rules (BER) + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PER_H +#define __PER_H + +#include + +void +per_write_length(STREAM* s, int length); +void +per_write_object_identifier(STREAM* s, uint8 oid[6]); + +#endif /* __PER_H */ -- 2.7.4