security/nss/lib/util/derenc.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/util/derenc.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,473 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "secder.h"
     1.9 +#include "secerr.h"
    1.10 +
    1.11 +#if 0
    1.12 +/*
    1.13 + * Generic templates for individual/simple items.
    1.14 + */
    1.15 +
    1.16 +DERTemplate SECAnyTemplate[] = {
    1.17 +    { DER_ANY,
    1.18 +	  0, NULL, sizeof(SECItem) }
    1.19 +};
    1.20 +
    1.21 +DERTemplate SECBitStringTemplate[] = {
    1.22 +    { DER_BIT_STRING,
    1.23 +	  0, NULL, sizeof(SECItem) }
    1.24 +};
    1.25 +
    1.26 +DERTemplate SECBooleanTemplate[] = {
    1.27 +    { DER_BOOLEAN,
    1.28 +	  0, NULL, sizeof(SECItem) }
    1.29 +};
    1.30 +
    1.31 +DERTemplate SECIA5StringTemplate[] = {
    1.32 +    { DER_IA5_STRING,
    1.33 +	  0, NULL, sizeof(SECItem) }
    1.34 +};
    1.35 +
    1.36 +DERTemplate SECIntegerTemplate[] = {
    1.37 +    { DER_INTEGER,
    1.38 +	  0, NULL, sizeof(SECItem) }
    1.39 +};
    1.40 +
    1.41 +DERTemplate SECNullTemplate[] = {
    1.42 +    { DER_NULL,
    1.43 +	  0, NULL, sizeof(SECItem) }
    1.44 +};
    1.45 +
    1.46 +DERTemplate SECObjectIDTemplate[] = {
    1.47 +    { DER_OBJECT_ID,
    1.48 +	  0, NULL, sizeof(SECItem) }
    1.49 +};
    1.50 +
    1.51 +DERTemplate SECOctetStringTemplate[] = {
    1.52 +    { DER_OCTET_STRING,
    1.53 +	  0, NULL, sizeof(SECItem) }
    1.54 +};
    1.55 +
    1.56 +DERTemplate SECPrintableStringTemplate[] = {
    1.57 +    { DER_PRINTABLE_STRING,
    1.58 +	  0, NULL, sizeof(SECItem) }
    1.59 +};
    1.60 +
    1.61 +DERTemplate SECT61StringTemplate[] = {
    1.62 +    { DER_T61_STRING,
    1.63 +	  0, NULL, sizeof(SECItem) }
    1.64 +};
    1.65 +
    1.66 +DERTemplate SECUTCTimeTemplate[] = {
    1.67 +    { DER_UTC_TIME,
    1.68 +	  0, NULL, sizeof(SECItem) }
    1.69 +};
    1.70 +
    1.71 +#endif
    1.72 +
    1.73 +static int
    1.74 +header_length(DERTemplate *dtemplate, PRUint32 contents_len)
    1.75 +{
    1.76 +    PRUint32 len;
    1.77 +    unsigned long encode_kind, under_kind;
    1.78 +    PRBool explicit, optional, universal;
    1.79 +
    1.80 +    encode_kind = dtemplate->kind;
    1.81 +
    1.82 +    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
    1.83 +    optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
    1.84 +    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
    1.85 +		? PR_TRUE : PR_FALSE;
    1.86 +
    1.87 +    PORT_Assert (!(explicit && universal));	/* bad templates */
    1.88 +
    1.89 +    if (encode_kind & DER_POINTER) {
    1.90 +	if (dtemplate->sub != NULL) {
    1.91 +	    under_kind = dtemplate->sub->kind;
    1.92 +	    if (universal) {
    1.93 +		encode_kind = under_kind;
    1.94 +	    }
    1.95 +	} else if (universal) {
    1.96 +	    under_kind = encode_kind & ~DER_POINTER;
    1.97 +	} else {
    1.98 +	    under_kind = dtemplate->arg;
    1.99 +	}
   1.100 +    } else if (encode_kind & DER_INLINE) {
   1.101 +	PORT_Assert (dtemplate->sub != NULL);
   1.102 +	under_kind = dtemplate->sub->kind;
   1.103 +	if (universal) {
   1.104 +	    encode_kind = under_kind;
   1.105 +	}
   1.106 +    } else if (universal) {
   1.107 +	under_kind = encode_kind;
   1.108 +    } else {
   1.109 +	under_kind = dtemplate->arg;
   1.110 +    }
   1.111 +
   1.112 +    /* This is only used in decoding; it plays no part in encoding.  */
   1.113 +    if (under_kind & DER_DERPTR)
   1.114 +	return 0;
   1.115 +
   1.116 +    /* No header at all for an "empty" optional.  */
   1.117 +    if ((contents_len == 0) && optional)
   1.118 +	return 0;
   1.119 +
   1.120 +    /* And no header for a full DER_ANY.  */
   1.121 +    if (encode_kind & DER_ANY)
   1.122 +	return 0;
   1.123 +
   1.124 +    /*
   1.125 +     * The common case: one octet for identifier and as many octets
   1.126 +     * as necessary to hold the content length.
   1.127 +     */
   1.128 +    len = 1 + DER_LengthLength(contents_len);
   1.129 +
   1.130 +    /* Account for the explicit wrapper, if necessary.  */
   1.131 +    if (explicit) {
   1.132 +#if 0		/*
   1.133 +		 * Well, I was trying to do something useful, but these
   1.134 +		 * assertions are too restrictive on valid templates.
   1.135 +		 * I wanted to make sure that the top-level "kind" of
   1.136 +		 * a template does not also specify DER_EXPLICIT, which
   1.137 +		 * should only modify a component field.  Maybe later
   1.138 +		 * I can figure out a better way to detect such a problem,
   1.139 +		 * but for now I must remove these checks altogether.
   1.140 +		 */
   1.141 +	/*
   1.142 +	 * This modifier applies only to components of a set or sequence;
   1.143 +	 * it should never be used on a set/sequence itself -- confirm.
   1.144 +	 */
   1.145 +	PORT_Assert (under_kind != DER_SEQUENCE);
   1.146 +	PORT_Assert (under_kind != DER_SET);
   1.147 +#endif
   1.148 +
   1.149 +	len += 1 + DER_LengthLength(len + contents_len);
   1.150 +    }
   1.151 +
   1.152 +    return len;
   1.153 +}
   1.154 +
   1.155 +
   1.156 +static PRUint32
   1.157 +contents_length(DERTemplate *dtemplate, void *src)
   1.158 +{
   1.159 +    PRUint32 len;
   1.160 +    unsigned long encode_kind, under_kind;
   1.161 +    PRBool universal;
   1.162 +
   1.163 +
   1.164 +    PORT_Assert (src != NULL);
   1.165 +
   1.166 +    encode_kind = dtemplate->kind;
   1.167 +
   1.168 +    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
   1.169 +		? PR_TRUE : PR_FALSE;
   1.170 +    encode_kind &= ~DER_OPTIONAL;
   1.171 +
   1.172 +    if (encode_kind & DER_POINTER) {
   1.173 +	src = *(void **)src;
   1.174 +	if (src == NULL) {
   1.175 +	    return 0;
   1.176 +	}
   1.177 +	if (dtemplate->sub != NULL) {
   1.178 +	    dtemplate = dtemplate->sub;
   1.179 +	    under_kind = dtemplate->kind;
   1.180 +	    src = (void *)((char *)src + dtemplate->offset);
   1.181 +	} else if (universal) {
   1.182 +	    under_kind = encode_kind & ~DER_POINTER;
   1.183 +	} else {
   1.184 +	    under_kind = dtemplate->arg;
   1.185 +	}
   1.186 +    } else if (encode_kind & DER_INLINE) {
   1.187 +	PORT_Assert (dtemplate->sub != NULL);
   1.188 +	dtemplate = dtemplate->sub;
   1.189 +	under_kind = dtemplate->kind;
   1.190 +	src = (void *)((char *)src + dtemplate->offset);
   1.191 +    } else if (universal) {
   1.192 +	under_kind = encode_kind;
   1.193 +    } else {
   1.194 +	under_kind = dtemplate->arg;
   1.195 +    }
   1.196 +
   1.197 +    /* Having any of these bits is not expected here...  */
   1.198 +    PORT_Assert ((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL
   1.199 +				| DER_POINTER | DER_SKIP)) == 0);
   1.200 +
   1.201 +    /* This is only used in decoding; it plays no part in encoding.  */
   1.202 +    if (under_kind & DER_DERPTR)
   1.203 +	return 0;
   1.204 +
   1.205 +    if (under_kind & DER_INDEFINITE) {
   1.206 +	PRUint32 sub_len;
   1.207 +	void   **indp = *(void ***)src;
   1.208 +
   1.209 +	if (indp == NULL)
   1.210 +	    return 0;
   1.211 +
   1.212 +	len = 0;
   1.213 +	under_kind &= ~DER_INDEFINITE;
   1.214 +
   1.215 +	if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
   1.216 +	    DERTemplate *tmpt = dtemplate->sub;
   1.217 +	    PORT_Assert (tmpt != NULL);
   1.218 +
   1.219 +	    for (; *indp != NULL; indp++) {
   1.220 +		void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
   1.221 +		sub_len = contents_length (tmpt, sub_src);
   1.222 +		len += sub_len + header_length (tmpt, sub_len);
   1.223 +	    }
   1.224 +	} else {
   1.225 +	    /*
   1.226 +	     * XXX Lisa is not sure this code (for handling, for example,
   1.227 +	     * DER_INDEFINITE | DER_OCTET_STRING) is right.
   1.228 +	     */
   1.229 +	    for (; *indp != NULL; indp++) {
   1.230 +		SECItem *item = (SECItem *)(*indp);
   1.231 +		sub_len = item->len;
   1.232 +		if (under_kind == DER_BIT_STRING) {
   1.233 +		    sub_len = (sub_len + 7) >> 3;
   1.234 +		    /* bit string contents involve an extra octet */
   1.235 +		    if (sub_len)
   1.236 +			sub_len++;
   1.237 +		}
   1.238 +		if (under_kind != DER_ANY)
   1.239 +		    len += 1 + DER_LengthLength (sub_len);
   1.240 +	    }
   1.241 +	}
   1.242 +
   1.243 +	return len;
   1.244 +    }
   1.245 +
   1.246 +    switch (under_kind) {
   1.247 +      case DER_SEQUENCE:
   1.248 +      case DER_SET:
   1.249 +	{
   1.250 +	    DERTemplate *tmpt;
   1.251 +	    void *sub_src;
   1.252 +	    PRUint32 sub_len;
   1.253 +
   1.254 +	    len = 0;
   1.255 +	    for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
   1.256 +		sub_src = (void *)((char *)src + tmpt->offset);
   1.257 +		sub_len = contents_length (tmpt, sub_src);
   1.258 +		len += sub_len + header_length (tmpt, sub_len);
   1.259 +	    }
   1.260 +	}
   1.261 +	break;
   1.262 +
   1.263 +      case DER_BIT_STRING:
   1.264 +	len = (((SECItem *)src)->len + 7) >> 3;
   1.265 +	/* bit string contents involve an extra octet */
   1.266 +	if (len)
   1.267 +	    len++;
   1.268 +	break;
   1.269 +
   1.270 +      default:
   1.271 +	len = ((SECItem *)src)->len;
   1.272 +	break;
   1.273 +    }
   1.274 +
   1.275 +    return len;
   1.276 +}
   1.277 +
   1.278 +
   1.279 +static unsigned char *
   1.280 +der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src)
   1.281 +{
   1.282 +    int header_len;
   1.283 +    PRUint32 contents_len;
   1.284 +    unsigned long encode_kind, under_kind;
   1.285 +    PRBool explicit, optional, universal;
   1.286 +
   1.287 +
   1.288 +    /*
   1.289 +     * First figure out how long the encoding will be.  Do this by
   1.290 +     * traversing the template from top to bottom and accumulating
   1.291 +     * the length of each leaf item.
   1.292 +     */
   1.293 +    contents_len = contents_length (dtemplate, src);
   1.294 +    header_len = header_length (dtemplate, contents_len);
   1.295 +
   1.296 +    /*
   1.297 +     * Enough smarts was involved already, so that if both the
   1.298 +     * header and the contents have a length of zero, then we
   1.299 +     * are not doing any encoding for this element.
   1.300 +     */
   1.301 +    if (header_len == 0 && contents_len == 0)
   1.302 +	return buf;
   1.303 +
   1.304 +    encode_kind = dtemplate->kind;
   1.305 +
   1.306 +    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
   1.307 +    optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
   1.308 +    encode_kind &= ~DER_OPTIONAL;
   1.309 +    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
   1.310 +		? PR_TRUE : PR_FALSE;
   1.311 +
   1.312 +    if (encode_kind & DER_POINTER) {
   1.313 +	if (contents_len) {
   1.314 +	    src = *(void **)src;
   1.315 +	    PORT_Assert (src != NULL);
   1.316 +	}
   1.317 +	if (dtemplate->sub != NULL) {
   1.318 +	    dtemplate = dtemplate->sub;
   1.319 +	    under_kind = dtemplate->kind;
   1.320 +	    if (universal) {
   1.321 +		encode_kind = under_kind;
   1.322 +	    }
   1.323 +	    src = (void *)((char *)src + dtemplate->offset);
   1.324 +	} else if (universal) {
   1.325 +	    under_kind = encode_kind & ~DER_POINTER;
   1.326 +	} else {
   1.327 +	    under_kind = dtemplate->arg;
   1.328 +	}
   1.329 +    } else if (encode_kind & DER_INLINE) {
   1.330 +	dtemplate = dtemplate->sub;
   1.331 +	under_kind = dtemplate->kind;
   1.332 +	if (universal) {
   1.333 +	    encode_kind = under_kind;
   1.334 +	}
   1.335 +	src = (void *)((char *)src + dtemplate->offset);
   1.336 +    } else if (universal) {
   1.337 +	under_kind = encode_kind;
   1.338 +    } else {
   1.339 +	under_kind = dtemplate->arg;
   1.340 +    }
   1.341 +
   1.342 +    if (explicit) {
   1.343 +	buf = DER_StoreHeader (buf, encode_kind,
   1.344 +			       (1 + DER_LengthLength(contents_len)
   1.345 +				+ contents_len));
   1.346 +	encode_kind = under_kind;
   1.347 +    }
   1.348 +
   1.349 +    if ((encode_kind & DER_ANY) == 0) {	/* DER_ANY already contains header */
   1.350 +	buf = DER_StoreHeader (buf, encode_kind, contents_len);
   1.351 +    }
   1.352 +
   1.353 +    /* If no real contents to encode, then we are done.  */
   1.354 +    if (contents_len == 0)
   1.355 +	return buf;
   1.356 +
   1.357 +    if (under_kind & DER_INDEFINITE) {
   1.358 +	void **indp;
   1.359 +
   1.360 +	indp = *(void ***)src;
   1.361 +	PORT_Assert (indp != NULL);
   1.362 +
   1.363 +	under_kind &= ~DER_INDEFINITE;
   1.364 +	if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
   1.365 +	    DERTemplate *tmpt = dtemplate->sub;
   1.366 +	    PORT_Assert (tmpt != NULL);
   1.367 +	    for (; *indp != NULL; indp++) {
   1.368 +		void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
   1.369 +		buf = der_encode (buf, tmpt, sub_src);
   1.370 +	    }
   1.371 +	} else {
   1.372 +	    for (; *indp != NULL; indp++) {
   1.373 +		SECItem *item;
   1.374 +		int sub_len;
   1.375 +
   1.376 +		item = (SECItem *)(*indp);
   1.377 +		sub_len = item->len;
   1.378 +		if (under_kind == DER_BIT_STRING) {
   1.379 +		    if (sub_len) {
   1.380 +			int rem;
   1.381 +
   1.382 +			sub_len = (sub_len + 7) >> 3;
   1.383 +			buf = DER_StoreHeader (buf, under_kind, sub_len + 1);
   1.384 +			rem = (sub_len << 3) - item->len;
   1.385 +			*buf++ = rem;		/* remaining bits */
   1.386 +		    } else {
   1.387 +			buf = DER_StoreHeader (buf, under_kind, 0);
   1.388 +		    }
   1.389 +		} else if (under_kind != DER_ANY) {
   1.390 +		    buf = DER_StoreHeader (buf, under_kind, sub_len);
   1.391 +		}
   1.392 +		PORT_Memcpy (buf, item->data, sub_len);
   1.393 +		buf += sub_len;
   1.394 +	    }
   1.395 +	}
   1.396 +	return buf;
   1.397 +    }
   1.398 +
   1.399 +    switch (under_kind) {
   1.400 +      case DER_SEQUENCE:
   1.401 +      case DER_SET:
   1.402 +	{
   1.403 +	    DERTemplate *tmpt;
   1.404 +	    void *sub_src;
   1.405 +
   1.406 +	    for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
   1.407 +		sub_src = (void *)((char *)src + tmpt->offset);
   1.408 +		buf = der_encode (buf, tmpt, sub_src);
   1.409 +	    }
   1.410 +	}
   1.411 +	break;
   1.412 +
   1.413 +      case DER_BIT_STRING:
   1.414 +	{
   1.415 +	    SECItem *item;
   1.416 +	    int rem;
   1.417 +
   1.418 +	    /*
   1.419 +	     * The contents length includes our extra octet; subtract
   1.420 +	     * it off so we just have the real string length there.
   1.421 +	     */
   1.422 +	    contents_len--;
   1.423 +	    item = (SECItem *)src;
   1.424 +	    PORT_Assert (contents_len == ((item->len + 7) >> 3));
   1.425 +	    rem = (contents_len << 3) - item->len;
   1.426 +	    *buf++ = rem;		/* remaining bits */
   1.427 +	    PORT_Memcpy (buf, item->data, contents_len);
   1.428 +	    buf += contents_len;
   1.429 +	}
   1.430 +	break;
   1.431 +
   1.432 +      default:
   1.433 +	{
   1.434 +	    SECItem *item;
   1.435 +
   1.436 +	    item = (SECItem *)src;
   1.437 +	    PORT_Assert (contents_len == item->len);
   1.438 +	    PORT_Memcpy (buf, item->data, contents_len);
   1.439 +	    buf += contents_len;
   1.440 +	}
   1.441 +	break;
   1.442 +    }
   1.443 +
   1.444 +    return buf;
   1.445 +}
   1.446 +
   1.447 +
   1.448 +SECStatus
   1.449 +DER_Encode(PLArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src)
   1.450 +{
   1.451 +    unsigned int contents_len, header_len;
   1.452 +
   1.453 +    src = (void **)((char *)src + dtemplate->offset);
   1.454 +
   1.455 +    /*
   1.456 +     * First figure out how long the encoding will be. Do this by
   1.457 +     * traversing the template from top to bottom and accumulating
   1.458 +     * the length of each leaf item.
   1.459 +     */
   1.460 +    contents_len = contents_length (dtemplate, src);
   1.461 +    header_len = header_length (dtemplate, contents_len);
   1.462 +
   1.463 +    dest->len = contents_len + header_len;
   1.464 +
   1.465 +    /* Allocate storage to hold the encoding */
   1.466 +    dest->data = (unsigned char*) PORT_ArenaAlloc(arena, dest->len);
   1.467 +    if (dest->data == NULL) {
   1.468 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.469 +	return SECFailure;
   1.470 +    }
   1.471 +
   1.472 +    /* Now encode into the buffer */
   1.473 +    (void) der_encode (dest->data, dtemplate, src);
   1.474 +
   1.475 +    return SECSuccess;
   1.476 +}

mercurial