security/nss/lib/util/derenc.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

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 }

mercurial