FreeRDP
Loading...
Searching...
No Matches
TestASN1.c
1#include <winpr/asn1.h>
2#include <winpr/print.h>
3
4static const BYTE boolContent[] = { 0x01, 0x01, 0xFF };
5static const BYTE badBoolContent[] = { 0x01, 0x04, 0xFF };
6
7static const BYTE integerContent[] = { 0x02, 0x01, 0x02 };
8static const BYTE badIntegerContent[] = { 0x02, 0x04, 0x02 };
9static const BYTE positiveIntegerContent[] = { 0x02, 0x02, 0x00, 0xff };
10static const BYTE negativeIntegerContent[] = { 0x02, 0x01, 0xff };
11
12static const BYTE seqContent[] = { 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1B, 0x44,
13 0x69, 0x67, 0x69, 0x74, 0x61, 0x6C, 0x20, 0x53, 0x69, 0x67,
14 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75,
15 0x73, 0x74, 0x20, 0x43, 0x6F, 0x2E, 0x31 };
16
17static const BYTE contextualInteger[] = { 0xA0, 0x03, 0x02, 0x01, 0x02 };
18
19static const BYTE oidContent[] = { 0x06, 0x03, 0x55, 0x04, 0x0A };
20static const BYTE badOidContent[] = { 0x06, 0x89, 0x55, 0x04, 0x0A };
21static const BYTE oidValue[] = { 0x55, 0x04, 0x0A };
22
23static const BYTE ia5stringContent[] = { 0x16, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F,
24 0x63, 0x70, 0x73, 0x2E, 0x72, 0x6F, 0x6F, 0x74, 0x2D,
25 0x78, 0x31, 0x2E, 0x6C, 0x65, 0x74, 0x73, 0x65, 0x6E,
26 0x63, 0x72, 0x79, 0x70, 0x74, 0x2E, 0x6F, 0x72, 0x67 };
27
28static const BYTE utctimeContent[] = { 0x17, 0x0D, 0x32, 0x31, 0x30, 0x33, 0x31, 0x37,
29 0x31, 0x36, 0x34, 0x30, 0x34, 0x36, 0x5A };
30
31int TestASN1Read(int argc, char* argv[])
32{
33 WinPrAsn1Decoder decoder;
34 WinPrAsn1Decoder seqDecoder;
35 wStream staticS;
36 WinPrAsn1_BOOL boolV = 0;
37 WinPrAsn1_INTEGER integerV = 0;
38 WinPrAsn1_OID oidV;
39 WinPrAsn1_IA5STRING ia5stringV = NULL;
40 WinPrAsn1_UTCTIME utctimeV;
41 WinPrAsn1_tag tag = 0;
42 size_t len = 0;
43 BOOL error = 0;
44
45 /* ============== Test INTEGERs ================ */
46 Stream_StaticConstInit(&staticS, integerContent, sizeof(integerContent));
47 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
48 if (!WinPrAsn1DecReadInteger(&decoder, &integerV))
49 return -1;
50
51 Stream_StaticConstInit(&staticS, positiveIntegerContent, sizeof(positiveIntegerContent));
52 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
53 if (!WinPrAsn1DecReadInteger(&decoder, &integerV) && integerV != 0xff)
54 return -1;
55
56 Stream_StaticConstInit(&staticS, negativeIntegerContent, sizeof(negativeIntegerContent));
57 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
58 if (!WinPrAsn1DecReadInteger(&decoder, &integerV) && integerV != -1)
59 return -1;
60
61 Stream_StaticConstInit(&staticS, badIntegerContent, sizeof(badIntegerContent));
62 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
63 if (WinPrAsn1DecReadInteger(&decoder, &integerV))
64 return -1;
65
66 /* ================ Test BOOL ================*/
67 Stream_StaticConstInit(&staticS, boolContent, sizeof(boolContent));
68 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
69 if (!WinPrAsn1DecReadBoolean(&decoder, &boolV))
70 return -10;
71
72 Stream_StaticConstInit(&staticS, badBoolContent, sizeof(badBoolContent));
73 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
74 if (WinPrAsn1DecReadBoolean(&decoder, &boolV))
75 return -11;
76
77 /* ================ Test OID ================*/
78 Stream_StaticConstInit(&staticS, oidContent, sizeof(oidContent));
79 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
80 if (!WinPrAsn1DecReadOID(&decoder, &oidV, TRUE) || oidV.len != 3 ||
81 (memcmp(oidV.data, oidValue, oidV.len) != 0))
82 return -15;
83 WinPrAsn1FreeOID(&oidV);
84
85 Stream_StaticConstInit(&staticS, badOidContent, sizeof(badOidContent));
86 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
87 if (WinPrAsn1DecReadOID(&decoder, &oidV, TRUE))
88 return -15;
89 WinPrAsn1FreeOID(&oidV);
90
91 Stream_StaticConstInit(&staticS, ia5stringContent, sizeof(ia5stringContent));
92 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
93 if (!WinPrAsn1DecReadIA5String(&decoder, &ia5stringV) ||
94 (strcmp(ia5stringV, "http://cps.root-x1.letsencrypt.org") != 0))
95 return -16;
96 free(ia5stringV);
97
98 /* ================ Test utc time ================*/
99 Stream_StaticConstInit(&staticS, utctimeContent, sizeof(utctimeContent));
100 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
101 if (!WinPrAsn1DecReadUtcTime(&decoder, &utctimeV) || utctimeV.year != 2021 ||
102 utctimeV.month != 3 || utctimeV.day != 17 || utctimeV.minute != 40 || utctimeV.tz != 'Z')
103 return -17;
104
105 /* ================ Test sequence ================*/
106 Stream_StaticConstInit(&staticS, seqContent, sizeof(seqContent));
107 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
108 if (!WinPrAsn1DecReadSequence(&decoder, &seqDecoder))
109 return -20;
110
111 Stream_StaticConstInit(&staticS, seqContent, sizeof(seqContent));
112 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
113 if (!WinPrAsn1DecReadTagLenValue(&decoder, &tag, &len, &seqDecoder))
114 return -21;
115
116 if (tag != ER_TAG_SEQUENCE)
117 return -22;
118
119 if (!WinPrAsn1DecPeekTag(&seqDecoder, &tag) || tag != ER_TAG_OBJECT_IDENTIFIER)
120 return -23;
121
122 /* ================ Test contextual ================*/
123 Stream_StaticConstInit(&staticS, contextualInteger, sizeof(contextualInteger));
124 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
125 error = TRUE;
126 if (!WinPrAsn1DecReadContextualInteger(&decoder, 0, &error, &integerV) || error)
127 return -25;
128
129 /* test reading a contextual integer that is not there (index 1).
130 * that should not touch the decoder read head and we shall be able to extract contextual tag 0
131 * after that
132 */
133 WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
134 error = FALSE;
135 if (WinPrAsn1DecReadContextualInteger(&decoder, 1, &error, &integerV) || error)
136 return -26;
137
138 error = FALSE;
139 if (!WinPrAsn1DecReadContextualInteger(&decoder, 0, &error, &integerV) || error)
140 return -27;
141
142 return 0;
143}
144
145static BYTE oid1_val[] = { 1 };
146static const WinPrAsn1_OID oid1 = { sizeof(oid1_val), oid1_val };
147static BYTE oid2_val[] = { 2, 2 };
148static WinPrAsn1_OID oid2 = { sizeof(oid2_val), oid2_val };
149static BYTE oid3_val[] = { 3, 3, 3 };
150static WinPrAsn1_OID oid3 = { sizeof(oid3_val), oid3_val };
151static BYTE oid4_val[] = { 4, 4, 4, 4 };
152static WinPrAsn1_OID oid4 = { sizeof(oid4_val), oid4_val };
153
154int TestASN1Write(int argc, char* argv[])
155{
156 wStream* s = NULL;
157 size_t expectedOuputSz = 0;
158 int retCode = 100;
159 WinPrAsn1_UTCTIME utcTime;
160 WinPrAsn1_IA5STRING ia5string = NULL;
161 WinPrAsn1Encoder* enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
162 if (!enc)
163 goto out;
164
165 /* Let's encode something like:
166 * APP(3)
167 * SEQ2
168 * OID1
169 * OID2
170 * SEQ3
171 * OID3
172 * OID4
173 *
174 * [5] integer(200)
175 * [6] SEQ (empty)
176 * [7] UTC time (2016-03-17 16:40:41 UTC)
177 * [8] IA5String(test)
178 * [9] OctetString
179 * SEQ(empty)
180 *
181 */
182
183 /* APP(3) */
184 retCode = 101;
185 if (!WinPrAsn1EncAppContainer(enc, 3))
186 goto out;
187
188 /* SEQ2 */
189 retCode = 102;
190 if (!WinPrAsn1EncSeqContainer(enc))
191 goto out;
192
193 retCode = 103;
194 if (WinPrAsn1EncOID(enc, &oid1) != 3)
195 goto out;
196
197 retCode = 104;
198 if (WinPrAsn1EncOID(enc, &oid2) != 4)
199 goto out;
200
201 retCode = 105;
202 if (WinPrAsn1EncEndContainer(enc) != 9)
203 goto out;
204
205 /* SEQ3 */
206 retCode = 110;
207 if (!WinPrAsn1EncSeqContainer(enc))
208 goto out;
209
210 retCode = 111;
211 if (WinPrAsn1EncOID(enc, &oid3) != 5)
212 goto out;
213
214 retCode = 112;
215 if (WinPrAsn1EncOID(enc, &oid4) != 6)
216 goto out;
217
218 retCode = 113;
219 if (WinPrAsn1EncEndContainer(enc) != 13)
220 goto out;
221
222 /* [5] integer(200) */
223 retCode = 114;
224 if (WinPrAsn1EncContextualInteger(enc, 5, 200) != 6)
225 goto out;
226
227 /* [6] SEQ (empty) */
228 retCode = 115;
229 if (!WinPrAsn1EncContextualSeqContainer(enc, 6))
230 goto out;
231
232 retCode = 116;
233 if (WinPrAsn1EncEndContainer(enc) != 4)
234 goto out;
235
236 /* [7] UTC time (2016-03-17 16:40:41 UTC) */
237 retCode = 117;
238 utcTime.year = 2016;
239 utcTime.month = 3;
240 utcTime.day = 17;
241 utcTime.hour = 16;
242 utcTime.minute = 40;
243 utcTime.second = 41;
244 utcTime.tz = 'Z';
245 if (WinPrAsn1EncContextualUtcTime(enc, 7, &utcTime) != 17)
246 goto out;
247
248 /* [8] IA5String(test) */
249 retCode = 118;
250 ia5string = "test";
251 if (!WinPrAsn1EncContextualContainer(enc, 8))
252 goto out;
253
254 retCode = 119;
255 if (WinPrAsn1EncIA5String(enc, ia5string) != 6)
256 goto out;
257
258 retCode = 120;
259 if (WinPrAsn1EncEndContainer(enc) != 8)
260 goto out;
261
262 /* [9] OctetString
263 * SEQ(empty)
264 */
265 retCode = 121;
266 if (!WinPrAsn1EncContextualOctetStringContainer(enc, 9))
267 goto out;
268
269 retCode = 122;
270 if (!WinPrAsn1EncSeqContainer(enc))
271 goto out;
272
273 retCode = 123;
274 if (WinPrAsn1EncEndContainer(enc) != 2)
275 goto out;
276
277 retCode = 124;
278 if (WinPrAsn1EncEndContainer(enc) != 6)
279 goto out;
280
281 /* close APP */
282 expectedOuputSz = 24 + 6 + 4 + 17 + 8 + 6;
283 retCode = 200;
284 if (WinPrAsn1EncEndContainer(enc) != expectedOuputSz)
285 goto out;
286
287 /* let's output the result */
288 retCode = 201;
289 s = Stream_New(NULL, 1024);
290 if (!s)
291 goto out;
292
293 retCode = 202;
294 if (!WinPrAsn1EncToStream(enc, s) || Stream_GetPosition(s) != expectedOuputSz)
295 goto out;
296 /* winpr_HexDump("", WLOG_ERROR, Stream_Buffer(s), Stream_GetPosition(s));*/
297
298 /*
299 * let's perform a mini-performance test, where we encode an ASN1 message with a big depth,
300 * so that we trigger reallocation routines in the encoder. We're gonna encode something like
301 * SEQ1
302 * SEQ2
303 * SEQ3
304 * ...
305 * SEQ1000
306 * INTEGER(2)
307 *
308 * As static chunks and containers are 50, a depth of 1000 should be enough
309 *
310 */
311 WinPrAsn1Encoder_Reset(enc);
312
313 retCode = 203;
314 for (size_t i = 0; i < 1000; i++)
315 {
316 if (!WinPrAsn1EncSeqContainer(enc))
317 goto out;
318 }
319
320 retCode = 204;
321 if (WinPrAsn1EncInteger(enc, 2) != 3)
322 goto out;
323
324 retCode = 205;
325 for (size_t i = 0; i < 1000; i++)
326 {
327 if (!WinPrAsn1EncEndContainer(enc))
328 goto out;
329 }
330
331 retCode = 0;
332
333out:
334 if (s)
335 Stream_Free(s, TRUE);
336 WinPrAsn1Encoder_Free(&enc);
337 return retCode;
338}
339
340int TestASN1(int argc, char* argv[])
341{
342 int ret = TestASN1Read(argc, argv);
343 if (ret)
344 return ret;
345
346 return TestASN1Write(argc, argv);
347}