| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* |
|
2
|
|
|
|
|
|
|
* pdfmake_asn1.c — ASN.1 DER encoding/decoding implementation |
|
3
|
|
|
|
|
|
|
* |
|
4
|
|
|
|
|
|
|
* Minimal ASN.1 DER codec for X.509, PKCS#7, PKCS#12 parsing and building. |
|
5
|
|
|
|
|
|
|
*/ |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#include "pdfmake_asn1.h" |
|
8
|
|
|
|
|
|
|
#include "pdfmake_arena.h" |
|
9
|
|
|
|
|
|
|
#include "pdfmake_buf.h" |
|
10
|
|
|
|
|
|
|
#include |
|
11
|
|
|
|
|
|
|
#include |
|
12
|
|
|
|
|
|
|
#include |
|
13
|
|
|
|
|
|
|
#include |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
/*============================================================================ |
|
16
|
|
|
|
|
|
|
* Internal helpers |
|
17
|
|
|
|
|
|
|
*==========================================================================*/ |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
/* Parse DER length field */ |
|
20
|
143
|
|
|
|
|
|
static int parse_length(const uint8_t *data, size_t len, size_t *pos, size_t *out_len) |
|
21
|
|
|
|
|
|
|
{ |
|
22
|
|
|
|
|
|
|
uint8_t first; |
|
23
|
|
|
|
|
|
|
size_t num_bytes; |
|
24
|
|
|
|
|
|
|
size_t length; |
|
25
|
|
|
|
|
|
|
size_t i; |
|
26
|
|
|
|
|
|
|
|
|
27
|
143
|
50
|
|
|
|
|
if (*pos >= len) return -1; |
|
28
|
|
|
|
|
|
|
|
|
29
|
143
|
|
|
|
|
|
first = data[(*pos)++]; |
|
30
|
|
|
|
|
|
|
|
|
31
|
143
|
100
|
|
|
|
|
if (first < 0x80) { |
|
32
|
|
|
|
|
|
|
/* Short form: length in single byte */ |
|
33
|
102
|
|
|
|
|
|
*out_len = first; |
|
34
|
102
|
|
|
|
|
|
return 0; |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
41
|
50
|
|
|
|
|
if (first == 0x80) { |
|
38
|
|
|
|
|
|
|
/* Indefinite length - not valid in DER */ |
|
39
|
0
|
|
|
|
|
|
return -1; |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
/* Long form: first byte indicates number of length bytes */ |
|
43
|
41
|
|
|
|
|
|
num_bytes = first & 0x7F; |
|
44
|
41
|
50
|
|
|
|
|
if (num_bytes > sizeof(size_t) || *pos + num_bytes > len) { |
|
|
|
50
|
|
|
|
|
|
|
45
|
0
|
|
|
|
|
|
return -1; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
|
|
48
|
41
|
|
|
|
|
|
length = 0; |
|
49
|
118
|
100
|
|
|
|
|
for (i = 0; i < num_bytes; i++) { |
|
50
|
77
|
|
|
|
|
|
length = (length << 8) | data[(*pos)++]; |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
|
|
53
|
41
|
|
|
|
|
|
*out_len = length; |
|
54
|
41
|
|
|
|
|
|
return 0; |
|
55
|
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
/* Encode DER length field */ |
|
58
|
0
|
|
|
|
|
|
static pdfmake_err_t write_length(pdfmake_buf_t *buf, size_t length) |
|
59
|
|
|
|
|
|
|
{ |
|
60
|
|
|
|
|
|
|
size_t temp; |
|
61
|
|
|
|
|
|
|
int num_bytes; |
|
62
|
|
|
|
|
|
|
pdfmake_err_t err; |
|
63
|
|
|
|
|
|
|
int i; |
|
64
|
|
|
|
|
|
|
|
|
65
|
0
|
0
|
|
|
|
|
if (length < 0x80) { |
|
66
|
0
|
|
|
|
|
|
return pdfmake_buf_append_byte(buf, (uint8_t)length); |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
/* Count bytes needed */ |
|
70
|
0
|
|
|
|
|
|
temp = length; |
|
71
|
0
|
|
|
|
|
|
num_bytes = 0; |
|
72
|
0
|
0
|
|
|
|
|
while (temp > 0) { |
|
73
|
0
|
|
|
|
|
|
num_bytes++; |
|
74
|
0
|
|
|
|
|
|
temp >>= 8; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
/* Write length-of-length byte */ |
|
78
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(buf, 0x80 | num_bytes); |
|
79
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
/* Write length bytes (big-endian) */ |
|
82
|
0
|
0
|
|
|
|
|
for (i = num_bytes - 1; i >= 0; i--) { |
|
83
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(buf, (length >> (i * 8)) & 0xFF); |
|
84
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
|
return PDFMAKE_OK; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
/*============================================================================ |
|
91
|
|
|
|
|
|
|
* Parsing API |
|
92
|
|
|
|
|
|
|
*==========================================================================*/ |
|
93
|
|
|
|
|
|
|
|
|
94
|
143
|
|
|
|
|
|
pdfmake_asn1_node_t *pdfmake_asn1_parse_element( |
|
95
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
96
|
|
|
|
|
|
|
const uint8_t *data, |
|
97
|
|
|
|
|
|
|
size_t len, |
|
98
|
|
|
|
|
|
|
size_t *pos) |
|
99
|
|
|
|
|
|
|
{ |
|
100
|
|
|
|
|
|
|
pdfmake_asn1_node_t *node; |
|
101
|
|
|
|
|
|
|
|
|
102
|
143
|
50
|
|
|
|
|
if (*pos >= len) return NULL; |
|
103
|
|
|
|
|
|
|
|
|
104
|
143
|
|
|
|
|
|
node = pdfmake_arena_alloc(arena, sizeof(pdfmake_asn1_node_t)); |
|
105
|
143
|
50
|
|
|
|
|
if (!node) return NULL; |
|
106
|
|
|
|
|
|
|
|
|
107
|
143
|
|
|
|
|
|
memset(node, 0, sizeof(pdfmake_asn1_node_t)); |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
/* Parse tag */ |
|
110
|
143
|
|
|
|
|
|
node->tag = data[(*pos)++]; |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
/* Handle multi-byte tags (tag number >= 31) */ |
|
113
|
143
|
50
|
|
|
|
|
if ((node->tag & 0x1F) == 0x1F) { |
|
114
|
|
|
|
|
|
|
/* Multi-byte tag - skip additional tag bytes for now */ |
|
115
|
0
|
0
|
|
|
|
|
while (*pos < len && (data[*pos] & 0x80)) { |
|
|
|
0
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
|
(*pos)++; |
|
117
|
|
|
|
|
|
|
} |
|
118
|
0
|
0
|
|
|
|
|
if (*pos < len) (*pos)++; /* Skip final tag byte */ |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
/* Parse length */ |
|
122
|
143
|
50
|
|
|
|
|
if (parse_length(data, len, pos, &node->length) != 0) { |
|
123
|
0
|
|
|
|
|
|
return NULL; |
|
124
|
|
|
|
|
|
|
} |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
/* Check bounds */ |
|
127
|
143
|
50
|
|
|
|
|
if (*pos + node->length > len) { |
|
128
|
0
|
|
|
|
|
|
return NULL; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
/* Set data pointer */ |
|
132
|
143
|
|
|
|
|
|
node->data = data + *pos; |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
/* Parse children for constructed types */ |
|
135
|
143
|
100
|
|
|
|
|
if (node->tag & ASN1_CONSTRUCTED) { |
|
136
|
65
|
|
|
|
|
|
size_t content_end = *pos + node->length; |
|
137
|
65
|
|
|
|
|
|
pdfmake_asn1_node_t *last_child = NULL; |
|
138
|
|
|
|
|
|
|
|
|
139
|
197
|
100
|
|
|
|
|
while (*pos < content_end) { |
|
140
|
132
|
|
|
|
|
|
pdfmake_asn1_node_t *child = pdfmake_asn1_parse_element(arena, data, content_end, pos); |
|
141
|
132
|
50
|
|
|
|
|
if (!child) return NULL; |
|
142
|
|
|
|
|
|
|
|
|
143
|
132
|
|
|
|
|
|
child->parent = node; |
|
144
|
|
|
|
|
|
|
|
|
145
|
132
|
100
|
|
|
|
|
if (last_child) { |
|
146
|
67
|
|
|
|
|
|
last_child->next = child; |
|
147
|
|
|
|
|
|
|
} else { |
|
148
|
65
|
|
|
|
|
|
node->children = child; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
132
|
|
|
|
|
|
last_child = child; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
} else { |
|
153
|
|
|
|
|
|
|
/* Primitive type - skip content */ |
|
154
|
78
|
|
|
|
|
|
*pos += node->length; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
143
|
|
|
|
|
|
return node; |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
3
|
|
|
|
|
|
pdfmake_asn1_node_t *pdfmake_asn1_parse( |
|
161
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
162
|
|
|
|
|
|
|
const uint8_t *data, |
|
163
|
|
|
|
|
|
|
size_t len) |
|
164
|
|
|
|
|
|
|
{ |
|
165
|
3
|
|
|
|
|
|
size_t pos = 0; |
|
166
|
3
|
|
|
|
|
|
return pdfmake_asn1_parse_element(arena, data, len, &pos); |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
0
|
|
|
|
|
|
size_t pdfmake_asn1_child_count(const pdfmake_asn1_node_t *node) |
|
170
|
|
|
|
|
|
|
{ |
|
171
|
0
|
|
|
|
|
|
size_t count = 0; |
|
172
|
|
|
|
|
|
|
pdfmake_asn1_node_t *child; |
|
173
|
|
|
|
|
|
|
|
|
174
|
0
|
0
|
|
|
|
|
if (!node) return 0; |
|
175
|
|
|
|
|
|
|
|
|
176
|
0
|
|
|
|
|
|
child = node->children; |
|
177
|
0
|
0
|
|
|
|
|
while (child) { |
|
178
|
0
|
|
|
|
|
|
count++; |
|
179
|
0
|
|
|
|
|
|
child = child->next; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
0
|
|
|
|
|
|
return count; |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
|
|
184
|
64
|
|
|
|
|
|
pdfmake_asn1_node_t *pdfmake_asn1_child_at( |
|
185
|
|
|
|
|
|
|
const pdfmake_asn1_node_t *node, |
|
186
|
|
|
|
|
|
|
size_t index) |
|
187
|
|
|
|
|
|
|
{ |
|
188
|
|
|
|
|
|
|
pdfmake_asn1_node_t *child; |
|
189
|
|
|
|
|
|
|
size_t i; |
|
190
|
|
|
|
|
|
|
|
|
191
|
64
|
50
|
|
|
|
|
if (!node) return NULL; |
|
192
|
|
|
|
|
|
|
|
|
193
|
64
|
|
|
|
|
|
child = node->children; |
|
194
|
110
|
100
|
|
|
|
|
for (i = 0; i < index && child; i++) { |
|
|
|
50
|
|
|
|
|
|
|
195
|
46
|
|
|
|
|
|
child = child->next; |
|
196
|
|
|
|
|
|
|
} |
|
197
|
64
|
|
|
|
|
|
return child; |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
|
|
200
|
2
|
|
|
|
|
|
pdfmake_asn1_node_t *pdfmake_asn1_find_tag( |
|
201
|
|
|
|
|
|
|
const pdfmake_asn1_node_t *node, |
|
202
|
|
|
|
|
|
|
uint8_t tag) |
|
203
|
|
|
|
|
|
|
{ |
|
204
|
|
|
|
|
|
|
pdfmake_asn1_node_t *child; |
|
205
|
|
|
|
|
|
|
|
|
206
|
2
|
50
|
|
|
|
|
if (!node) return NULL; |
|
207
|
|
|
|
|
|
|
|
|
208
|
2
|
|
|
|
|
|
child = node->children; |
|
209
|
3
|
100
|
|
|
|
|
while (child) { |
|
210
|
2
|
100
|
|
|
|
|
if (child->tag == tag) return child; |
|
211
|
1
|
|
|
|
|
|
child = child->next; |
|
212
|
|
|
|
|
|
|
} |
|
213
|
1
|
|
|
|
|
|
return NULL; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
/*============================================================================ |
|
217
|
|
|
|
|
|
|
* Value Extraction |
|
218
|
|
|
|
|
|
|
*==========================================================================*/ |
|
219
|
|
|
|
|
|
|
|
|
220
|
4
|
|
|
|
|
|
int pdfmake_asn1_get_int64(const pdfmake_asn1_node_t *node, int64_t *out) |
|
221
|
|
|
|
|
|
|
{ |
|
222
|
|
|
|
|
|
|
int negative; |
|
223
|
|
|
|
|
|
|
int64_t value; |
|
224
|
|
|
|
|
|
|
size_t i; |
|
225
|
|
|
|
|
|
|
|
|
226
|
4
|
50
|
|
|
|
|
if (!node || !out) return -1; |
|
|
|
50
|
|
|
|
|
|
|
227
|
4
|
50
|
|
|
|
|
if (node->tag != ASN1_TAG_INTEGER && node->tag != ASN1_TAG_ENUMERATED) return -1; |
|
|
|
0
|
|
|
|
|
|
|
228
|
4
|
50
|
|
|
|
|
if (node->length == 0 || node->length > 8) return -1; |
|
|
|
50
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
/* Check if negative (high bit set) */ |
|
231
|
4
|
|
|
|
|
|
negative = (node->data[0] & 0x80) != 0; |
|
232
|
|
|
|
|
|
|
|
|
233
|
4
|
50
|
|
|
|
|
value = negative ? -1 : 0; /* Sign extend */ |
|
234
|
10
|
100
|
|
|
|
|
for (i = 0; i < node->length; i++) { |
|
235
|
6
|
|
|
|
|
|
value = (value << 8) | node->data[i]; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
|
|
238
|
4
|
|
|
|
|
|
*out = value; |
|
239
|
4
|
|
|
|
|
|
return 0; |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
|
|
242
|
0
|
|
|
|
|
|
int pdfmake_asn1_get_uint64(const pdfmake_asn1_node_t *node, uint64_t *out) |
|
243
|
|
|
|
|
|
|
{ |
|
244
|
|
|
|
|
|
|
const uint8_t *data; |
|
245
|
|
|
|
|
|
|
size_t len; |
|
246
|
|
|
|
|
|
|
uint64_t value; |
|
247
|
|
|
|
|
|
|
size_t i; |
|
248
|
|
|
|
|
|
|
|
|
249
|
0
|
0
|
|
|
|
|
if (!node || !out) return -1; |
|
|
|
0
|
|
|
|
|
|
|
250
|
0
|
0
|
|
|
|
|
if (node->tag != ASN1_TAG_INTEGER) return -1; |
|
251
|
0
|
0
|
|
|
|
|
if (node->length == 0) return -1; |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
/* Skip leading zero byte if present (for positive numbers with high bit set) */ |
|
254
|
0
|
|
|
|
|
|
data = node->data; |
|
255
|
0
|
|
|
|
|
|
len = node->length; |
|
256
|
|
|
|
|
|
|
|
|
257
|
0
|
0
|
|
|
|
|
if (len > 1 && data[0] == 0x00) { |
|
|
|
0
|
|
|
|
|
|
|
258
|
0
|
|
|
|
|
|
data++; |
|
259
|
0
|
|
|
|
|
|
len--; |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
|
|
262
|
0
|
0
|
|
|
|
|
if (len > 8) return -1; /* Too large */ |
|
263
|
|
|
|
|
|
|
|
|
264
|
0
|
|
|
|
|
|
value = 0; |
|
265
|
0
|
0
|
|
|
|
|
for (i = 0; i < len; i++) { |
|
266
|
0
|
|
|
|
|
|
value = (value << 8) | data[i]; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
0
|
|
|
|
|
|
*out = value; |
|
270
|
0
|
|
|
|
|
|
return 0; |
|
271
|
|
|
|
|
|
|
} |
|
272
|
|
|
|
|
|
|
|
|
273
|
1
|
|
|
|
|
|
int pdfmake_asn1_get_bool(const pdfmake_asn1_node_t *node, int *out) |
|
274
|
|
|
|
|
|
|
{ |
|
275
|
1
|
50
|
|
|
|
|
if (!node || !out) return -1; |
|
|
|
50
|
|
|
|
|
|
|
276
|
1
|
50
|
|
|
|
|
if (node->tag != ASN1_TAG_BOOLEAN) return -1; |
|
277
|
1
|
50
|
|
|
|
|
if (node->length != 1) return -1; |
|
278
|
|
|
|
|
|
|
|
|
279
|
1
|
|
|
|
|
|
*out = (node->data[0] != 0); |
|
280
|
1
|
|
|
|
|
|
return 0; |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
|
|
283
|
15
|
|
|
|
|
|
char *pdfmake_asn1_get_oid_string( |
|
284
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
285
|
|
|
|
|
|
|
const pdfmake_asn1_node_t *node) |
|
286
|
|
|
|
|
|
|
{ |
|
287
|
|
|
|
|
|
|
char buf[256]; |
|
288
|
|
|
|
|
|
|
char *p; |
|
289
|
|
|
|
|
|
|
char *end; |
|
290
|
|
|
|
|
|
|
int first; |
|
291
|
|
|
|
|
|
|
int second; |
|
292
|
|
|
|
|
|
|
size_t i; |
|
293
|
|
|
|
|
|
|
size_t len; |
|
294
|
|
|
|
|
|
|
char *result; |
|
295
|
|
|
|
|
|
|
|
|
296
|
15
|
50
|
|
|
|
|
if (!node || !arena) return NULL; |
|
|
|
50
|
|
|
|
|
|
|
297
|
15
|
50
|
|
|
|
|
if (node->tag != ASN1_TAG_OID) return NULL; |
|
298
|
15
|
50
|
|
|
|
|
if (node->length == 0) return NULL; |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
/* Build string representation */ |
|
301
|
15
|
|
|
|
|
|
p = buf; |
|
302
|
15
|
|
|
|
|
|
end = buf + sizeof(buf) - 1; |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
/* First byte encodes first two components: first * 40 + second */ |
|
305
|
15
|
|
|
|
|
|
first = node->data[0] / 40; |
|
306
|
15
|
|
|
|
|
|
second = node->data[0] % 40; |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
/* Special case for first component >= 2 */ |
|
309
|
15
|
100
|
|
|
|
|
if (first >= 2) { |
|
310
|
6
|
|
|
|
|
|
first = 2; |
|
311
|
6
|
|
|
|
|
|
second = node->data[0] - 80; |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
|
|
314
|
15
|
|
|
|
|
|
p += snprintf(p, end - p, "%d.%d", first, second); |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
/* Remaining components are base-128 encoded */ |
|
317
|
15
|
|
|
|
|
|
i = 1; |
|
318
|
78
|
100
|
|
|
|
|
while (i < node->length && p < end) { |
|
|
|
50
|
|
|
|
|
|
|
319
|
63
|
|
|
|
|
|
uint32_t value = 0; |
|
320
|
90
|
50
|
|
|
|
|
while (i < node->length) { |
|
321
|
90
|
|
|
|
|
|
uint8_t byte = node->data[i++]; |
|
322
|
90
|
|
|
|
|
|
value = (value << 7) | (byte & 0x7F); |
|
323
|
90
|
100
|
|
|
|
|
if (!(byte & 0x80)) break; |
|
324
|
|
|
|
|
|
|
} |
|
325
|
63
|
|
|
|
|
|
p += snprintf(p, end - p, ".%u", value); |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
|
|
328
|
15
|
|
|
|
|
|
len = p - buf; |
|
329
|
15
|
|
|
|
|
|
result = pdfmake_arena_alloc(arena, len + 1); |
|
330
|
15
|
50
|
|
|
|
|
if (result) { |
|
331
|
15
|
|
|
|
|
|
memcpy(result, buf, len + 1); |
|
332
|
|
|
|
|
|
|
} |
|
333
|
15
|
|
|
|
|
|
return result; |
|
334
|
|
|
|
|
|
|
} |
|
335
|
|
|
|
|
|
|
|
|
336
|
12
|
|
|
|
|
|
int pdfmake_asn1_oid_equals( |
|
337
|
|
|
|
|
|
|
const pdfmake_asn1_node_t *node, |
|
338
|
|
|
|
|
|
|
const char *oid_str) |
|
339
|
|
|
|
|
|
|
{ |
|
340
|
|
|
|
|
|
|
uint8_t encoded[64]; |
|
341
|
12
|
|
|
|
|
|
size_t encoded_len = 0; |
|
342
|
|
|
|
|
|
|
const char *p; |
|
343
|
12
|
|
|
|
|
|
int first = -1, second = -1; |
|
344
|
|
|
|
|
|
|
|
|
345
|
12
|
50
|
|
|
|
|
if (!node || !oid_str) return 0; |
|
|
|
50
|
|
|
|
|
|
|
346
|
12
|
50
|
|
|
|
|
if (node->tag != ASN1_TAG_OID) return 0; |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
/* Encode expected OID and compare bytes */ |
|
349
|
12
|
|
|
|
|
|
p = oid_str; |
|
350
|
|
|
|
|
|
|
|
|
351
|
67
|
100
|
|
|
|
|
while (*p && encoded_len < sizeof(encoded)) { |
|
|
|
50
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
/* Parse next component */ |
|
353
|
55
|
|
|
|
|
|
int value = 0; |
|
354
|
145
|
100
|
|
|
|
|
while (*p >= '0' && *p <= '9') { |
|
|
|
50
|
|
|
|
|
|
|
355
|
90
|
|
|
|
|
|
value = value * 10 + (*p - '0'); |
|
356
|
90
|
|
|
|
|
|
p++; |
|
357
|
|
|
|
|
|
|
} |
|
358
|
55
|
100
|
|
|
|
|
if (*p == '.') p++; |
|
359
|
|
|
|
|
|
|
|
|
360
|
55
|
100
|
|
|
|
|
if (first < 0) { |
|
361
|
12
|
|
|
|
|
|
first = value; |
|
362
|
43
|
100
|
|
|
|
|
} else if (second < 0) { |
|
363
|
12
|
|
|
|
|
|
second = value; |
|
364
|
|
|
|
|
|
|
/* Encode first two components */ |
|
365
|
12
|
|
|
|
|
|
encoded[encoded_len++] = first * 40 + second; |
|
366
|
|
|
|
|
|
|
} else { |
|
367
|
|
|
|
|
|
|
/* Encode as base-128 */ |
|
368
|
|
|
|
|
|
|
uint8_t temp[5]; |
|
369
|
31
|
|
|
|
|
|
int temp_len = 0; |
|
370
|
|
|
|
|
|
|
int i; |
|
371
|
|
|
|
|
|
|
do { |
|
372
|
37
|
|
|
|
|
|
temp[temp_len++] = value & 0x7F; |
|
373
|
37
|
|
|
|
|
|
value >>= 7; |
|
374
|
37
|
100
|
|
|
|
|
} while (value > 0); |
|
375
|
|
|
|
|
|
|
|
|
376
|
68
|
100
|
|
|
|
|
for (i = temp_len - 1; i >= 0; i--) { |
|
377
|
37
|
100
|
|
|
|
|
encoded[encoded_len++] = temp[i] | (i > 0 ? 0x80 : 0); |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
12
|
50
|
|
|
|
|
if (encoded_len != node->length) return 0; |
|
383
|
12
|
|
|
|
|
|
return memcmp(encoded, node->data, encoded_len) == 0; |
|
384
|
|
|
|
|
|
|
} |
|
385
|
|
|
|
|
|
|
|
|
386
|
6
|
|
|
|
|
|
char *pdfmake_asn1_get_string( |
|
387
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
388
|
|
|
|
|
|
|
const pdfmake_asn1_node_t *node) |
|
389
|
|
|
|
|
|
|
{ |
|
390
|
|
|
|
|
|
|
char *result; |
|
391
|
|
|
|
|
|
|
|
|
392
|
6
|
50
|
|
|
|
|
if (!node || !arena) return NULL; |
|
|
|
50
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
/* Accept various string types */ |
|
395
|
6
|
50
|
|
|
|
|
switch (node->tag) { |
|
396
|
6
|
|
|
|
|
|
case ASN1_TAG_UTF8STRING: |
|
397
|
|
|
|
|
|
|
case ASN1_TAG_PRINTABLESTRING: |
|
398
|
|
|
|
|
|
|
case ASN1_TAG_IA5STRING: |
|
399
|
|
|
|
|
|
|
case ASN1_TAG_T61STRING: |
|
400
|
|
|
|
|
|
|
case ASN1_TAG_VISIBLESTRING: |
|
401
|
|
|
|
|
|
|
case ASN1_TAG_NUMERICSTRING: |
|
402
|
|
|
|
|
|
|
case ASN1_TAG_BMPSTRING: |
|
403
|
|
|
|
|
|
|
case ASN1_TAG_UNIVERSALSTRING: |
|
404
|
6
|
|
|
|
|
|
break; |
|
405
|
0
|
|
|
|
|
|
default: |
|
406
|
0
|
|
|
|
|
|
return NULL; |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
/* For BMPString, convert from UCS-2 to UTF-8 */ |
|
410
|
6
|
50
|
|
|
|
|
if (node->tag == ASN1_TAG_BMPSTRING) { |
|
411
|
|
|
|
|
|
|
/* Simple conversion assuming ASCII subset */ |
|
412
|
0
|
|
|
|
|
|
size_t out_len = node->length / 2; |
|
413
|
|
|
|
|
|
|
size_t i; |
|
414
|
0
|
|
|
|
|
|
result = pdfmake_arena_alloc(arena, out_len + 1); |
|
415
|
0
|
0
|
|
|
|
|
if (result) { |
|
416
|
0
|
0
|
|
|
|
|
for (i = 0; i < out_len; i++) { |
|
417
|
0
|
|
|
|
|
|
uint16_t ch = (node->data[i*2] << 8) | node->data[i*2 + 1]; |
|
418
|
0
|
0
|
|
|
|
|
result[i] = (ch < 128) ? ch : '?'; |
|
419
|
|
|
|
|
|
|
} |
|
420
|
0
|
|
|
|
|
|
result[out_len] = '\0'; |
|
421
|
|
|
|
|
|
|
} |
|
422
|
0
|
|
|
|
|
|
return result; |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
/* Copy as-is for other string types */ |
|
426
|
6
|
|
|
|
|
|
result = pdfmake_arena_alloc(arena, node->length + 1); |
|
427
|
6
|
50
|
|
|
|
|
if (result) { |
|
428
|
6
|
|
|
|
|
|
memcpy(result, node->data, node->length); |
|
429
|
6
|
|
|
|
|
|
result[node->length] = '\0'; |
|
430
|
|
|
|
|
|
|
} |
|
431
|
6
|
|
|
|
|
|
return result; |
|
432
|
|
|
|
|
|
|
} |
|
433
|
|
|
|
|
|
|
|
|
434
|
2
|
|
|
|
|
|
int pdfmake_asn1_get_time(const pdfmake_asn1_node_t *node, int64_t *out) |
|
435
|
|
|
|
|
|
|
{ |
|
436
|
|
|
|
|
|
|
struct tm tm; |
|
437
|
|
|
|
|
|
|
const char *s; |
|
438
|
|
|
|
|
|
|
size_t len; |
|
439
|
|
|
|
|
|
|
|
|
440
|
2
|
50
|
|
|
|
|
if (!node || !out) return -1; |
|
|
|
50
|
|
|
|
|
|
|
441
|
2
|
50
|
|
|
|
|
if (node->tag != ASN1_TAG_UTCTIME && node->tag != ASN1_TAG_GENERALIZEDTIME) { |
|
|
|
0
|
|
|
|
|
|
|
442
|
0
|
|
|
|
|
|
return -1; |
|
443
|
|
|
|
|
|
|
} |
|
444
|
|
|
|
|
|
|
|
|
445
|
2
|
|
|
|
|
|
memset(&tm, 0, sizeof(tm)); |
|
446
|
2
|
|
|
|
|
|
s = (const char *)node->data; |
|
447
|
2
|
|
|
|
|
|
len = node->length; |
|
448
|
|
|
|
|
|
|
|
|
449
|
2
|
50
|
|
|
|
|
if (node->tag == ASN1_TAG_UTCTIME) { |
|
450
|
|
|
|
|
|
|
/* YYMMDDhhmmssZ or YYMMDDhhmmss+hhmm */ |
|
451
|
2
|
50
|
|
|
|
|
if (len < 12) return -1; |
|
452
|
|
|
|
|
|
|
|
|
453
|
2
|
|
|
|
|
|
tm.tm_year = (s[0] - '0') * 10 + (s[1] - '0'); |
|
454
|
2
|
50
|
|
|
|
|
if (tm.tm_year < 50) tm.tm_year += 100; /* 2000-2049 */ |
|
455
|
2
|
|
|
|
|
|
tm.tm_mon = (s[2] - '0') * 10 + (s[3] - '0') - 1; |
|
456
|
2
|
|
|
|
|
|
tm.tm_mday = (s[4] - '0') * 10 + (s[5] - '0'); |
|
457
|
2
|
|
|
|
|
|
tm.tm_hour = (s[6] - '0') * 10 + (s[7] - '0'); |
|
458
|
2
|
|
|
|
|
|
tm.tm_min = (s[8] - '0') * 10 + (s[9] - '0'); |
|
459
|
2
|
|
|
|
|
|
tm.tm_sec = (s[10] - '0') * 10 + (s[11] - '0'); |
|
460
|
|
|
|
|
|
|
} else { |
|
461
|
|
|
|
|
|
|
/* GeneralizedTime: YYYYMMDDhhmmssZ */ |
|
462
|
0
|
0
|
|
|
|
|
if (len < 14) return -1; |
|
463
|
|
|
|
|
|
|
|
|
464
|
0
|
|
|
|
|
|
tm.tm_year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + |
|
465
|
0
|
|
|
|
|
|
(s[2] - '0') * 10 + (s[3] - '0') - 1900; |
|
466
|
0
|
|
|
|
|
|
tm.tm_mon = (s[4] - '0') * 10 + (s[5] - '0') - 1; |
|
467
|
0
|
|
|
|
|
|
tm.tm_mday = (s[6] - '0') * 10 + (s[7] - '0'); |
|
468
|
0
|
|
|
|
|
|
tm.tm_hour = (s[8] - '0') * 10 + (s[9] - '0'); |
|
469
|
0
|
|
|
|
|
|
tm.tm_min = (s[10] - '0') * 10 + (s[11] - '0'); |
|
470
|
0
|
|
|
|
|
|
tm.tm_sec = (s[12] - '0') * 10 + (s[13] - '0'); |
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
/* Convert to Unix timestamp (assume UTC) */ |
|
474
|
2
|
|
|
|
|
|
tm.tm_isdst = 0; |
|
475
|
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
477
|
|
|
|
|
|
|
*out = _mkgmtime(&tm); |
|
478
|
|
|
|
|
|
|
#else |
|
479
|
2
|
|
|
|
|
|
*out = timegm(&tm); |
|
480
|
|
|
|
|
|
|
#endif |
|
481
|
|
|
|
|
|
|
|
|
482
|
2
|
|
|
|
|
|
return 0; |
|
483
|
|
|
|
|
|
|
} |
|
484
|
|
|
|
|
|
|
|
|
485
|
2
|
|
|
|
|
|
int pdfmake_asn1_get_bit_string( |
|
486
|
|
|
|
|
|
|
const pdfmake_asn1_node_t *node, |
|
487
|
|
|
|
|
|
|
const uint8_t **bits, |
|
488
|
|
|
|
|
|
|
size_t *bit_count) |
|
489
|
|
|
|
|
|
|
{ |
|
490
|
|
|
|
|
|
|
uint8_t unused; |
|
491
|
|
|
|
|
|
|
|
|
492
|
2
|
50
|
|
|
|
|
if (!node || !bits || !bit_count) return -1; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
493
|
2
|
50
|
|
|
|
|
if (node->tag != ASN1_TAG_BIT_STRING) return -1; |
|
494
|
2
|
50
|
|
|
|
|
if (node->length < 1) return -1; |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
/* First byte is number of unused bits in last byte */ |
|
497
|
2
|
|
|
|
|
|
unused = node->data[0]; |
|
498
|
2
|
50
|
|
|
|
|
if (unused > 7) return -1; |
|
499
|
|
|
|
|
|
|
|
|
500
|
2
|
|
|
|
|
|
*bits = node->data + 1; |
|
501
|
2
|
|
|
|
|
|
*bit_count = (node->length - 1) * 8 - unused; |
|
502
|
|
|
|
|
|
|
|
|
503
|
2
|
|
|
|
|
|
return 0; |
|
504
|
|
|
|
|
|
|
} |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
/*============================================================================ |
|
507
|
|
|
|
|
|
|
* Encoding API |
|
508
|
|
|
|
|
|
|
*==========================================================================*/ |
|
509
|
|
|
|
|
|
|
|
|
510
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_encoder_init( |
|
511
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
512
|
|
|
|
|
|
|
pdfmake_arena_t *arena, |
|
513
|
|
|
|
|
|
|
pdfmake_buf_t *buf) |
|
514
|
|
|
|
|
|
|
{ |
|
515
|
0
|
0
|
|
|
|
|
if (!enc || !arena || !buf) return PDFMAKE_EINVAL; |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
|
|
517
|
0
|
|
|
|
|
|
enc->arena = arena; |
|
518
|
0
|
|
|
|
|
|
enc->buf = buf; |
|
519
|
0
|
|
|
|
|
|
return PDFMAKE_OK; |
|
520
|
|
|
|
|
|
|
} |
|
521
|
|
|
|
|
|
|
|
|
522
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_header( |
|
523
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
524
|
|
|
|
|
|
|
uint8_t tag, |
|
525
|
|
|
|
|
|
|
size_t length) |
|
526
|
|
|
|
|
|
|
{ |
|
527
|
0
|
|
|
|
|
|
pdfmake_err_t err = pdfmake_buf_append_byte(enc->buf, tag); |
|
528
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
529
|
0
|
|
|
|
|
|
return write_length(enc->buf, length); |
|
530
|
|
|
|
|
|
|
} |
|
531
|
|
|
|
|
|
|
|
|
532
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_null(pdfmake_asn1_encoder_t *enc) |
|
533
|
|
|
|
|
|
|
{ |
|
534
|
0
|
|
|
|
|
|
pdfmake_err_t err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_NULL); |
|
535
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
536
|
0
|
|
|
|
|
|
return pdfmake_buf_append_byte(enc->buf, 0x00); |
|
537
|
|
|
|
|
|
|
} |
|
538
|
|
|
|
|
|
|
|
|
539
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_bool(pdfmake_asn1_encoder_t *enc, int value) |
|
540
|
|
|
|
|
|
|
{ |
|
541
|
0
|
|
|
|
|
|
pdfmake_err_t err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_BOOLEAN); |
|
542
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
543
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(enc->buf, 0x01); |
|
544
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
545
|
0
|
0
|
|
|
|
|
return pdfmake_buf_append_byte(enc->buf, value ? 0xFF : 0x00); |
|
546
|
|
|
|
|
|
|
} |
|
547
|
|
|
|
|
|
|
|
|
548
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_int64(pdfmake_asn1_encoder_t *enc, int64_t value) |
|
549
|
|
|
|
|
|
|
{ |
|
550
|
|
|
|
|
|
|
uint8_t bytes[9]; |
|
551
|
0
|
|
|
|
|
|
int len = 0; |
|
552
|
|
|
|
|
|
|
pdfmake_err_t err; |
|
553
|
|
|
|
|
|
|
|
|
554
|
0
|
0
|
|
|
|
|
if (value == 0) { |
|
555
|
0
|
|
|
|
|
|
bytes[0] = 0; |
|
556
|
0
|
|
|
|
|
|
len = 1; |
|
557
|
0
|
0
|
|
|
|
|
} else if (value > 0) { |
|
558
|
|
|
|
|
|
|
/* Positive: encode as minimal big-endian, add leading 0 if high bit set */ |
|
559
|
0
|
|
|
|
|
|
uint64_t v = value; |
|
560
|
0
|
0
|
|
|
|
|
while (v > 0) { |
|
561
|
0
|
|
|
|
|
|
bytes[8 - len++] = v & 0xFF; |
|
562
|
0
|
|
|
|
|
|
v >>= 8; |
|
563
|
|
|
|
|
|
|
} |
|
564
|
0
|
|
|
|
|
|
memmove(bytes, bytes + 9 - len, len); |
|
565
|
|
|
|
|
|
|
|
|
566
|
0
|
0
|
|
|
|
|
if (bytes[0] & 0x80) { |
|
567
|
0
|
|
|
|
|
|
memmove(bytes + 1, bytes, len); |
|
568
|
0
|
|
|
|
|
|
bytes[0] = 0; |
|
569
|
0
|
|
|
|
|
|
len++; |
|
570
|
|
|
|
|
|
|
} |
|
571
|
|
|
|
|
|
|
} else { |
|
572
|
|
|
|
|
|
|
/* Negative: encode as two's complement */ |
|
573
|
0
|
|
|
|
|
|
uint64_t v = (uint64_t)value; |
|
574
|
0
|
|
|
|
|
|
int all_ff = 1; |
|
575
|
|
|
|
|
|
|
int i; |
|
576
|
0
|
0
|
|
|
|
|
for (i = 0; i < 8; i++) { |
|
577
|
0
|
|
|
|
|
|
uint8_t b = (v >> (56 - i * 8)) & 0xFF; |
|
578
|
0
|
0
|
|
|
|
|
if (all_ff && b == 0xFF && i < 7) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
579
|
0
|
|
|
|
|
|
uint8_t next = (v >> (48 - i * 8)) & 0xFF; |
|
580
|
0
|
0
|
|
|
|
|
if (next & 0x80) continue; /* Can skip this 0xFF */ |
|
581
|
|
|
|
|
|
|
} |
|
582
|
0
|
|
|
|
|
|
all_ff = 0; |
|
583
|
0
|
|
|
|
|
|
bytes[len++] = b; |
|
584
|
|
|
|
|
|
|
} |
|
585
|
|
|
|
|
|
|
} |
|
586
|
|
|
|
|
|
|
|
|
587
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_INTEGER); |
|
588
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
589
|
0
|
|
|
|
|
|
err = write_length(enc->buf, len); |
|
590
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
591
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, bytes, len); |
|
592
|
|
|
|
|
|
|
} |
|
593
|
|
|
|
|
|
|
|
|
594
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_uint64(pdfmake_asn1_encoder_t *enc, uint64_t value) |
|
595
|
|
|
|
|
|
|
{ |
|
596
|
|
|
|
|
|
|
uint8_t bytes[9]; |
|
597
|
0
|
|
|
|
|
|
int len = 0; |
|
598
|
|
|
|
|
|
|
pdfmake_err_t err; |
|
599
|
|
|
|
|
|
|
|
|
600
|
0
|
0
|
|
|
|
|
if (value == 0) { |
|
601
|
0
|
|
|
|
|
|
bytes[0] = 0; |
|
602
|
0
|
|
|
|
|
|
len = 1; |
|
603
|
|
|
|
|
|
|
} else { |
|
604
|
|
|
|
|
|
|
/* Encode as minimal big-endian */ |
|
605
|
0
|
|
|
|
|
|
uint64_t v = value; |
|
606
|
0
|
0
|
|
|
|
|
while (v > 0) { |
|
607
|
0
|
|
|
|
|
|
bytes[8 - len++] = v & 0xFF; |
|
608
|
0
|
|
|
|
|
|
v >>= 8; |
|
609
|
|
|
|
|
|
|
} |
|
610
|
0
|
|
|
|
|
|
memmove(bytes, bytes + 9 - len, len); |
|
611
|
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
/* Add leading 0 if high bit set (to indicate positive) */ |
|
613
|
0
|
0
|
|
|
|
|
if (bytes[0] & 0x80) { |
|
614
|
0
|
|
|
|
|
|
memmove(bytes + 1, bytes, len); |
|
615
|
0
|
|
|
|
|
|
bytes[0] = 0; |
|
616
|
0
|
|
|
|
|
|
len++; |
|
617
|
|
|
|
|
|
|
} |
|
618
|
|
|
|
|
|
|
} |
|
619
|
|
|
|
|
|
|
|
|
620
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_INTEGER); |
|
621
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
622
|
0
|
|
|
|
|
|
err = write_length(enc->buf, len); |
|
623
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
624
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, bytes, len); |
|
625
|
|
|
|
|
|
|
} |
|
626
|
|
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_integer( |
|
628
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
629
|
|
|
|
|
|
|
const uint8_t *bytes, |
|
630
|
|
|
|
|
|
|
size_t len) |
|
631
|
|
|
|
|
|
|
{ |
|
632
|
|
|
|
|
|
|
int need_zero; |
|
633
|
|
|
|
|
|
|
pdfmake_err_t err; |
|
634
|
|
|
|
|
|
|
|
|
635
|
0
|
0
|
|
|
|
|
if (!enc || !bytes) return PDFMAKE_EINVAL; |
|
|
|
0
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
/* Skip leading zeros but keep at least one byte */ |
|
638
|
0
|
0
|
|
|
|
|
while (len > 1 && bytes[0] == 0 && !(bytes[1] & 0x80)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
639
|
0
|
|
|
|
|
|
bytes++; |
|
640
|
0
|
|
|
|
|
|
len--; |
|
641
|
|
|
|
|
|
|
} |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
/* Add leading zero if high bit set (to indicate positive) */ |
|
644
|
0
|
|
|
|
|
|
need_zero = (bytes[0] & 0x80) != 0; |
|
645
|
|
|
|
|
|
|
|
|
646
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_INTEGER); |
|
647
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
648
|
0
|
0
|
|
|
|
|
err = write_length(enc->buf, len + (need_zero ? 1 : 0)); |
|
649
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
650
|
|
|
|
|
|
|
|
|
651
|
0
|
0
|
|
|
|
|
if (need_zero) { |
|
652
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(enc->buf, 0x00); |
|
653
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
654
|
|
|
|
|
|
|
} |
|
655
|
|
|
|
|
|
|
|
|
656
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, bytes, len); |
|
657
|
|
|
|
|
|
|
} |
|
658
|
|
|
|
|
|
|
|
|
659
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_oid( |
|
660
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
661
|
|
|
|
|
|
|
const char *oid_str) |
|
662
|
|
|
|
|
|
|
{ |
|
663
|
|
|
|
|
|
|
uint8_t encoded[64]; |
|
664
|
0
|
|
|
|
|
|
size_t encoded_len = 0; |
|
665
|
|
|
|
|
|
|
const char *p; |
|
666
|
0
|
|
|
|
|
|
int first = -1, second = -1; |
|
667
|
|
|
|
|
|
|
pdfmake_err_t err; |
|
668
|
|
|
|
|
|
|
|
|
669
|
0
|
0
|
|
|
|
|
if (!enc || !oid_str) return PDFMAKE_EINVAL; |
|
|
|
0
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
|
|
671
|
0
|
|
|
|
|
|
p = oid_str; |
|
672
|
|
|
|
|
|
|
|
|
673
|
0
|
0
|
|
|
|
|
while (*p && encoded_len < sizeof(encoded)) { |
|
|
|
0
|
|
|
|
|
|
|
674
|
0
|
|
|
|
|
|
int value = 0; |
|
675
|
0
|
0
|
|
|
|
|
while (*p >= '0' && *p <= '9') { |
|
|
|
0
|
|
|
|
|
|
|
676
|
0
|
|
|
|
|
|
value = value * 10 + (*p - '0'); |
|
677
|
0
|
|
|
|
|
|
p++; |
|
678
|
|
|
|
|
|
|
} |
|
679
|
0
|
0
|
|
|
|
|
if (*p == '.') p++; |
|
680
|
|
|
|
|
|
|
|
|
681
|
0
|
0
|
|
|
|
|
if (first < 0) { |
|
682
|
0
|
|
|
|
|
|
first = value; |
|
683
|
0
|
0
|
|
|
|
|
} else if (second < 0) { |
|
684
|
0
|
|
|
|
|
|
second = value; |
|
685
|
0
|
|
|
|
|
|
encoded[encoded_len++] = first * 40 + second; |
|
686
|
|
|
|
|
|
|
} else { |
|
687
|
|
|
|
|
|
|
/* Encode as base-128 */ |
|
688
|
|
|
|
|
|
|
uint8_t temp[5]; |
|
689
|
0
|
|
|
|
|
|
int temp_len = 0; |
|
690
|
|
|
|
|
|
|
int i; |
|
691
|
|
|
|
|
|
|
do { |
|
692
|
0
|
|
|
|
|
|
temp[temp_len++] = value & 0x7F; |
|
693
|
0
|
|
|
|
|
|
value >>= 7; |
|
694
|
0
|
0
|
|
|
|
|
} while (value > 0); |
|
695
|
|
|
|
|
|
|
|
|
696
|
0
|
0
|
|
|
|
|
for (i = temp_len - 1; i >= 0; i--) { |
|
697
|
0
|
0
|
|
|
|
|
if (encoded_len >= sizeof(encoded)) return PDFMAKE_EINVAL; |
|
698
|
0
|
0
|
|
|
|
|
encoded[encoded_len++] = temp[i] | (i > 0 ? 0x80 : 0); |
|
699
|
|
|
|
|
|
|
} |
|
700
|
|
|
|
|
|
|
} |
|
701
|
|
|
|
|
|
|
} |
|
702
|
|
|
|
|
|
|
|
|
703
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_OID); |
|
704
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
705
|
0
|
|
|
|
|
|
err = write_length(enc->buf, encoded_len); |
|
706
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
707
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, encoded, encoded_len); |
|
708
|
|
|
|
|
|
|
} |
|
709
|
|
|
|
|
|
|
|
|
710
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_octet_string( |
|
711
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
712
|
|
|
|
|
|
|
const uint8_t *data, |
|
713
|
|
|
|
|
|
|
size_t len) |
|
714
|
|
|
|
|
|
|
{ |
|
715
|
0
|
|
|
|
|
|
pdfmake_err_t err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_OCTET_STRING); |
|
716
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
717
|
0
|
|
|
|
|
|
err = write_length(enc->buf, len); |
|
718
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
719
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, data, len); |
|
720
|
|
|
|
|
|
|
} |
|
721
|
|
|
|
|
|
|
|
|
722
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_bit_string( |
|
723
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
724
|
|
|
|
|
|
|
const uint8_t *bits, |
|
725
|
|
|
|
|
|
|
size_t bit_count) |
|
726
|
|
|
|
|
|
|
{ |
|
727
|
0
|
|
|
|
|
|
size_t byte_count = (bit_count + 7) / 8; |
|
728
|
0
|
|
|
|
|
|
uint8_t unused = (byte_count * 8 - bit_count) % 8; |
|
729
|
|
|
|
|
|
|
|
|
730
|
0
|
|
|
|
|
|
pdfmake_err_t err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_BIT_STRING); |
|
731
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
732
|
0
|
|
|
|
|
|
err = write_length(enc->buf, byte_count + 1); |
|
733
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
734
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(enc->buf, unused); |
|
735
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
736
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, bits, byte_count); |
|
737
|
|
|
|
|
|
|
} |
|
738
|
|
|
|
|
|
|
|
|
739
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_utf8_string( |
|
740
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
741
|
|
|
|
|
|
|
const char *str) |
|
742
|
|
|
|
|
|
|
{ |
|
743
|
0
|
|
|
|
|
|
size_t len = strlen(str); |
|
744
|
0
|
|
|
|
|
|
pdfmake_err_t err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_UTF8STRING); |
|
745
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
746
|
0
|
|
|
|
|
|
err = write_length(enc->buf, len); |
|
747
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
748
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, (const uint8_t *)str, len); |
|
749
|
|
|
|
|
|
|
} |
|
750
|
|
|
|
|
|
|
|
|
751
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_printable_string( |
|
752
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
753
|
|
|
|
|
|
|
const char *str) |
|
754
|
|
|
|
|
|
|
{ |
|
755
|
0
|
|
|
|
|
|
size_t len = strlen(str); |
|
756
|
0
|
|
|
|
|
|
pdfmake_err_t err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_PRINTABLESTRING); |
|
757
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
758
|
0
|
|
|
|
|
|
err = write_length(enc->buf, len); |
|
759
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
760
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, (const uint8_t *)str, len); |
|
761
|
|
|
|
|
|
|
} |
|
762
|
|
|
|
|
|
|
|
|
763
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_ia5_string( |
|
764
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
765
|
|
|
|
|
|
|
const char *str) |
|
766
|
|
|
|
|
|
|
{ |
|
767
|
0
|
|
|
|
|
|
size_t len = strlen(str); |
|
768
|
0
|
|
|
|
|
|
pdfmake_err_t err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_IA5STRING); |
|
769
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
770
|
0
|
|
|
|
|
|
err = write_length(enc->buf, len); |
|
771
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
772
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, (const uint8_t *)str, len); |
|
773
|
|
|
|
|
|
|
} |
|
774
|
|
|
|
|
|
|
|
|
775
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_utc_time( |
|
776
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
777
|
|
|
|
|
|
|
int64_t timestamp) |
|
778
|
|
|
|
|
|
|
{ |
|
779
|
0
|
|
|
|
|
|
time_t t = (time_t)timestamp; |
|
780
|
0
|
|
|
|
|
|
struct tm *tm = gmtime(&t); |
|
781
|
|
|
|
|
|
|
char buf[16]; |
|
782
|
|
|
|
|
|
|
int year; |
|
783
|
|
|
|
|
|
|
pdfmake_err_t err; |
|
784
|
|
|
|
|
|
|
|
|
785
|
0
|
0
|
|
|
|
|
if (!tm) return PDFMAKE_EINVAL; |
|
786
|
|
|
|
|
|
|
|
|
787
|
0
|
|
|
|
|
|
year = tm->tm_year % 100; /* Two-digit year */ |
|
788
|
0
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "%02d%02d%02d%02d%02d%02dZ", |
|
789
|
0
|
|
|
|
|
|
year, tm->tm_mon + 1, tm->tm_mday, |
|
790
|
|
|
|
|
|
|
tm->tm_hour, tm->tm_min, tm->tm_sec); |
|
791
|
|
|
|
|
|
|
|
|
792
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_UTCTIME); |
|
793
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
794
|
0
|
|
|
|
|
|
err = write_length(enc->buf, 13); |
|
795
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
796
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, (const uint8_t *)buf, 13); |
|
797
|
|
|
|
|
|
|
} |
|
798
|
|
|
|
|
|
|
|
|
799
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_generalized_time( |
|
800
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
801
|
|
|
|
|
|
|
int64_t timestamp) |
|
802
|
|
|
|
|
|
|
{ |
|
803
|
0
|
|
|
|
|
|
time_t t = (time_t)timestamp; |
|
804
|
0
|
|
|
|
|
|
struct tm *tm = gmtime(&t); |
|
805
|
|
|
|
|
|
|
char buf[20]; |
|
806
|
|
|
|
|
|
|
pdfmake_err_t err; |
|
807
|
|
|
|
|
|
|
|
|
808
|
0
|
0
|
|
|
|
|
if (!tm) return PDFMAKE_EINVAL; |
|
809
|
|
|
|
|
|
|
|
|
810
|
0
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ", |
|
811
|
0
|
|
|
|
|
|
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
|
812
|
|
|
|
|
|
|
tm->tm_hour, tm->tm_min, tm->tm_sec); |
|
813
|
|
|
|
|
|
|
|
|
814
|
0
|
|
|
|
|
|
err = pdfmake_buf_append_byte(enc->buf, ASN1_TAG_GENERALIZEDTIME); |
|
815
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
816
|
0
|
|
|
|
|
|
err = write_length(enc->buf, 15); |
|
817
|
0
|
0
|
|
|
|
|
if (err != PDFMAKE_OK) return err; |
|
818
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, (const uint8_t *)buf, 15); |
|
819
|
|
|
|
|
|
|
} |
|
820
|
|
|
|
|
|
|
|
|
821
|
0
|
|
|
|
|
|
size_t pdfmake_asn1_begin_sequence(pdfmake_asn1_encoder_t *enc) |
|
822
|
|
|
|
|
|
|
{ |
|
823
|
0
|
|
|
|
|
|
size_t pos = enc->buf->len; |
|
824
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, ASN1_TAG_SEQUENCE | ASN1_CONSTRUCTED); |
|
825
|
|
|
|
|
|
|
/* Reserve 4 bytes for length (will be fixed up later) */ |
|
826
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x84); |
|
827
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
828
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
829
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
830
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
831
|
0
|
|
|
|
|
|
return pos; |
|
832
|
|
|
|
|
|
|
} |
|
833
|
|
|
|
|
|
|
|
|
834
|
0
|
|
|
|
|
|
size_t pdfmake_asn1_begin_set(pdfmake_asn1_encoder_t *enc) |
|
835
|
|
|
|
|
|
|
{ |
|
836
|
0
|
|
|
|
|
|
size_t pos = enc->buf->len; |
|
837
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, ASN1_TAG_SET | ASN1_CONSTRUCTED); |
|
838
|
|
|
|
|
|
|
/* Reserve 4 bytes for length */ |
|
839
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x84); |
|
840
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
841
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
842
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
843
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
844
|
0
|
|
|
|
|
|
return pos; |
|
845
|
|
|
|
|
|
|
} |
|
846
|
|
|
|
|
|
|
|
|
847
|
0
|
|
|
|
|
|
size_t pdfmake_asn1_begin_context( |
|
848
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
849
|
|
|
|
|
|
|
uint8_t tag_number, |
|
850
|
|
|
|
|
|
|
int constructed) |
|
851
|
|
|
|
|
|
|
{ |
|
852
|
0
|
|
|
|
|
|
size_t pos = enc->buf->len; |
|
853
|
0
|
|
|
|
|
|
uint8_t tag = ASN1_CLASS_CONTEXT | tag_number; |
|
854
|
0
|
0
|
|
|
|
|
if (constructed) tag |= ASN1_CONSTRUCTED; |
|
855
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, tag); |
|
856
|
|
|
|
|
|
|
/* Reserve 4 bytes for length */ |
|
857
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x84); |
|
858
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
859
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
860
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
861
|
0
|
|
|
|
|
|
pdfmake_buf_append_byte(enc->buf, 0x00); |
|
862
|
0
|
|
|
|
|
|
return pos; |
|
863
|
|
|
|
|
|
|
} |
|
864
|
|
|
|
|
|
|
|
|
865
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_end_constructed( |
|
866
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
867
|
|
|
|
|
|
|
size_t start_pos) |
|
868
|
|
|
|
|
|
|
{ |
|
869
|
|
|
|
|
|
|
/* The begin_* helpers reserved 5 bytes for the length prefix |
|
870
|
|
|
|
|
|
|
* (0x84 + 4 length bytes). For strict DER (required by CMS |
|
871
|
|
|
|
|
|
|
* verifiers) the prefix must use the shortest form: |
|
872
|
|
|
|
|
|
|
* length < 128 → 1 byte |
|
873
|
|
|
|
|
|
|
* length <= 0xFF → 2 bytes (0x81 + 1) |
|
874
|
|
|
|
|
|
|
* length <= 0xFFFF → 3 bytes (0x82 + 2) |
|
875
|
|
|
|
|
|
|
* length <= 0xFFFFFF → 4 bytes (0x83 + 3) |
|
876
|
|
|
|
|
|
|
* otherwise → 5 bytes (0x84 + 4) |
|
877
|
|
|
|
|
|
|
* After computing the content length we rewrite the header and, if |
|
878
|
|
|
|
|
|
|
* the new header is shorter, shift content left to close the gap. */ |
|
879
|
|
|
|
|
|
|
|
|
880
|
0
|
|
|
|
|
|
size_t content_start = start_pos + 6; /* tag + 5 reserved length bytes */ |
|
881
|
0
|
|
|
|
|
|
size_t content_len = enc->buf->len - content_start; |
|
882
|
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
/* Determine minimum length encoding. */ |
|
884
|
|
|
|
|
|
|
int header_len_bytes; /* bytes following the tag (len-of-len + len) */ |
|
885
|
0
|
|
|
|
|
|
int reserved = 5; |
|
886
|
|
|
|
|
|
|
int shift; |
|
887
|
|
|
|
|
|
|
uint8_t *base; |
|
888
|
|
|
|
|
|
|
uint8_t *len_start; |
|
889
|
|
|
|
|
|
|
|
|
890
|
0
|
0
|
|
|
|
|
if (content_len < 0x80) header_len_bytes = 1; |
|
891
|
0
|
0
|
|
|
|
|
else if (content_len <= 0xFF) header_len_bytes = 2; |
|
892
|
0
|
0
|
|
|
|
|
else if (content_len <= 0xFFFF) header_len_bytes = 3; |
|
893
|
0
|
0
|
|
|
|
|
else if (content_len <= 0xFFFFFF) header_len_bytes = 4; |
|
894
|
0
|
|
|
|
|
|
else header_len_bytes = 5; |
|
895
|
|
|
|
|
|
|
|
|
896
|
0
|
|
|
|
|
|
shift = reserved - header_len_bytes; |
|
897
|
|
|
|
|
|
|
|
|
898
|
0
|
|
|
|
|
|
base = enc->buf->data + start_pos; |
|
899
|
0
|
|
|
|
|
|
len_start = base + 1; |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
/* If the minimum encoding is shorter, slide the content bytes left |
|
902
|
|
|
|
|
|
|
* by `shift` bytes and decrement the buffer length. */ |
|
903
|
0
|
0
|
|
|
|
|
if (shift > 0 && content_len > 0) { |
|
|
|
0
|
|
|
|
|
|
|
904
|
0
|
|
|
|
|
|
memmove(base + 1 + header_len_bytes, |
|
905
|
0
|
|
|
|
|
|
base + 1 + reserved, |
|
906
|
|
|
|
|
|
|
content_len); |
|
907
|
0
|
|
|
|
|
|
enc->buf->len -= (size_t)shift; |
|
908
|
0
|
0
|
|
|
|
|
} else if (shift > 0) { |
|
909
|
0
|
|
|
|
|
|
enc->buf->len -= (size_t)shift; |
|
910
|
|
|
|
|
|
|
} |
|
911
|
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
/* Write the new length header. */ |
|
913
|
0
|
0
|
|
|
|
|
if (header_len_bytes == 1) { |
|
914
|
0
|
|
|
|
|
|
len_start[0] = (uint8_t)content_len; |
|
915
|
|
|
|
|
|
|
} else { |
|
916
|
|
|
|
|
|
|
int i; |
|
917
|
0
|
|
|
|
|
|
len_start[0] = (uint8_t)(0x80 | (header_len_bytes - 1)); |
|
918
|
0
|
0
|
|
|
|
|
for (i = 1; i < header_len_bytes; i++) { |
|
919
|
0
|
|
|
|
|
|
int shift_bits = (header_len_bytes - 1 - i) * 8; |
|
920
|
0
|
|
|
|
|
|
len_start[i] = (uint8_t)((content_len >> shift_bits) & 0xFF); |
|
921
|
|
|
|
|
|
|
} |
|
922
|
|
|
|
|
|
|
} |
|
923
|
|
|
|
|
|
|
|
|
924
|
0
|
|
|
|
|
|
return PDFMAKE_OK; |
|
925
|
|
|
|
|
|
|
} |
|
926
|
|
|
|
|
|
|
|
|
927
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_asn1_write_raw( |
|
928
|
|
|
|
|
|
|
pdfmake_asn1_encoder_t *enc, |
|
929
|
|
|
|
|
|
|
const uint8_t *data, |
|
930
|
|
|
|
|
|
|
size_t len) |
|
931
|
|
|
|
|
|
|
{ |
|
932
|
0
|
|
|
|
|
|
return pdfmake_buf_append(enc->buf, data, len); |
|
933
|
|
|
|
|
|
|
} |