Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / util / derenc.c
blob3470f74f77bd5abb22c475679ad79f8c7144e786
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "secder.h"
38 #include "secerr.h"
40 * Generic templates for individual/simple items.
43 DERTemplate SECAnyTemplate[] = {
44 { DER_ANY,
45 0, NULL, sizeof(SECItem) }
48 DERTemplate SECBitStringTemplate[] = {
49 { DER_BIT_STRING,
50 0, NULL, sizeof(SECItem) }
53 DERTemplate SECBooleanTemplate[] = {
54 { DER_BOOLEAN,
55 0, NULL, sizeof(SECItem) }
58 DERTemplate SECIA5StringTemplate[] = {
59 { DER_IA5_STRING,
60 0, NULL, sizeof(SECItem) }
63 DERTemplate SECIntegerTemplate[] = {
64 { DER_INTEGER,
65 0, NULL, sizeof(SECItem) }
68 DERTemplate SECNullTemplate[] = {
69 { DER_NULL,
70 0, NULL, sizeof(SECItem) }
73 DERTemplate SECObjectIDTemplate[] = {
74 { DER_OBJECT_ID,
75 0, NULL, sizeof(SECItem) }
78 DERTemplate SECOctetStringTemplate[] = {
79 { DER_OCTET_STRING,
80 0, NULL, sizeof(SECItem) }
83 DERTemplate SECPrintableStringTemplate[] = {
84 { DER_PRINTABLE_STRING,
85 0, NULL, sizeof(SECItem) }
88 DERTemplate SECT61StringTemplate[] = {
89 { DER_T61_STRING,
90 0, NULL, sizeof(SECItem) }
93 DERTemplate SECUTCTimeTemplate[] = {
94 { DER_UTC_TIME,
95 0, NULL, sizeof(SECItem) }
99 static int
100 header_length(DERTemplate *dtemplate, uint32 contents_len)
102 uint32 len;
103 unsigned long encode_kind, under_kind;
104 PRBool explicit, optional, universal;
106 encode_kind = dtemplate->kind;
108 explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
109 optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
110 universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
111 ? PR_TRUE : PR_FALSE;
113 PORT_Assert (!(explicit && universal)); /* bad templates */
115 if (encode_kind & DER_POINTER) {
116 if (dtemplate->sub != NULL) {
117 under_kind = dtemplate->sub->kind;
118 if (universal) {
119 encode_kind = under_kind;
121 } else if (universal) {
122 under_kind = encode_kind & ~DER_POINTER;
123 } else {
124 under_kind = dtemplate->arg;
126 } else if (encode_kind & DER_INLINE) {
127 PORT_Assert (dtemplate->sub != NULL);
128 under_kind = dtemplate->sub->kind;
129 if (universal) {
130 encode_kind = under_kind;
132 } else if (universal) {
133 under_kind = encode_kind;
134 } else {
135 under_kind = dtemplate->arg;
138 /* This is only used in decoding; it plays no part in encoding. */
139 if (under_kind & DER_DERPTR)
140 return 0;
142 /* No header at all for an "empty" optional. */
143 if ((contents_len == 0) && optional)
144 return 0;
146 /* And no header for a full DER_ANY. */
147 if (encode_kind & DER_ANY)
148 return 0;
151 * The common case: one octet for identifier and as many octets
152 * as necessary to hold the content length.
154 len = 1 + DER_LengthLength(contents_len);
156 /* Account for the explicit wrapper, if necessary. */
157 if (explicit) {
158 #if 0 /*
159 * Well, I was trying to do something useful, but these
160 * assertions are too restrictive on valid templates.
161 * I wanted to make sure that the top-level "kind" of
162 * a template does not also specify DER_EXPLICIT, which
163 * should only modify a component field. Maybe later
164 * I can figure out a better way to detect such a problem,
165 * but for now I must remove these checks altogether.
168 * This modifier applies only to components of a set or sequence;
169 * it should never be used on a set/sequence itself -- confirm.
171 PORT_Assert (under_kind != DER_SEQUENCE);
172 PORT_Assert (under_kind != DER_SET);
173 #endif
175 len += 1 + DER_LengthLength(len + contents_len);
178 return len;
182 static uint32
183 contents_length(DERTemplate *dtemplate, void *src)
185 uint32 len;
186 unsigned long encode_kind, under_kind;
187 PRBool universal;
190 PORT_Assert (src != NULL);
192 encode_kind = dtemplate->kind;
194 universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
195 ? PR_TRUE : PR_FALSE;
196 encode_kind &= ~DER_OPTIONAL;
198 if (encode_kind & DER_POINTER) {
199 src = *(void **)src;
200 if (src == NULL) {
201 return 0;
203 if (dtemplate->sub != NULL) {
204 dtemplate = dtemplate->sub;
205 under_kind = dtemplate->kind;
206 src = (void *)((char *)src + dtemplate->offset);
207 } else if (universal) {
208 under_kind = encode_kind & ~DER_POINTER;
209 } else {
210 under_kind = dtemplate->arg;
212 } else if (encode_kind & DER_INLINE) {
213 PORT_Assert (dtemplate->sub != NULL);
214 dtemplate = dtemplate->sub;
215 under_kind = dtemplate->kind;
216 src = (void *)((char *)src + dtemplate->offset);
217 } else if (universal) {
218 under_kind = encode_kind;
219 } else {
220 under_kind = dtemplate->arg;
223 /* Having any of these bits is not expected here... */
224 PORT_Assert ((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL
225 | DER_POINTER | DER_SKIP)) == 0);
227 /* This is only used in decoding; it plays no part in encoding. */
228 if (under_kind & DER_DERPTR)
229 return 0;
231 if (under_kind & DER_INDEFINITE) {
232 uint32 sub_len;
233 void **indp = *(void ***)src;
235 if (indp == NULL)
236 return 0;
238 len = 0;
239 under_kind &= ~DER_INDEFINITE;
241 if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
242 DERTemplate *tmpt = dtemplate->sub;
243 PORT_Assert (tmpt != NULL);
245 for (; *indp != NULL; indp++) {
246 void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
247 sub_len = contents_length (tmpt, sub_src);
248 len += sub_len + header_length (tmpt, sub_len);
250 } else {
252 * XXX Lisa is not sure this code (for handling, for example,
253 * DER_INDEFINITE | DER_OCTET_STRING) is right.
255 for (; *indp != NULL; indp++) {
256 SECItem *item = (SECItem *)(*indp);
257 sub_len = item->len;
258 if (under_kind == DER_BIT_STRING) {
259 sub_len = (sub_len + 7) >> 3;
260 /* bit string contents involve an extra octet */
261 if (sub_len)
262 sub_len++;
264 if (under_kind != DER_ANY)
265 len += 1 + DER_LengthLength (sub_len);
269 return len;
272 switch (under_kind) {
273 case DER_SEQUENCE:
274 case DER_SET:
276 DERTemplate *tmpt;
277 void *sub_src;
278 uint32 sub_len;
280 len = 0;
281 for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
282 sub_src = (void *)((char *)src + tmpt->offset);
283 sub_len = contents_length (tmpt, sub_src);
284 len += sub_len + header_length (tmpt, sub_len);
287 break;
289 case DER_BIT_STRING:
290 len = (((SECItem *)src)->len + 7) >> 3;
291 /* bit string contents involve an extra octet */
292 if (len)
293 len++;
294 break;
296 default:
297 len = ((SECItem *)src)->len;
298 break;
301 return len;
305 static unsigned char *
306 der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src)
308 int header_len;
309 uint32 contents_len;
310 unsigned long encode_kind, under_kind;
311 PRBool explicit, optional, universal;
315 * First figure out how long the encoding will be. Do this by
316 * traversing the template from top to bottom and accumulating
317 * the length of each leaf item.
319 contents_len = contents_length (dtemplate, src);
320 header_len = header_length (dtemplate, contents_len);
323 * Enough smarts was involved already, so that if both the
324 * header and the contents have a length of zero, then we
325 * are not doing any encoding for this element.
327 if (header_len == 0 && contents_len == 0)
328 return buf;
330 encode_kind = dtemplate->kind;
332 explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
333 optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
334 encode_kind &= ~DER_OPTIONAL;
335 universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
336 ? PR_TRUE : PR_FALSE;
338 if (encode_kind & DER_POINTER) {
339 if (contents_len) {
340 src = *(void **)src;
341 PORT_Assert (src != NULL);
343 if (dtemplate->sub != NULL) {
344 dtemplate = dtemplate->sub;
345 under_kind = dtemplate->kind;
346 if (universal) {
347 encode_kind = under_kind;
349 src = (void *)((char *)src + dtemplate->offset);
350 } else if (universal) {
351 under_kind = encode_kind & ~DER_POINTER;
352 } else {
353 under_kind = dtemplate->arg;
355 } else if (encode_kind & DER_INLINE) {
356 dtemplate = dtemplate->sub;
357 under_kind = dtemplate->kind;
358 if (universal) {
359 encode_kind = under_kind;
361 src = (void *)((char *)src + dtemplate->offset);
362 } else if (universal) {
363 under_kind = encode_kind;
364 } else {
365 under_kind = dtemplate->arg;
368 if (explicit) {
369 buf = DER_StoreHeader (buf, encode_kind,
370 (1 + DER_LengthLength(contents_len)
371 + contents_len));
372 encode_kind = under_kind;
375 if ((encode_kind & DER_ANY) == 0) { /* DER_ANY already contains header */
376 buf = DER_StoreHeader (buf, encode_kind, contents_len);
379 /* If no real contents to encode, then we are done. */
380 if (contents_len == 0)
381 return buf;
383 if (under_kind & DER_INDEFINITE) {
384 void **indp;
386 indp = *(void ***)src;
387 PORT_Assert (indp != NULL);
389 under_kind &= ~DER_INDEFINITE;
390 if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
391 DERTemplate *tmpt = dtemplate->sub;
392 PORT_Assert (tmpt != NULL);
393 for (; *indp != NULL; indp++) {
394 void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
395 buf = der_encode (buf, tmpt, sub_src);
397 } else {
398 for (; *indp != NULL; indp++) {
399 SECItem *item;
400 int sub_len;
402 item = (SECItem *)(*indp);
403 sub_len = item->len;
404 if (under_kind == DER_BIT_STRING) {
405 if (sub_len) {
406 int rem;
408 sub_len = (sub_len + 7) >> 3;
409 buf = DER_StoreHeader (buf, under_kind, sub_len + 1);
410 rem = (sub_len << 3) - item->len;
411 *buf++ = rem; /* remaining bits */
412 } else {
413 buf = DER_StoreHeader (buf, under_kind, 0);
415 } else if (under_kind != DER_ANY) {
416 buf = DER_StoreHeader (buf, under_kind, sub_len);
418 PORT_Memcpy (buf, item->data, sub_len);
419 buf += sub_len;
422 return buf;
425 switch (under_kind) {
426 case DER_SEQUENCE:
427 case DER_SET:
429 DERTemplate *tmpt;
430 void *sub_src;
432 for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
433 sub_src = (void *)((char *)src + tmpt->offset);
434 buf = der_encode (buf, tmpt, sub_src);
437 break;
439 case DER_BIT_STRING:
441 SECItem *item;
442 int rem;
445 * The contents length includes our extra octet; subtract
446 * it off so we just have the real string length there.
448 contents_len--;
449 item = (SECItem *)src;
450 PORT_Assert (contents_len == ((item->len + 7) >> 3));
451 rem = (contents_len << 3) - item->len;
452 *buf++ = rem; /* remaining bits */
453 PORT_Memcpy (buf, item->data, contents_len);
454 buf += contents_len;
456 break;
458 default:
460 SECItem *item;
462 item = (SECItem *)src;
463 PORT_Assert (contents_len == item->len);
464 PORT_Memcpy (buf, item->data, contents_len);
465 buf += contents_len;
467 break;
470 return buf;
474 SECStatus
475 DER_Encode(PRArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src)
477 unsigned int contents_len, header_len;
479 src = (void **)((char *)src + dtemplate->offset);
482 * First figure out how long the encoding will be. Do this by
483 * traversing the template from top to bottom and accumulating
484 * the length of each leaf item.
486 contents_len = contents_length (dtemplate, src);
487 header_len = header_length (dtemplate, contents_len);
489 dest->len = contents_len + header_len;
491 /* Allocate storage to hold the encoding */
492 dest->data = (unsigned char*) PORT_ArenaAlloc(arena, dest->len);
493 if (dest->data == NULL) {
494 PORT_SetError(SEC_ERROR_NO_MEMORY);
495 return SECFailure;
498 /* Now encode into the buffer */
499 (void) der_encode (dest->data, dtemplate, src);
501 return SECSuccess;