summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbiswatosh.chakraborty%sun.com <devnull@localhost>2007-10-01 16:09:19 +0000
committerbiswatosh.chakraborty%sun.com <devnull@localhost>2007-10-01 16:09:19 +0000
commit85b1aa52c60cae80640d0ecabc3f24d35e2d854a (patch)
treea4d8bbd46012a18f722e6a48eafa375339488e12
parent665a2bafd65ee0c63e3b13968f2491f319b3e24d (diff)
downloadnss-hg-85b1aa52c60cae80640d0ecabc3f24d35e2d854a.tar.gz
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.
-rw-r--r--security/nss/lib/util/derdec.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/security/nss/lib/util/derdec.c b/security/nss/lib/util/derdec.c
index 544dde221..b0215c61f 100644
--- a/security/nss/lib/util/derdec.c
+++ b/security/nss/lib/util/derdec.c
@@ -213,6 +213,340 @@ der_capture(unsigned char *buf, unsigned char *end,
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)
{