/src/FreeRDP/libfreerdp/crypto/per.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /**  | 
2  |  |  * FreeRDP: A Remote Desktop Protocol Implementation  | 
3  |  |  * ASN.1 Packed Encoding Rules (BER)  | 
4  |  |  *  | 
5  |  |  * Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>  | 
6  |  |  *  | 
7  |  |  * Licensed under the Apache License, Version 2.0 (the "License");  | 
8  |  |  * you may not use this file except in compliance with the License.  | 
9  |  |  * You may obtain a copy of the License at  | 
10  |  |  *  | 
11  |  |  *     http://www.apache.org/licenses/LICENSE-2.0  | 
12  |  |  *  | 
13  |  |  * Unless required by applicable law or agreed to in writing, software  | 
14  |  |  * distributed under the License is distributed on an "AS IS" BASIS,  | 
15  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
16  |  |  * See the License for the specific language governing permissions and  | 
17  |  |  * limitations under the License.  | 
18  |  |  */  | 
19  |  |  | 
20  |  | #include <winpr/assert.h>  | 
21  |  | #include <winpr/print.h>  | 
22  |  |  | 
23  |  | #include <freerdp/config.h>  | 
24  |  | #include <freerdp/crypto/per.h>  | 
25  |  |  | 
26  |  | #include <freerdp/log.h>  | 
27  |  | #define TAG FREERDP_TAG("crypto.per") | 
28  |  |  | 
29  |  | /**  | 
30  |  |  * Read PER length.  | 
31  |  |  *  | 
32  |  |  * @param s stream to read from  | 
33  |  |  * @param length A pointer to return the length read, must not be NULL  | 
34  |  |  *  | 
35  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
36  |  |  */  | 
37  |  |  | 
38  |  | BOOL per_read_length(wStream* s, UINT16* length)  | 
39  | 21.5k  | { | 
40  | 21.5k  |   BYTE byte = 0;  | 
41  |  |  | 
42  | 21.5k  |   WINPR_ASSERT(length);  | 
43  | 21.5k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))  | 
44  | 65  |     return FALSE;  | 
45  |  |  | 
46  | 21.4k  |   Stream_Read_UINT8(s, byte);  | 
47  |  |  | 
48  | 21.4k  |   if (byte & 0x80)  | 
49  | 2.38k  |   { | 
50  | 2.38k  |     if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))  | 
51  | 23  |       return FALSE;  | 
52  |  |  | 
53  | 2.36k  |     byte &= ~(0x80);  | 
54  | 2.36k  |     *length = (byte << 8);  | 
55  | 2.36k  |     Stream_Read_UINT8(s, byte);  | 
56  | 2.36k  |     *length += byte;  | 
57  | 2.36k  |   }  | 
58  | 19.0k  |   else  | 
59  | 19.0k  |   { | 
60  | 19.0k  |     *length = byte;  | 
61  | 19.0k  |   }  | 
62  |  |  | 
63  | 21.4k  |   return TRUE;  | 
64  | 21.4k  | }  | 
65  |  |  | 
66  |  | /**  | 
67  |  |  * Write PER length.  | 
68  |  |  * @param s stream  | 
69  |  |  * @param length length  | 
70  |  |  *  | 
71  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
72  |  |  */  | 
73  |  |  | 
74  |  | BOOL per_write_length(wStream* s, UINT16 length)  | 
75  | 0  | { | 
76  | 0  |   if (length > 0x7F)  | 
77  | 0  |   { | 
78  | 0  |     if (!Stream_EnsureRemainingCapacity(s, 2))  | 
79  | 0  |       return FALSE;  | 
80  | 0  |     Stream_Write_UINT16_BE(s, (length | 0x8000));  | 
81  | 0  |   }  | 
82  | 0  |   else  | 
83  | 0  |   { | 
84  | 0  |     if (!Stream_EnsureRemainingCapacity(s, 1))  | 
85  | 0  |       return FALSE;  | 
86  | 0  |     Stream_Write_UINT8(s, (UINT8)length);  | 
87  | 0  |   }  | 
88  | 0  |   return TRUE;  | 
89  | 0  | }  | 
90  |  |  | 
91  |  | /**  | 
92  |  |  * Read PER choice.  | 
93  |  |  * @param s stream  | 
94  |  |  * @param choice choice  | 
95  |  |  *  | 
96  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
97  |  |  */  | 
98  |  |  | 
99  |  | BOOL per_read_choice(wStream* s, BYTE* choice)  | 
100  | 5.94k  | { | 
101  | 5.94k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))  | 
102  | 14  |     return FALSE;  | 
103  |  |  | 
104  | 5.92k  |   Stream_Read_UINT8(s, *choice);  | 
105  | 5.92k  |   return TRUE;  | 
106  | 5.94k  | }  | 
107  |  |  | 
108  |  | /**  | 
109  |  |  * Write PER CHOICE.  | 
110  |  |  * @param s stream  | 
111  |  |  * @param choice index of chosen field  | 
112  |  |  *  | 
113  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
114  |  |  */  | 
115  |  |  | 
116  |  | BOOL per_write_choice(wStream* s, BYTE choice)  | 
117  | 2.54k  | { | 
118  | 2.54k  |   if (!Stream_EnsureRemainingCapacity(s, 1))  | 
119  | 0  |     return FALSE;  | 
120  | 2.54k  |   Stream_Write_UINT8(s, choice);  | 
121  | 2.54k  |   return TRUE;  | 
122  | 2.54k  | }  | 
123  |  |  | 
124  |  | /**  | 
125  |  |  * Read PER selection.  | 
126  |  |  * @param s stream  | 
127  |  |  * @param selection selection  | 
128  |  |  *  | 
129  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
130  |  |  */  | 
131  |  |  | 
132  |  | BOOL per_read_selection(wStream* s, BYTE* selection)  | 
133  | 551  | { | 
134  | 551  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))  | 
135  | 1  |     return FALSE;  | 
136  |  |  | 
137  | 550  |   WINPR_ASSERT(selection);  | 
138  | 550  |   Stream_Read_UINT8(s, *selection);  | 
139  | 550  |   return TRUE;  | 
140  | 550  | }  | 
141  |  |  | 
142  |  | /**  | 
143  |  |  * Write PER selection for OPTIONAL fields.  | 
144  |  |  * @param s stream  | 
145  |  |  * @param selection bit map of selected fields  | 
146  |  |  *  | 
147  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
148  |  |  */  | 
149  |  |  | 
150  |  | BOOL per_write_selection(wStream* s, BYTE selection)  | 
151  | 0  | { | 
152  | 0  |   if (!Stream_EnsureRemainingCapacity(s, 1))  | 
153  | 0  |     return FALSE;  | 
154  | 0  |   Stream_Write_UINT8(s, selection);  | 
155  | 0  |   return TRUE;  | 
156  | 0  | }  | 
157  |  |  | 
158  |  | /**  | 
159  |  |  * Read PER number of sets.  | 
160  |  |  * @param s stream  | 
161  |  |  * @param number number of sets  | 
162  |  |  *  | 
163  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
164  |  |  */  | 
165  |  |  | 
166  |  | BOOL per_read_number_of_sets(wStream* s, BYTE* number)  | 
167  | 1.66k  | { | 
168  | 1.66k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))  | 
169  | 4  |     return FALSE;  | 
170  |  |  | 
171  | 1.65k  |   WINPR_ASSERT(number);  | 
172  | 1.65k  |   Stream_Read_UINT8(s, *number);  | 
173  | 1.65k  |   return TRUE;  | 
174  | 1.65k  | }  | 
175  |  |  | 
176  |  | /**  | 
177  |  |  * Write PER number of sets for SET OF.  | 
178  |  |  *  | 
179  |  |  * @param s stream  | 
180  |  |  * @param number number of sets  | 
181  |  |  *  | 
182  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
183  |  |  */  | 
184  |  |  | 
185  |  | BOOL per_write_number_of_sets(wStream* s, BYTE number)  | 
186  | 0  | { | 
187  | 0  |   if (!Stream_EnsureRemainingCapacity(s, 1))  | 
188  | 0  |     return FALSE;  | 
189  | 0  |   Stream_Write_UINT8(s, number);  | 
190  | 0  |   return TRUE;  | 
191  | 0  | }  | 
192  |  |  | 
193  |  | /**  | 
194  |  |  * Read PER padding with zeros.  | 
195  |  |  *  | 
196  |  |  * @param s A stream to read from  | 
197  |  |  * @param length the data to write  | 
198  |  |  *  | 
199  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
200  |  |  */  | 
201  |  |  | 
202  |  | BOOL per_read_padding(wStream* s, UINT16 length)  | 
203  | 548  | { | 
204  | 548  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, length))  | 
205  | 1  |     return FALSE;  | 
206  |  |  | 
207  | 547  |   Stream_Seek(s, length);  | 
208  | 547  |   return TRUE;  | 
209  | 548  | }  | 
210  |  |  | 
211  |  | /**  | 
212  |  |  * Write PER padding with zeros.  | 
213  |  |  * @param s A stream to write to  | 
214  |  |  * @param length the data to write  | 
215  |  |  *  | 
216  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
217  |  |  */  | 
218  |  |  | 
219  |  | BOOL per_write_padding(wStream* s, UINT16 length)  | 
220  | 0  | { | 
221  | 0  |   if (!Stream_EnsureRemainingCapacity(s, length))  | 
222  | 0  |     return FALSE;  | 
223  | 0  |   Stream_Zero(s, length);  | 
224  | 0  |   return TRUE;  | 
225  | 0  | }  | 
226  |  |  | 
227  |  | /**  | 
228  |  |  * Read PER INTEGER.  | 
229  |  |  * @param s stream  | 
230  |  |  * @param integer integer  | 
231  |  |  *  | 
232  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
233  |  |  */  | 
234  |  |  | 
235  |  | BOOL per_read_integer(wStream* s, UINT32* integer)  | 
236  | 1.15k  | { | 
237  | 1.15k  |   UINT16 length = 0;  | 
238  |  |  | 
239  | 1.15k  |   WINPR_ASSERT(integer);  | 
240  |  |  | 
241  | 1.15k  |   if (!per_read_length(s, &length))  | 
242  | 2  |     return FALSE;  | 
243  |  |  | 
244  | 1.15k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, length))  | 
245  | 4  |     return FALSE;  | 
246  |  |  | 
247  | 1.15k  |   if (length == 0)  | 
248  | 1.09k  |     *integer = 0;  | 
249  | 60  |   else if (length == 1)  | 
250  | 34  |     Stream_Read_UINT8(s, *integer);  | 
251  | 26  |   else if (length == 2)  | 
252  | 12  |     Stream_Read_UINT16_BE(s, *integer);  | 
253  | 14  |   else  | 
254  | 14  |     return FALSE;  | 
255  |  |  | 
256  | 1.13k  |   return TRUE;  | 
257  | 1.15k  | }  | 
258  |  |  | 
259  |  | /**  | 
260  |  |  * Write PER INTEGER.  | 
261  |  |  * @param s stream  | 
262  |  |  * @param integer integer  | 
263  |  |  *  | 
264  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
265  |  |  */  | 
266  |  |  | 
267  |  | BOOL per_write_integer(wStream* s, UINT32 integer)  | 
268  | 0  | { | 
269  | 0  |   if (integer <= UINT8_MAX)  | 
270  | 0  |   { | 
271  | 0  |     if (!per_write_length(s, 1))  | 
272  | 0  |       return FALSE;  | 
273  | 0  |     if (!Stream_EnsureRemainingCapacity(s, 1))  | 
274  | 0  |       return FALSE;  | 
275  | 0  |     Stream_Write_UINT8(s, integer);  | 
276  | 0  |   }  | 
277  | 0  |   else if (integer <= UINT16_MAX)  | 
278  | 0  |   { | 
279  | 0  |     if (!per_write_length(s, 2))  | 
280  | 0  |       return FALSE;  | 
281  | 0  |     if (!Stream_EnsureRemainingCapacity(s, 2))  | 
282  | 0  |       return FALSE;  | 
283  | 0  |     Stream_Write_UINT16_BE(s, integer);  | 
284  | 0  |   }  | 
285  | 0  |   else if (integer <= UINT32_MAX)  | 
286  | 0  |   { | 
287  | 0  |     if (!per_write_length(s, 4))  | 
288  | 0  |       return FALSE;  | 
289  | 0  |     if (!Stream_EnsureRemainingCapacity(s, 4))  | 
290  | 0  |       return FALSE;  | 
291  | 0  |     Stream_Write_UINT32_BE(s, integer);  | 
292  | 0  |   }  | 
293  | 0  |   return TRUE;  | 
294  | 0  | }  | 
295  |  |  | 
296  |  | /**  | 
297  |  |  * Read PER INTEGER (UINT16).  | 
298  |  |  *  | 
299  |  |  * @param s The stream to read from  | 
300  |  |  * @param integer The integer result variable pointer, must not be NULL  | 
301  |  |  * @param min minimum value  | 
302  |  |  *  | 
303  |  |  * @return \b TRUE for success, \b FALSE otherwise  | 
304  |  |  */  | 
305  |  |  | 
306  |  | BOOL per_read_integer16(wStream* s, UINT16* integer, UINT16 min)  | 
307  | 1.40k  | { | 
308  | 1.40k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))  | 
309  | 2  |     return FALSE;  | 
310  |  |  | 
311  | 1.40k  |   Stream_Read_UINT16_BE(s, *integer);  | 
312  |  |  | 
313  | 1.40k  |   if (*integer > UINT16_MAX - min)  | 
314  | 28  |   { | 
315  | 28  |     WLog_WARN(TAG, "PER uint16 invalid value %" PRIu16 " > %" PRIu16, *integer,  | 
316  | 28  |               UINT16_MAX - min);  | 
317  | 28  |     return FALSE;  | 
318  | 28  |   }  | 
319  |  |  | 
320  | 1.37k  |   *integer += min;  | 
321  |  |  | 
322  | 1.37k  |   return TRUE;  | 
323  | 1.40k  | }  | 
324  |  |  | 
325  |  | /**  | 
326  |  |  * Write PER INTEGER (UINT16).  | 
327  |  |  * @param s stream  | 
328  |  |  * @param integer integer  | 
329  |  |  * @param min minimum value  | 
330  |  |  *  | 
331  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
332  |  |  */  | 
333  |  |  | 
334  |  | BOOL per_write_integer16(wStream* s, UINT16 integer, UINT16 min)  | 
335  | 5.08k  | { | 
336  | 5.08k  |   if (!Stream_EnsureRemainingCapacity(s, 2))  | 
337  | 0  |     return FALSE;  | 
338  | 5.08k  |   Stream_Write_UINT16_BE(s, integer - min);  | 
339  | 5.08k  |   return TRUE;  | 
340  | 5.08k  | }  | 
341  |  |  | 
342  |  | /**  | 
343  |  |  * Read PER ENUMERATED.  | 
344  |  |  *  | 
345  |  |  * @param s The stream to read from  | 
346  |  |  * @param enumerated enumerated result variable, must not be NULL  | 
347  |  |  * @param count enumeration count  | 
348  |  |  *  | 
349  |  |  * @return \b TRUE for success, \b FALSE otherwise  | 
350  |  |  */  | 
351  |  |  | 
352  |  | BOOL per_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)  | 
353  | 1.13k  | { | 
354  | 1.13k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))  | 
355  | 5  |     return FALSE;  | 
356  |  |  | 
357  | 1.13k  |   WINPR_ASSERT(enumerated);  | 
358  | 1.13k  |   Stream_Read_UINT8(s, *enumerated);  | 
359  |  |  | 
360  |  |   /* check that enumerated value falls within expected range */  | 
361  | 1.13k  |   if (*enumerated + 1 > count)  | 
362  | 18  |   { | 
363  | 18  |     WLog_WARN(TAG, "PER invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);  | 
364  | 18  |     return FALSE;  | 
365  | 18  |   }  | 
366  |  |  | 
367  | 1.11k  |   return TRUE;  | 
368  | 1.13k  | }  | 
369  |  |  | 
370  |  | /**  | 
371  |  |  * Write PER ENUMERATED.  | 
372  |  |  *  | 
373  |  |  * @param s The stream to write to  | 
374  |  |  * @param enumerated enumerated  | 
375  |  |  * @param count enumeration count  | 
376  |  |  *  | 
377  |  |  * @return \b TRUE for success, \b FALSE otherwise  | 
378  |  |  */  | 
379  |  |  | 
380  |  | BOOL per_write_enumerated(wStream* s, BYTE enumerated, BYTE count)  | 
381  | 0  | { | 
382  | 0  |   if (!Stream_EnsureRemainingCapacity(s, 1))  | 
383  | 0  |     return FALSE;  | 
384  | 0  |   Stream_Write_UINT8(s, enumerated);  | 
385  | 0  |   return TRUE;  | 
386  | 0  | }  | 
387  |  |  | 
388  |  | static BOOL per_check_oid_and_log_mismatch(const BYTE* got, const BYTE* expect, size_t length)  | 
389  | 3.40k  | { | 
390  | 3.40k  |   if (memcmp(got, expect, length) == 0)  | 
391  | 3.25k  |   { | 
392  | 3.25k  |     return TRUE;  | 
393  | 3.25k  |   }  | 
394  | 143  |   else  | 
395  | 143  |   { | 
396  | 143  |     char* got_str = winpr_BinToHexString(got, length, TRUE);  | 
397  | 143  |     char* expect_str = winpr_BinToHexString(expect, length, TRUE);  | 
398  |  |  | 
399  | 143  |     WLog_WARN(TAG, "PER OID mismatch, got %s, expected %s", got_str, expect_str);  | 
400  | 143  |     free(got_str);  | 
401  | 143  |     free(expect_str);  | 
402  | 143  |     return FALSE;  | 
403  | 143  |   }  | 
404  | 3.40k  | }  | 
405  |  |  | 
406  |  | /**  | 
407  |  |  * Read PER OBJECT_IDENTIFIER (OID).  | 
408  |  |  *  | 
409  |  |  * @param s The stream to read from  | 
410  |  |  * @param oid object identifier (OID)  | 
411  |  |  * @warning It works correctly only for limited set of OIDs.  | 
412  |  |  *  | 
413  |  |  * @return \b TRUE for success, \b FALSE otherwise  | 
414  |  |  */  | 
415  |  |  | 
416  |  | BOOL per_read_object_identifier(wStream* s, const BYTE oid[6])  | 
417  | 1.82k  | { | 
418  | 1.82k  |   BYTE t12 = 0;  | 
419  | 1.82k  |   UINT16 length = 0;  | 
420  | 1.82k  |   BYTE a_oid[6] = { 0 }; | 
421  |  |  | 
422  | 1.82k  |   if (!per_read_length(s, &length))  | 
423  | 3  |     return FALSE;  | 
424  |  |  | 
425  | 1.82k  |   if (length != 5)  | 
426  | 7  |   { | 
427  | 7  |     WLog_WARN(TAG, "PER length, got %" PRIu16 ", expected 5", length);  | 
428  | 7  |     return FALSE;  | 
429  | 7  |   }  | 
430  |  |  | 
431  | 1.81k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, length))  | 
432  | 3  |     return FALSE;  | 
433  |  |  | 
434  | 1.81k  |   Stream_Read_UINT8(s, t12); /* first two tuples */  | 
435  | 1.81k  |   a_oid[0] = t12 / 40;  | 
436  | 1.81k  |   a_oid[1] = t12 % 40;  | 
437  |  |  | 
438  | 1.81k  |   Stream_Read_UINT8(s, a_oid[2]); /* tuple 3 */  | 
439  | 1.81k  |   Stream_Read_UINT8(s, a_oid[3]); /* tuple 4 */  | 
440  | 1.81k  |   Stream_Read_UINT8(s, a_oid[4]); /* tuple 5 */  | 
441  | 1.81k  |   Stream_Read_UINT8(s, a_oid[5]); /* tuple 6 */  | 
442  |  |  | 
443  | 1.81k  |   return per_check_oid_and_log_mismatch(a_oid, oid, sizeof(a_oid));  | 
444  | 1.81k  | }  | 
445  |  |  | 
446  |  | /**  | 
447  |  |  * Write PER OBJECT_IDENTIFIER (OID)  | 
448  |  |  * @param s stream  | 
449  |  |  * @param oid object identifier (oid)  | 
450  |  |  * @warning It works correctly only for limited set of OIDs.  | 
451  |  |  *  | 
452  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
453  |  |  */  | 
454  |  |  | 
455  |  | BOOL per_write_object_identifier(wStream* s, const BYTE oid[6])  | 
456  | 0  | { | 
457  | 0  |   BYTE t12 = oid[0] * 40 + oid[1];  | 
458  | 0  |   if (!Stream_EnsureRemainingCapacity(s, 6))  | 
459  | 0  |     return FALSE;  | 
460  | 0  |   Stream_Write_UINT8(s, 5);      /* length */  | 
461  | 0  |   Stream_Write_UINT8(s, t12);    /* first two tuples */  | 
462  | 0  |   Stream_Write_UINT8(s, oid[2]); /* tuple 3 */  | 
463  | 0  |   Stream_Write_UINT8(s, oid[3]); /* tuple 4 */  | 
464  | 0  |   Stream_Write_UINT8(s, oid[4]); /* tuple 5 */  | 
465  | 0  |   Stream_Write_UINT8(s, oid[5]); /* tuple 6 */  | 
466  | 0  |   return TRUE;  | 
467  | 0  | }  | 
468  |  |  | 
469  |  | /**  | 
470  |  |  * Write PER string.  | 
471  |  |  * @param s stream  | 
472  |  |  * @param str string  | 
473  |  |  * @param length string length  | 
474  |  |  */  | 
475  |  |  | 
476  |  | static void per_write_string(wStream* s, BYTE* str, int length)  | 
477  | 0  | { | 
478  | 0  |   for (int i = 0; i < length; i++)  | 
479  | 0  |     Stream_Write_UINT8(s, str[i]);  | 
480  | 0  | }  | 
481  |  |  | 
482  |  | /**  | 
483  |  |  * Read PER OCTET_STRING.  | 
484  |  |  *  | 
485  |  |  * @param s The stream to read from  | 
486  |  |  * @param oct_str octet string  | 
487  |  |  * @param length string length  | 
488  |  |  * @param min minimum length  | 
489  |  |  *  | 
490  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
491  |  |  */  | 
492  |  |  | 
493  |  | BOOL per_read_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)  | 
494  | 1.64k  | { | 
495  | 1.64k  |   UINT16 mlength = 0;  | 
496  |  |  | 
497  | 1.64k  |   if (!per_read_length(s, &mlength))  | 
498  | 3  |     return FALSE;  | 
499  |  |  | 
500  | 1.64k  |   if (mlength + min != length)  | 
501  | 48  |   { | 
502  | 48  |     WLog_ERR(TAG, "length mismatch: %" PRIu16 "!= %" PRIu16, mlength + min, length);  | 
503  | 48  |     return FALSE;  | 
504  | 48  |   }  | 
505  |  |  | 
506  | 1.59k  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, length))  | 
507  | 3  |     return FALSE;  | 
508  |  |  | 
509  | 1.59k  |   const BYTE* a_oct_str = Stream_ConstPointer(s);  | 
510  | 1.59k  |   Stream_Seek(s, length);  | 
511  |  |  | 
512  | 1.59k  |   return per_check_oid_and_log_mismatch(a_oct_str, oct_str, length);  | 
513  | 1.59k  | }  | 
514  |  |  | 
515  |  | /**  | 
516  |  |  * Write PER OCTET_STRING  | 
517  |  |  * @param s stream  | 
518  |  |  * @param oct_str octet string  | 
519  |  |  * @param length string length  | 
520  |  |  * @param min minimum string length  | 
521  |  |  *  | 
522  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
523  |  |  */  | 
524  |  |  | 
525  |  | BOOL per_write_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)  | 
526  | 0  | { | 
527  | 0  |   UINT16 mlength = 0;  | 
528  |  | 
  | 
529  | 0  |   mlength = (length >= min) ? length - min : min;  | 
530  |  | 
  | 
531  | 0  |   if (!per_write_length(s, mlength))  | 
532  | 0  |     return FALSE;  | 
533  |  |  | 
534  | 0  |   if (!Stream_EnsureRemainingCapacity(s, length))  | 
535  | 0  |     return FALSE;  | 
536  | 0  |   for (UINT16 i = 0; i < length; i++)  | 
537  | 0  |     Stream_Write_UINT8(s, oct_str[i]);  | 
538  | 0  |   return TRUE;  | 
539  | 0  | }  | 
540  |  |  | 
541  |  | /**  | 
542  |  |  * Read PER NumericString.  | 
543  |  |  * @param s stream  | 
544  |  |  * @param min minimum string length  | 
545  |  |  *  | 
546  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
547  |  |  */  | 
548  |  |  | 
549  |  | BOOL per_read_numeric_string(wStream* s, UINT16 min)  | 
550  | 550  | { | 
551  | 550  |   size_t length = 0;  | 
552  | 550  |   UINT16 mlength = 0;  | 
553  |  |  | 
554  | 550  |   if (!per_read_length(s, &mlength))  | 
555  | 1  |     return FALSE;  | 
556  |  |  | 
557  | 549  |   length = (mlength + min + 1) / 2;  | 
558  |  |  | 
559  | 549  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, length))  | 
560  | 1  |     return FALSE;  | 
561  |  |  | 
562  | 548  |   Stream_Seek(s, length);  | 
563  | 548  |   return TRUE;  | 
564  | 549  | }  | 
565  |  |  | 
566  |  | /**  | 
567  |  |  * Write PER NumericString.  | 
568  |  |  * @param s stream  | 
569  |  |  * @param num_str numeric string  | 
570  |  |  * @param length string length  | 
571  |  |  * @param min minimum string length  | 
572  |  |  *  | 
573  |  |  * @return \b TRUE for success, \b FALSE otherwise.  | 
574  |  |  */  | 
575  |  |  | 
576  |  | BOOL per_write_numeric_string(wStream* s, const BYTE* num_str, UINT16 length, UINT16 min)  | 
577  | 0  | { | 
578  | 0  |   WINPR_ASSERT(num_str || (length == 0));  | 
579  |  |  | 
580  | 0  |   const UINT16 mlength = (length >= min) ? length - min : min;  | 
581  |  | 
  | 
582  | 0  |   if (!per_write_length(s, mlength))  | 
583  | 0  |     return FALSE;  | 
584  |  |  | 
585  | 0  |   if (!Stream_EnsureRemainingCapacity(s, length))  | 
586  | 0  |     return FALSE;  | 
587  | 0  |   for (UINT16 i = 0; i < length; i += 2)  | 
588  | 0  |   { | 
589  | 0  |     BYTE c1 = num_str[i];  | 
590  | 0  |     BYTE c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;  | 
591  |  | 
  | 
592  | 0  |     if ((c1 < 0x30) || (c2 < 0x30))  | 
593  | 0  |       return FALSE;  | 
594  |  |  | 
595  | 0  |     c1 = (c1 - 0x30) % 10;  | 
596  | 0  |     c2 = (c2 - 0x30) % 10;  | 
597  | 0  |     const BYTE num = (c1 << 4) | c2;  | 
598  |  | 
  | 
599  | 0  |     Stream_Write_UINT8(s, num); /* string */  | 
600  | 0  |   }  | 
601  | 0  |   return TRUE;  | 
602  | 0  | }  |