Backing out derdec.c ver 1.3.28.1 and commiting back ver 1.3 NSS_3_11_BRANCH
authorbiswatosh.chakraborty%sun.com
Mon, 01 Oct 2007 16:09:19 +0000
branchNSS_3_11_BRANCH
changeset 8092 e7235ed37daaf0bfd58dff02780ba7ee3dc6997a
parent 8091 71cdb0d5ae7312df8c419b12165111ee77b376ad
child 8093 c2f1b8e84db364822f07c3f9c98125817fa01fe6
push idunknown
push userunknown
push dateunknown
Backing out derdec.c ver 1.3.28.1 and commiting back ver 1.3 because the cvs comment for ver 1.3.28.1 was blank and hence will now commit that again after this commit, with appropriate comments.
security/nss/lib/util/derdec.c
--- a/security/nss/lib/util/derdec.c
+++ b/security/nss/lib/util/derdec.c
@@ -208,14 +208,348 @@ der_capture(unsigned char *buf, unsigned
     }
 
     *header_len_p = bp - buf;
     *contents_len_p = contents_len;
 
     return SECSuccess;
 }
 
+static unsigned char *
+der_decode(PRArenaPool *arena, void *dest, DERTemplate *dtemplate,
+	   unsigned char *buf, int header_len, uint32 contents_len)
+{
+    unsigned char *orig_buf, *end;
+    unsigned long encode_kind, under_kind;
+    PRBool explicit, optional, universal, check_tag;
+    SECItem *item;
+    SECStatus rv;
+    PRBool indefinite_length, explicit_indefinite_length;
+
+    encode_kind = dtemplate->kind;
+    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
+    optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
+    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+		? PR_TRUE : PR_FALSE;
+
+    PORT_Assert (!(explicit && universal));	/* bad templates */
+
+    if (header_len == 0) {
+	if (optional || (encode_kind & DER_ANY))
+	    return buf;
+	PORT_SetError(SEC_ERROR_BAD_DER);
+	return NULL;
+    }
+
+    if (encode_kind & DER_POINTER) {
+	void *place, **placep;
+	int offset;
+
+	if (dtemplate->sub != NULL) {
+	    dtemplate = dtemplate->sub;
+	    under_kind = dtemplate->kind;
+	    if (universal) {
+		encode_kind = under_kind;
+	    }
+	    place = PORT_ArenaZAlloc(arena, dtemplate->arg);
+	    offset = dtemplate->offset;
+	} else {
+	    if (universal) {
+		under_kind = encode_kind & ~DER_POINTER;
+	    } else {
+		under_kind = dtemplate->arg;
+	    }
+	    place = PORT_ArenaZAlloc(arena, sizeof(SECItem));
+	    offset = 0;
+	}
+	if (place == NULL) {
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	    return NULL;		/* Out of memory */
+	}
+	placep = (void **)dest;
+	*placep = place;
+	dest = (void *)((char *)place + offset);
+    } else if (encode_kind & DER_INLINE) {
+	PORT_Assert (dtemplate->sub != NULL);
+	dtemplate = dtemplate->sub;
+	under_kind = dtemplate->kind;
+	if (universal) {
+	    encode_kind = under_kind;
+	}
+	dest = (void *)((char *)dest + dtemplate->offset);
+    } else if (universal) {
+	under_kind = encode_kind;
+    } else {
+	under_kind = dtemplate->arg;
+    }
+
+    orig_buf = buf;
+    end = buf + header_len + contents_len;
+
+    explicit_indefinite_length = PR_FALSE;
+
+    if (explicit) {
+	/*
+	 * This tag is expected to match exactly.
+	 * (The template has all of the bits specified.)
+	 */
+	if (*buf != (encode_kind & DER_TAG_MASK)) {
+	    if (optional)
+		return buf;
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    return NULL;
+	}
+	if ((header_len == 2) && (*(buf + 1) == 0x80))
+	    explicit_indefinite_length = PR_TRUE;
+	buf += header_len;
+	rv = der_capture (buf, end, &header_len, &contents_len);
+	if (rv != SECSuccess)
+	    return NULL;
+	if (header_len == 0) {		/* XXX is this right? */
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    return NULL;
+	}
+	optional = PR_FALSE;		/* can no longer be optional */
+	encode_kind = under_kind;
+    }
+
+    check_tag = PR_TRUE;
+    if (encode_kind & (DER_DERPTR | DER_ANY | DER_FORCE | DER_SKIP)) {
+	PORT_Assert ((encode_kind & DER_ANY) || !optional);
+	encode_kind = encode_kind & (~DER_FORCE);
+	under_kind = under_kind & (~DER_FORCE);
+	check_tag = PR_FALSE;
+    }
+
+    if (check_tag) {
+	PRBool wrong;
+	unsigned char expect_tag, expect_num;
+
+	/*
+	 * This tag is expected to match, but the simple types
+	 * may or may not have the constructed bit set, so we
+	 * have to have all this extra logic.
+	 */
+	wrong = PR_TRUE;
+	expect_tag = (unsigned char)encode_kind & DER_TAG_MASK;
+	expect_num = expect_tag & DER_TAGNUM_MASK;
+	if (expect_num == DER_SET || expect_num == DER_SEQUENCE) {
+	    if (*buf == (expect_tag | DER_CONSTRUCTED))
+		wrong = PR_FALSE;
+	} else {
+	    if (*buf == expect_tag)
+		wrong = PR_FALSE;
+	    else if (*buf == (expect_tag | DER_CONSTRUCTED))
+		wrong = PR_FALSE;
+	}
+	if (wrong) {
+	    if (optional)
+		return buf;
+	    PORT_SetError(SEC_ERROR_BAD_DER);
+	    return NULL;
+	}
+    }
+
+    if (under_kind & DER_DERPTR) {
+	item = (SECItem *)dest;
+	if (under_kind & DER_OUTER) {
+	    item->data = buf;
+	    item->len = header_len + contents_len;
+	} else {
+	    item->data = buf + header_len;
+	    item->len = contents_len;
+	}
+	return orig_buf;
+    }
+
+    if (encode_kind & DER_ANY) {
+	contents_len += header_len;
+	header_len = 0;
+    }
+
+    if ((header_len == 2) && (*(buf + 1) == 0x80))
+	indefinite_length = PR_TRUE;
+    else
+	indefinite_length = PR_FALSE;
+
+    buf += header_len;
+
+    if (contents_len == 0)
+	return buf;
+
+    under_kind &= ~DER_OPTIONAL;
+
+    if (under_kind & DER_INDEFINITE) {
+	int count, thing_size;
+	unsigned char *sub_buf;
+	DERTemplate *tmpt;
+	void *things, **indp, ***placep;
+
+	under_kind &= ~DER_INDEFINITE;
+
+	/*
+	 * Count items.
+	 */
+	count = 0;
+	sub_buf = buf;
+	while (sub_buf < end) {
+	    if (indefinite_length && sub_buf[0] == 0 && sub_buf[1] == 0) {
+		break; 
+	    }
+	    rv = der_capture (sub_buf, end, &header_len, &contents_len);
+	    if (rv != SECSuccess)
+		return NULL;
+	    count++;
+	    sub_buf += header_len + contents_len;
+	}
+
+	/*
+	 * Allocate an array of pointers to items; extra one is for a NULL.
+	 */
+	indp = (void**)PORT_ArenaZAlloc(arena, (count + 1) * sizeof(void *));
+	if (indp == NULL) {
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	    return NULL;
+	}
+
+	/*
+	 * Prepare.
+	 */
+	if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
+	    tmpt = dtemplate->sub;
+	    PORT_Assert (tmpt != NULL);
+	    thing_size = tmpt->arg;
+	    PORT_Assert (thing_size != 0);
+	} else {
+	    tmpt = NULL;
+	    thing_size = sizeof(SECItem);
+	}
+
+	/*
+	 * Allocate the items themselves.
+	 */
+	things = PORT_ArenaZAlloc(arena, count * thing_size);
+	if (things == NULL) {
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	    return NULL;
+	}
+
+	placep = (void ***)dest;
+	*placep = indp;
+
+	while (count) {
+	    /* ignore return value because we already did whole thing above */
+	    (void) der_capture (buf, end, &header_len, &contents_len);
+	    if (tmpt != NULL) {
+		void *sub_thing;
+
+		sub_thing = (void *)((char *)things + tmpt->offset);
+		buf = der_decode (arena, sub_thing, tmpt,
+				  buf, header_len, contents_len);
+		if (buf == NULL)
+		    return NULL;
+	    } else {
+		item = (SECItem *)things;
+		if (under_kind == DER_ANY) {
+		    contents_len += header_len;
+		    header_len = 0;
+		}
+		buf += header_len;
+		if (under_kind == DER_BIT_STRING) {
+		    item->data = buf + 1;
+		    item->len = ((contents_len - 1) << 3) - *buf;
+		} else {
+		    item->data = buf;
+		    item->len = contents_len;
+		}
+		buf += contents_len;
+	    }
+	    *indp++ = things;
+	    things = (void *)((char *)things + thing_size);
+	    count--;
+	}
+
+	*indp = NULL;
+
+	goto der_decode_done;
+    }
+
+    switch (under_kind) {
+      case DER_SEQUENCE:
+      case DER_SET:
+	{
+	    DERTemplate *tmpt;
+	    void *sub_dest;
+
+	    for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
+		sub_dest = (void *)((char *)dest + tmpt->offset);
+		rv = der_capture (buf, end, &header_len, &contents_len);
+		if (rv != SECSuccess)
+		    return NULL;
+		buf = der_decode (arena, sub_dest, tmpt,
+				  buf, header_len, contents_len);
+		if (buf == NULL)
+		    return NULL;
+	    }
+	}
+	break;
+
+      case DER_BIT_STRING:
+	item = (SECItem *)dest;
+	item->data = buf + 1;
+	item->len = ((contents_len - 1) << 3) - *buf;
+	buf += contents_len;
+	break;
+
+      case DER_SKIP:
+	buf += contents_len;
+	break;
+
+      default:
+	item = (SECItem *)dest;
+	item->data = buf;
+	item->len = contents_len;
+	buf += contents_len;
+	break;
+    }
+
+der_decode_done:
+
+    if (indefinite_length && buf[0] == 0 && buf[1] == 0) {
+	buf += 2;
+    }
+
+    if (explicit_indefinite_length && buf[0] == 0 && buf[1] == 0) {
+	buf += 2;
+    }
+
+    return buf;
+}
+
+SECStatus
+DER_Decode(PRArenaPool *arena, void *dest, DERTemplate *dtemplate, SECItem *src)
+{
+    unsigned char *buf;
+    uint32 buf_len, contents_len;
+    int header_len;
+    SECStatus rv;
+
+    buf = src->data;
+    buf_len = src->len;
+
+    rv = der_capture (buf, buf + buf_len, &header_len, &contents_len);
+    if (rv != SECSuccess)
+	return rv;
+
+    dest = (void *)((char *)dest + dtemplate->offset);
+    buf = der_decode (arena, dest, dtemplate, buf, header_len, contents_len);
+    if (buf == NULL)
+	return SECFailure;
+
+    return SECSuccess;
+}
+
 SECStatus
 DER_Lengths(SECItem *item, int *header_len_p, uint32 *contents_len_p)
 {
     return(der_capture(item->data, &item->data[item->len], header_len_p,
 		       contents_len_p));
 }