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