/src/nss-nspr/nss/lib/util/derenc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | #include "secder.h" |
6 | | #include "secerr.h" |
7 | | |
8 | | #if 0 |
9 | | /* |
10 | | * Generic templates for individual/simple items. |
11 | | */ |
12 | | |
13 | | DERTemplate SECAnyTemplate[] = { |
14 | | { DER_ANY, |
15 | | 0, NULL, sizeof(SECItem) } |
16 | | }; |
17 | | |
18 | | DERTemplate SECBitStringTemplate[] = { |
19 | | { DER_BIT_STRING, |
20 | | 0, NULL, sizeof(SECItem) } |
21 | | }; |
22 | | |
23 | | DERTemplate SECBooleanTemplate[] = { |
24 | | { DER_BOOLEAN, |
25 | | 0, NULL, sizeof(SECItem) } |
26 | | }; |
27 | | |
28 | | DERTemplate SECIA5StringTemplate[] = { |
29 | | { DER_IA5_STRING, |
30 | | 0, NULL, sizeof(SECItem) } |
31 | | }; |
32 | | |
33 | | DERTemplate SECIntegerTemplate[] = { |
34 | | { DER_INTEGER, |
35 | | 0, NULL, sizeof(SECItem) } |
36 | | }; |
37 | | |
38 | | DERTemplate SECNullTemplate[] = { |
39 | | { DER_NULL, |
40 | | 0, NULL, sizeof(SECItem) } |
41 | | }; |
42 | | |
43 | | DERTemplate SECObjectIDTemplate[] = { |
44 | | { DER_OBJECT_ID, |
45 | | 0, NULL, sizeof(SECItem) } |
46 | | }; |
47 | | |
48 | | DERTemplate SECOctetStringTemplate[] = { |
49 | | { DER_OCTET_STRING, |
50 | | 0, NULL, sizeof(SECItem) } |
51 | | }; |
52 | | |
53 | | DERTemplate SECPrintableStringTemplate[] = { |
54 | | { DER_PRINTABLE_STRING, |
55 | | 0, NULL, sizeof(SECItem) } |
56 | | }; |
57 | | |
58 | | DERTemplate SECT61StringTemplate[] = { |
59 | | { DER_T61_STRING, |
60 | | 0, NULL, sizeof(SECItem) } |
61 | | }; |
62 | | |
63 | | DERTemplate SECUTCTimeTemplate[] = { |
64 | | { DER_UTC_TIME, |
65 | | 0, NULL, sizeof(SECItem) } |
66 | | }; |
67 | | |
68 | | #endif |
69 | | |
70 | | static int |
71 | | header_length(DERTemplate *dtemplate, PRUint32 contents_len) |
72 | 96 | { |
73 | 96 | PRUint32 len; |
74 | 96 | unsigned long encode_kind, under_kind; |
75 | 96 | PRBool explicit, optional, universal; |
76 | | |
77 | 96 | encode_kind = dtemplate->kind; |
78 | | |
79 | 96 | explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE; |
80 | 96 | optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE; |
81 | 96 | universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL) |
82 | 96 | ? PR_TRUE |
83 | 96 | : PR_FALSE; |
84 | | |
85 | 96 | PORT_Assert(!(explicit && universal)); /* bad templates */ |
86 | | |
87 | 96 | if (encode_kind & DER_POINTER) { |
88 | 0 | if (dtemplate->sub != NULL) { |
89 | 0 | under_kind = dtemplate->sub->kind; |
90 | 0 | if (universal) { |
91 | 0 | encode_kind = under_kind; |
92 | 0 | } |
93 | 0 | } else if (universal) { |
94 | 0 | under_kind = encode_kind & ~DER_POINTER; |
95 | 0 | } else { |
96 | 0 | under_kind = dtemplate->arg; |
97 | 0 | } |
98 | 96 | } else if (encode_kind & DER_INLINE) { |
99 | 18 | PORT_Assert(dtemplate->sub != NULL); |
100 | 18 | under_kind = dtemplate->sub->kind; |
101 | 18 | if (universal) { |
102 | 18 | encode_kind = under_kind; |
103 | 18 | } |
104 | 78 | } else if (universal) { |
105 | 78 | under_kind = encode_kind; |
106 | 78 | } else { |
107 | 0 | under_kind = dtemplate->arg; |
108 | 0 | } |
109 | | |
110 | | /* This is only used in decoding; it plays no part in encoding. */ |
111 | 96 | if (under_kind & DER_DERPTR) |
112 | 0 | return 0; |
113 | | |
114 | | /* No header at all for an "empty" optional. */ |
115 | 96 | if ((contents_len == 0) && optional) |
116 | 0 | return 0; |
117 | | |
118 | | /* And no header for a full DER_ANY. */ |
119 | 96 | if (encode_kind & DER_ANY) |
120 | 24 | return 0; |
121 | | |
122 | | /* |
123 | | * The common case: one octet for identifier and as many octets |
124 | | * as necessary to hold the content length. |
125 | | */ |
126 | 72 | len = 1 + DER_LengthLength(contents_len); |
127 | | |
128 | | /* Account for the explicit wrapper, if necessary. */ |
129 | 72 | if (explicit) { |
130 | | #if 0 /* \ |
131 | | * Well, I was trying to do something useful, but these \ |
132 | | * assertions are too restrictive on valid templates. \ |
133 | | * I wanted to make sure that the top-level "kind" of \ |
134 | | * a template does not also specify DER_EXPLICIT, which \ |
135 | | * should only modify a component field. Maybe later \ |
136 | | * I can figure out a better way to detect such a problem, \ |
137 | | * but for now I must remove these checks altogether. \ |
138 | | */ |
139 | | /* |
140 | | * This modifier applies only to components of a set or sequence; |
141 | | * it should never be used on a set/sequence itself -- confirm. |
142 | | */ |
143 | | PORT_Assert (under_kind != DER_SEQUENCE); |
144 | | PORT_Assert (under_kind != DER_SET); |
145 | | #endif |
146 | |
|
147 | 0 | len += 1 + DER_LengthLength(len + contents_len); |
148 | 0 | } |
149 | | |
150 | 72 | return len; |
151 | 96 | } |
152 | | |
153 | | static PRUint32 |
154 | | contents_length(DERTemplate *dtemplate, void *src) |
155 | 96 | { |
156 | 96 | PRUint32 len; |
157 | 96 | unsigned long encode_kind, under_kind; |
158 | 96 | PRBool universal; |
159 | | |
160 | 96 | PORT_Assert(src != NULL); |
161 | | |
162 | 96 | encode_kind = dtemplate->kind; |
163 | | |
164 | 96 | universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL) |
165 | 96 | ? PR_TRUE |
166 | 96 | : PR_FALSE; |
167 | 96 | encode_kind &= ~DER_OPTIONAL; |
168 | | |
169 | 96 | if (encode_kind & DER_POINTER) { |
170 | 0 | src = *(void **)src; |
171 | 0 | if (src == NULL) { |
172 | 0 | return 0; |
173 | 0 | } |
174 | 0 | if (dtemplate->sub != NULL) { |
175 | 0 | dtemplate = dtemplate->sub; |
176 | 0 | under_kind = dtemplate->kind; |
177 | 0 | src = (void *)((char *)src + dtemplate->offset); |
178 | 0 | } else if (universal) { |
179 | 0 | under_kind = encode_kind & ~DER_POINTER; |
180 | 0 | } else { |
181 | 0 | under_kind = dtemplate->arg; |
182 | 0 | } |
183 | 96 | } else if (encode_kind & DER_INLINE) { |
184 | 18 | PORT_Assert(dtemplate->sub != NULL); |
185 | 18 | dtemplate = dtemplate->sub; |
186 | 18 | under_kind = dtemplate->kind; |
187 | 18 | src = (void *)((char *)src + dtemplate->offset); |
188 | 78 | } else if (universal) { |
189 | 78 | under_kind = encode_kind; |
190 | 78 | } else { |
191 | 0 | under_kind = dtemplate->arg; |
192 | 0 | } |
193 | | |
194 | | /* Having any of these bits is not expected here... */ |
195 | 96 | PORT_Assert((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL | DER_POINTER | DER_SKIP)) == 0); |
196 | | |
197 | | /* This is only used in decoding; it plays no part in encoding. */ |
198 | 96 | if (under_kind & DER_DERPTR) |
199 | 0 | return 0; |
200 | | |
201 | 96 | if (under_kind & DER_INDEFINITE) { |
202 | 0 | PRUint32 sub_len; |
203 | 0 | void **indp = *(void ***)src; |
204 | |
|
205 | 0 | if (indp == NULL) |
206 | 0 | return 0; |
207 | | |
208 | 0 | len = 0; |
209 | 0 | under_kind &= ~DER_INDEFINITE; |
210 | |
|
211 | 0 | if (under_kind == DER_SET || under_kind == DER_SEQUENCE) { |
212 | 0 | DERTemplate *tmpt = dtemplate->sub; |
213 | 0 | PORT_Assert(tmpt != NULL); |
214 | |
|
215 | 0 | for (; *indp != NULL; indp++) { |
216 | 0 | void *sub_src = (void *)((char *)(*indp) + tmpt->offset); |
217 | 0 | sub_len = contents_length(tmpt, sub_src); |
218 | 0 | len += sub_len + header_length(tmpt, sub_len); |
219 | 0 | } |
220 | 0 | } else { |
221 | | /* |
222 | | * XXX Lisa is not sure this code (for handling, for example, |
223 | | * DER_INDEFINITE | DER_OCTET_STRING) is right. |
224 | | */ |
225 | 0 | for (; *indp != NULL; indp++) { |
226 | 0 | SECItem *item = (SECItem *)(*indp); |
227 | 0 | sub_len = item->len; |
228 | 0 | if (under_kind == DER_BIT_STRING) { |
229 | 0 | sub_len = (sub_len + 7) >> 3; |
230 | | /* bit string contents involve an extra octet */ |
231 | 0 | if (sub_len) |
232 | 0 | sub_len++; |
233 | 0 | } |
234 | 0 | if (under_kind != DER_ANY) |
235 | 0 | len += 1 + DER_LengthLength(sub_len); |
236 | 0 | } |
237 | 0 | } |
238 | |
|
239 | 0 | return len; |
240 | 0 | } |
241 | | |
242 | 96 | switch (under_kind) { |
243 | 30 | case DER_SEQUENCE: |
244 | 30 | case DER_SET: { |
245 | 30 | DERTemplate *tmpt; |
246 | 30 | void *sub_src; |
247 | 30 | PRUint32 sub_len; |
248 | | |
249 | 30 | len = 0; |
250 | 90 | for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) { |
251 | 60 | sub_src = (void *)((char *)src + tmpt->offset); |
252 | 60 | sub_len = contents_length(tmpt, sub_src); |
253 | 60 | len += sub_len + header_length(tmpt, sub_len); |
254 | 60 | } |
255 | 30 | } break; |
256 | | |
257 | 0 | case DER_BIT_STRING: |
258 | 0 | len = (((SECItem *)src)->len + 7) >> 3; |
259 | | /* bit string contents involve an extra octet */ |
260 | 0 | if (len) |
261 | 0 | len++; |
262 | 0 | break; |
263 | | |
264 | 66 | default: |
265 | 66 | len = ((SECItem *)src)->len; |
266 | 66 | break; |
267 | 96 | } |
268 | | |
269 | 96 | return len; |
270 | 96 | } |
271 | | |
272 | | static unsigned char * |
273 | | der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src) |
274 | 30 | { |
275 | 30 | int header_len; |
276 | 30 | PRUint32 contents_len; |
277 | 30 | unsigned long encode_kind, under_kind; |
278 | 30 | PRBool explicit, universal; |
279 | | |
280 | | /* |
281 | | * First figure out how long the encoding will be. Do this by |
282 | | * traversing the template from top to bottom and accumulating |
283 | | * the length of each leaf item. |
284 | | */ |
285 | 30 | contents_len = contents_length(dtemplate, src); |
286 | 30 | header_len = header_length(dtemplate, contents_len); |
287 | | |
288 | | /* |
289 | | * Enough smarts was involved already, so that if both the |
290 | | * header and the contents have a length of zero, then we |
291 | | * are not doing any encoding for this element. |
292 | | */ |
293 | 30 | if (header_len == 0 && contents_len == 0) |
294 | 0 | return buf; |
295 | | |
296 | 30 | encode_kind = dtemplate->kind; |
297 | | |
298 | 30 | explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE; |
299 | 30 | encode_kind &= ~DER_OPTIONAL; |
300 | 30 | universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL) |
301 | 30 | ? PR_TRUE |
302 | 30 | : PR_FALSE; |
303 | | |
304 | 30 | if (encode_kind & DER_POINTER) { |
305 | 0 | if (contents_len) { |
306 | 0 | src = *(void **)src; |
307 | 0 | PORT_Assert(src != NULL); |
308 | 0 | } |
309 | 0 | if (dtemplate->sub != NULL) { |
310 | 0 | dtemplate = dtemplate->sub; |
311 | 0 | under_kind = dtemplate->kind; |
312 | 0 | if (universal) { |
313 | 0 | encode_kind = under_kind; |
314 | 0 | } |
315 | 0 | src = (void *)((char *)src + dtemplate->offset); |
316 | 0 | } else if (universal) { |
317 | 0 | under_kind = encode_kind & ~DER_POINTER; |
318 | 0 | } else { |
319 | 0 | under_kind = dtemplate->arg; |
320 | 0 | } |
321 | 30 | } else if (encode_kind & DER_INLINE) { |
322 | 6 | dtemplate = dtemplate->sub; |
323 | 6 | under_kind = dtemplate->kind; |
324 | 6 | if (universal) { |
325 | 6 | encode_kind = under_kind; |
326 | 6 | } |
327 | 6 | src = (void *)((char *)src + dtemplate->offset); |
328 | 24 | } else if (universal) { |
329 | 24 | under_kind = encode_kind; |
330 | 24 | } else { |
331 | 0 | under_kind = dtemplate->arg; |
332 | 0 | } |
333 | | |
334 | 30 | if (explicit) { |
335 | 0 | buf = DER_StoreHeader(buf, encode_kind, |
336 | 0 | (1 + DER_LengthLength(contents_len) + contents_len)); |
337 | 0 | encode_kind = under_kind; |
338 | 0 | } |
339 | | |
340 | 30 | if ((encode_kind & DER_ANY) == 0) { /* DER_ANY already contains header */ |
341 | 24 | buf = DER_StoreHeader(buf, encode_kind, contents_len); |
342 | 24 | } |
343 | | |
344 | | /* If no real contents to encode, then we are done. */ |
345 | 30 | if (contents_len == 0) |
346 | 0 | return buf; |
347 | | |
348 | 30 | if (under_kind & DER_INDEFINITE) { |
349 | 0 | void **indp; |
350 | |
|
351 | 0 | indp = *(void ***)src; |
352 | 0 | PORT_Assert(indp != NULL); |
353 | |
|
354 | 0 | under_kind &= ~DER_INDEFINITE; |
355 | 0 | if (under_kind == DER_SET || under_kind == DER_SEQUENCE) { |
356 | 0 | DERTemplate *tmpt = dtemplate->sub; |
357 | 0 | PORT_Assert(tmpt != NULL); |
358 | 0 | for (; *indp != NULL; indp++) { |
359 | 0 | void *sub_src = (void *)((char *)(*indp) + tmpt->offset); |
360 | 0 | buf = der_encode(buf, tmpt, sub_src); |
361 | 0 | } |
362 | 0 | } else { |
363 | 0 | for (; *indp != NULL; indp++) { |
364 | 0 | SECItem *item; |
365 | 0 | int sub_len; |
366 | |
|
367 | 0 | item = (SECItem *)(*indp); |
368 | 0 | sub_len = item->len; |
369 | 0 | if (under_kind == DER_BIT_STRING) { |
370 | 0 | if (sub_len) { |
371 | 0 | int rem; |
372 | |
|
373 | 0 | sub_len = (sub_len + 7) >> 3; |
374 | 0 | buf = DER_StoreHeader(buf, under_kind, sub_len + 1); |
375 | 0 | rem = (sub_len << 3) - item->len; |
376 | 0 | *buf++ = rem; /* remaining bits */ |
377 | 0 | } else { |
378 | 0 | buf = DER_StoreHeader(buf, under_kind, 0); |
379 | 0 | } |
380 | 0 | } else if (under_kind != DER_ANY) { |
381 | 0 | buf = DER_StoreHeader(buf, under_kind, sub_len); |
382 | 0 | } |
383 | 0 | PORT_Memcpy(buf, item->data, sub_len); |
384 | 0 | buf += sub_len; |
385 | 0 | } |
386 | 0 | } |
387 | 0 | return buf; |
388 | 0 | } |
389 | | |
390 | 30 | switch (under_kind) { |
391 | 12 | case DER_SEQUENCE: |
392 | 12 | case DER_SET: { |
393 | 12 | DERTemplate *tmpt; |
394 | 12 | void *sub_src; |
395 | | |
396 | 36 | for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) { |
397 | 24 | sub_src = (void *)((char *)src + tmpt->offset); |
398 | 24 | buf = der_encode(buf, tmpt, sub_src); |
399 | 24 | } |
400 | 12 | } break; |
401 | | |
402 | 0 | case DER_BIT_STRING: { |
403 | 0 | SECItem *item; |
404 | 0 | int rem; |
405 | | |
406 | | /* |
407 | | * The contents length includes our extra octet; subtract |
408 | | * it off so we just have the real string length there. |
409 | | */ |
410 | 0 | contents_len--; |
411 | 0 | item = (SECItem *)src; |
412 | 0 | PORT_Assert(contents_len == ((item->len + 7) >> 3)); |
413 | 0 | rem = (contents_len << 3) - item->len; |
414 | 0 | *buf++ = rem; /* remaining bits */ |
415 | 0 | PORT_Memcpy(buf, item->data, contents_len); |
416 | 0 | buf += contents_len; |
417 | 0 | } break; |
418 | | |
419 | 18 | default: { |
420 | 18 | SECItem *item; |
421 | | |
422 | 18 | item = (SECItem *)src; |
423 | 18 | PORT_Assert(contents_len == item->len); |
424 | 18 | PORT_Memcpy(buf, item->data, contents_len); |
425 | 18 | buf += contents_len; |
426 | 18 | } break; |
427 | 30 | } |
428 | | |
429 | 30 | return buf; |
430 | 30 | } |
431 | | |
432 | | SECStatus |
433 | | DER_Encode(PLArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src) |
434 | 6 | { |
435 | 6 | unsigned int contents_len, header_len; |
436 | | |
437 | 6 | src = (void **)((char *)src + dtemplate->offset); |
438 | | |
439 | | /* |
440 | | * First figure out how long the encoding will be. Do this by |
441 | | * traversing the template from top to bottom and accumulating |
442 | | * the length of each leaf item. |
443 | | */ |
444 | 6 | contents_len = contents_length(dtemplate, src); |
445 | 6 | header_len = header_length(dtemplate, contents_len); |
446 | | |
447 | 6 | dest->len = contents_len + header_len; |
448 | | |
449 | | /* Allocate storage to hold the encoding */ |
450 | 6 | dest->data = (unsigned char *)PORT_ArenaAlloc(arena, dest->len); |
451 | 6 | if (dest->data == NULL) { |
452 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
453 | 0 | return SECFailure; |
454 | 0 | } |
455 | | |
456 | | /* Now encode into the buffer */ |
457 | 6 | (void)der_encode(dest->data, dtemplate, src); |
458 | | |
459 | 6 | return SECSuccess; |
460 | 6 | } |