summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/jar
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/jar')
-rw-r--r--security/nss/lib/jar/Makefile11
-rw-r--r--security/nss/lib/jar/config.mk26
-rw-r--r--security/nss/lib/jar/exports.gyp27
-rw-r--r--security/nss/lib/jar/jar-ds.c36
-rw-r--r--security/nss/lib/jar/jar-ds.h77
-rw-r--r--security/nss/lib/jar/jar.c687
-rw-r--r--security/nss/lib/jar/jar.gyp76
-rw-r--r--security/nss/lib/jar/jar.h372
-rw-r--r--security/nss/lib/jar/jarfile.c966
-rw-r--r--security/nss/lib/jar/jarfile.h76
-rw-r--r--security/nss/lib/jar/jarint.c52
-rw-r--r--security/nss/lib/jar/jarint.h54
-rw-r--r--security/nss/lib/jar/jarnav.c63
-rw-r--r--security/nss/lib/jar/jarsign.c250
-rw-r--r--security/nss/lib/jar/jarver.c1167
-rw-r--r--security/nss/lib/jar/jzconf.h189
-rw-r--r--security/nss/lib/jar/jzlib.h916
-rw-r--r--security/nss/lib/jar/manifest.mn25
18 files changed, 5070 insertions, 0 deletions
diff --git a/security/nss/lib/jar/Makefile b/security/nss/lib/jar/Makefile
new file mode 100644
index 000000000..245c127a4
--- /dev/null
+++ b/security/nss/lib/jar/Makefile
@@ -0,0 +1,11 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+include manifest.mn
+include $(CORE_DEPTH)/coreconf/config.mk
+include config.mk
+include $(CORE_DEPTH)/coreconf/rules.mk
+
diff --git a/security/nss/lib/jar/config.mk b/security/nss/lib/jar/config.mk
new file mode 100644
index 000000000..1412dcc59
--- /dev/null
+++ b/security/nss/lib/jar/config.mk
@@ -0,0 +1,26 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+TARGETS = $(LIBRARY)
+SHARED_LIBRARY =
+IMPORT_LIBRARY =
+PROGRAM =
+
+# NSS_X86 means the target is a 32-bits x86 CPU architecture
+# NSS_X64 means the target is a 64-bits x64 CPU architecture
+# NSS_X86_OR_X64 means the target is either x86 or x64
+ifeq (,$(filter-out i386 x386 x86 x86_64,$(CPU_ARCH)))
+ DEFINES += -DNSS_X86_OR_X64
+ifdef USE_64
+ DEFINES += -DNSS_X64
+else
+ DEFINES += -DNSS_X86
+endif
+endif
diff --git a/security/nss/lib/jar/exports.gyp b/security/nss/lib/jar/exports.gyp
new file mode 100644
index 000000000..94ee144e8
--- /dev/null
+++ b/security/nss/lib/jar/exports.gyp
@@ -0,0 +1,27 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'lib_jar_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ 'jar-ds.h',
+ 'jar.h',
+ 'jarfile.h'
+ ],
+ 'destination': '<(nss_public_dist_dir)/<(module)'
+ }
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/jar/jar-ds.c b/security/nss/lib/jar/jar-ds.c
new file mode 100644
index 000000000..8962305ca
--- /dev/null
+++ b/security/nss/lib/jar/jar-ds.c
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jar.h"
+
+/* These are old DS_* routines renamed to ZZ_* */
+ZZList *
+ZZ_NewList(void)
+{
+ ZZList *list = (ZZList *)PORT_ZAlloc(sizeof(ZZList));
+ if (list)
+ ZZ_InitList(list);
+ return list;
+}
+
+ZZLink *
+ZZ_NewLink(JAR_Item *thing)
+{
+ ZZLink *link = (ZZLink *)PORT_ZAlloc(sizeof(ZZLink));
+ if (link)
+ link->thing = thing;
+ return link;
+}
+
+void
+ZZ_DestroyLink(ZZLink *link)
+{
+ PORT_Free(link);
+}
+
+void
+ZZ_DestroyList(ZZList *list)
+{
+ PORT_Free(list);
+}
diff --git a/security/nss/lib/jar/jar-ds.h b/security/nss/lib/jar/jar-ds.h
new file mode 100644
index 000000000..9818c66c9
--- /dev/null
+++ b/security/nss/lib/jar/jar-ds.h
@@ -0,0 +1,77 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __JAR_DS_h_
+#define __JAR_DS_h_
+
+/* Typedefs */
+typedef struct ZZLinkStr ZZLink;
+typedef struct ZZListStr ZZList;
+
+/*
+** Circular linked list. Each link contains a pointer to the object that
+** is actually in the list.
+*/
+struct ZZLinkStr {
+ ZZLink *next;
+ ZZLink *prev;
+ JAR_Item *thing;
+};
+
+struct ZZListStr {
+ ZZLink link;
+};
+
+#define ZZ_InitList(lst) \
+ { \
+ (lst)->link.next = &(lst)->link; \
+ (lst)->link.prev = &(lst)->link; \
+ (lst)->link.thing = 0; \
+ }
+
+#define ZZ_ListEmpty(lst) ((lst)->link.next == &(lst)->link)
+
+#define ZZ_ListHead(lst) ((lst)->link.next)
+
+#define ZZ_ListTail(lst) ((lst)->link.prev)
+
+#define ZZ_ListIterDone(lst, lnk) ((lnk) == &(lst)->link)
+
+#define ZZ_AppendLink(lst, lnk) \
+ { \
+ (lnk)->next = &(lst)->link; \
+ (lnk)->prev = (lst)->link.prev; \
+ (lst)->link.prev->next = (lnk); \
+ (lst)->link.prev = (lnk); \
+ }
+
+#define ZZ_InsertLink(lst, lnk) \
+ { \
+ (lnk)->next = (lst)->link.next; \
+ (lnk)->prev = &(lst)->link; \
+ (lst)->link.next->prev = (lnk); \
+ (lst)->link.next = (lnk); \
+ }
+
+#define ZZ_RemoveLink(lnk) \
+ { \
+ (lnk)->next->prev = (lnk)->prev; \
+ (lnk)->prev->next = (lnk)->next; \
+ (lnk)->next = 0; \
+ (lnk)->prev = 0; \
+ }
+
+extern ZZLink *
+ZZ_NewLink(JAR_Item *thing);
+
+extern void
+ZZ_DestroyLink(ZZLink *link);
+
+extern ZZList *
+ZZ_NewList(void);
+
+extern void
+ZZ_DestroyList(ZZList *list);
+
+#endif /* __JAR_DS_h_ */
diff --git a/security/nss/lib/jar/jar.c b/security/nss/lib/jar/jar.c
new file mode 100644
index 000000000..00a55463e
--- /dev/null
+++ b/security/nss/lib/jar/jar.c
@@ -0,0 +1,687 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * JAR.C
+ *
+ * Jarnature.
+ * Routines common to signing and validating.
+ *
+ */
+
+#include "jar.h"
+#include "jarint.h"
+#include "portreg.h"
+
+static void
+jar_destroy_list(ZZList *list);
+
+static int
+jar_find_first_cert(JAR_Signer *signer, int type, JAR_Item **it);
+
+/*
+ * J A R _ n e w
+ *
+ * Create a new instantiation of a manifest representation.
+ * Use this as a token to any calls to this API.
+ *
+ */
+JAR *
+JAR_new(void)
+{
+ JAR *jar;
+
+ if ((jar = (JAR *)PORT_ZAlloc(sizeof(JAR))) == NULL)
+ goto loser;
+ if ((jar->manifest = ZZ_NewList()) == NULL)
+ goto loser;
+ if ((jar->hashes = ZZ_NewList()) == NULL)
+ goto loser;
+ if ((jar->phy = ZZ_NewList()) == NULL)
+ goto loser;
+ if ((jar->metainfo = ZZ_NewList()) == NULL)
+ goto loser;
+ if ((jar->signers = ZZ_NewList()) == NULL)
+ goto loser;
+ return jar;
+
+loser:
+ if (jar) {
+ if (jar->manifest)
+ ZZ_DestroyList(jar->manifest);
+ if (jar->hashes)
+ ZZ_DestroyList(jar->hashes);
+ if (jar->phy)
+ ZZ_DestroyList(jar->phy);
+ if (jar->metainfo)
+ ZZ_DestroyList(jar->metainfo);
+ if (jar->signers)
+ ZZ_DestroyList(jar->signers);
+ PORT_Free(jar);
+ }
+ return NULL;
+}
+
+/*
+ * J A R _ d e s t r o y
+ */
+void PR_CALLBACK
+JAR_destroy(JAR *jar)
+{
+ PORT_Assert(jar != NULL);
+
+ if (jar == NULL)
+ return;
+
+ if (jar->fp)
+ JAR_FCLOSE((PRFileDesc *)jar->fp);
+ if (jar->url)
+ PORT_Free(jar->url);
+ if (jar->filename)
+ PORT_Free(jar->filename);
+ if (jar->globalmeta)
+ PORT_Free(jar->globalmeta);
+
+ /* Free the linked list elements */
+ jar_destroy_list(jar->manifest);
+ ZZ_DestroyList(jar->manifest);
+ jar_destroy_list(jar->hashes);
+ ZZ_DestroyList(jar->hashes);
+ jar_destroy_list(jar->phy);
+ ZZ_DestroyList(jar->phy);
+ jar_destroy_list(jar->metainfo);
+ ZZ_DestroyList(jar->metainfo);
+ jar_destroy_list(jar->signers);
+ ZZ_DestroyList(jar->signers);
+ PORT_Free(jar);
+}
+
+static void
+jar_destroy_list(ZZList *list)
+{
+ ZZLink *link, *oldlink;
+ JAR_Item *it;
+ JAR_Physical *phy;
+ JAR_Digest *dig;
+ JAR_Cert *fing;
+ JAR_Metainfo *met;
+ JAR_Signer *signer;
+
+ if (list && !ZZ_ListEmpty(list)) {
+ link = ZZ_ListHead(list);
+ while (!ZZ_ListIterDone(list, link)) {
+ it = link->thing;
+ if (!it)
+ goto next;
+ if (it->pathname)
+ PORT_Free(it->pathname);
+
+ switch (it->type) {
+ case jarTypeMeta:
+ met = (JAR_Metainfo *)it->data;
+ if (met) {
+ if (met->header)
+ PORT_Free(met->header);
+ if (met->info)
+ PORT_Free(met->info);
+ PORT_Free(met);
+ }
+ break;
+
+ case jarTypePhy:
+ phy = (JAR_Physical *)it->data;
+ if (phy)
+ PORT_Free(phy);
+ break;
+
+ case jarTypeSign:
+ fing = (JAR_Cert *)it->data;
+ if (fing) {
+ if (fing->cert)
+ CERT_DestroyCertificate(fing->cert);
+ if (fing->key)
+ PORT_Free(fing->key);
+ PORT_Free(fing);
+ }
+ break;
+
+ case jarTypeSect:
+ case jarTypeMF:
+ case jarTypeSF:
+ dig = (JAR_Digest *)it->data;
+ if (dig) {
+ PORT_Free(dig);
+ }
+ break;
+
+ case jarTypeOwner:
+ signer = (JAR_Signer *)it->data;
+ if (signer)
+ JAR_destroy_signer(signer);
+ break;
+
+ default:
+ /* PORT_Assert( 1 != 2 ); */
+ break;
+ }
+ PORT_Free(it);
+
+ next:
+ oldlink = link;
+ link = link->next;
+ ZZ_DestroyLink(oldlink);
+ }
+ }
+}
+
+/*
+ * J A R _ g e t _ m e t a i n f o
+ *
+ * Retrieve meta information from the manifest file.
+ * It doesn't matter whether it's from .MF or .SF, does it?
+ *
+ */
+
+int
+JAR_get_metainfo(JAR *jar, char *name, char *header, void **info,
+ unsigned long *length)
+{
+ JAR_Item *it;
+ ZZLink *link;
+ ZZList *list;
+
+ PORT_Assert(jar != NULL && header != NULL);
+
+ if (jar == NULL || header == NULL)
+ return JAR_ERR_PNF;
+
+ list = jar->metainfo;
+
+ if (ZZ_ListEmpty(list))
+ return JAR_ERR_PNF;
+
+ for (link = ZZ_ListHead(list);
+ !ZZ_ListIterDone(list, link);
+ link = link->next) {
+ it = link->thing;
+ if (it->type == jarTypeMeta) {
+ JAR_Metainfo *met;
+
+ if ((name && !it->pathname) || (!name && it->pathname))
+ continue;
+ if (name && it->pathname && strcmp(it->pathname, name))
+ continue;
+ met = (JAR_Metainfo *)it->data;
+ if (!PORT_Strcasecmp(met->header, header)) {
+ *info = PORT_Strdup(met->info);
+ *length = PORT_Strlen(met->info);
+ return 0;
+ }
+ }
+ }
+ return JAR_ERR_PNF;
+}
+
+/*
+ * J A R _ f i n d
+ *
+ * Establish the search pattern for use
+ * by JAR_find_next, to traverse the filenames
+ * or certificates in the JAR structure.
+ *
+ * See jar.h for a description on how to use.
+ *
+ */
+JAR_Context *
+JAR_find(JAR *jar, char *pattern, jarType type)
+{
+ JAR_Context *ctx;
+
+ PORT_Assert(jar != NULL);
+
+ if (!jar)
+ return NULL;
+
+ ctx = (JAR_Context *)PORT_ZAlloc(sizeof(JAR_Context));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->jar = jar;
+ if (pattern) {
+ if ((ctx->pattern = PORT_Strdup(pattern)) == NULL) {
+ PORT_Free(ctx);
+ return NULL;
+ }
+ }
+ ctx->finding = type;
+
+ switch (type) {
+ case jarTypeMF:
+ ctx->next = ZZ_ListHead(jar->hashes);
+ break;
+
+ case jarTypeSF:
+ case jarTypeSign:
+ ctx->next = NULL;
+ ctx->nextsign = ZZ_ListHead(jar->signers);
+ break;
+
+ case jarTypeSect:
+ ctx->next = ZZ_ListHead(jar->manifest);
+ break;
+
+ case jarTypePhy:
+ ctx->next = ZZ_ListHead(jar->phy);
+ break;
+
+ case jarTypeOwner:
+ if (jar->signers)
+ ctx->next = ZZ_ListHead(jar->signers);
+ else
+ ctx->next = NULL;
+ break;
+
+ case jarTypeMeta:
+ ctx->next = ZZ_ListHead(jar->metainfo);
+ break;
+
+ default:
+ PORT_Assert(1 != 2);
+ break;
+ }
+ return ctx;
+}
+
+/*
+ * J A R _ f i n d _ e n d
+ *
+ * Destroy the find iterator context.
+ *
+ */
+void
+JAR_find_end(JAR_Context *ctx)
+{
+ PORT_Assert(ctx != NULL);
+ if (ctx) {
+ if (ctx->pattern)
+ PORT_Free(ctx->pattern);
+ PORT_Free(ctx);
+ }
+}
+
+/*
+ * J A R _ f i n d _ n e x t
+ *
+ * Return the next item of the given type
+ * from one of the JAR linked lists.
+ *
+ */
+
+int
+JAR_find_next(JAR_Context *ctx, JAR_Item **it)
+{
+ JAR *jar;
+ ZZList *list = NULL;
+ int finding;
+ JAR_Signer *signer = NULL;
+
+ PORT_Assert(ctx != NULL);
+ PORT_Assert(ctx->jar != NULL);
+
+ jar = ctx->jar;
+
+ /* Internally, convert jarTypeSign to jarTypeSF, and return
+ the actual attached certificate later */
+ finding = (ctx->finding == jarTypeSign) ? jarTypeSF : ctx->finding;
+ if (ctx->nextsign) {
+ if (ZZ_ListIterDone(jar->signers, ctx->nextsign)) {
+ *it = NULL;
+ return -1;
+ }
+ PORT_Assert(ctx->nextsign->thing != NULL);
+ signer = (JAR_Signer *)ctx->nextsign->thing->data;
+ }
+
+ /* Find out which linked list to traverse. Then if
+ necessary, advance to the next linked list. */
+ while (1) {
+ switch (finding) {
+ case jarTypeSign: /* not any more */
+ PORT_Assert(finding != jarTypeSign);
+ list = signer->certs;
+ break;
+
+ case jarTypeSect:
+ list = jar->manifest;
+ break;
+
+ case jarTypePhy:
+ list = jar->phy;
+ break;
+
+ case jarTypeSF: /* signer, not jar */
+ PORT_Assert(signer != NULL);
+ list = signer ? signer->sf : NULL;
+ break;
+
+ case jarTypeMF:
+ list = jar->hashes;
+ break;
+
+ case jarTypeOwner:
+ list = jar->signers;
+ break;
+
+ case jarTypeMeta:
+ list = jar->metainfo;
+ break;
+
+ default:
+ PORT_Assert(1 != 2);
+ list = NULL;
+ break;
+ }
+ if (list == NULL) {
+ *it = NULL;
+ return -1;
+ }
+ /* When looping over lists of lists, advance to the next signer.
+ This is done when multiple signers are possible. */
+ if (ZZ_ListIterDone(list, ctx->next)) {
+ if (ctx->nextsign && jar->signers) {
+ ctx->nextsign = ctx->nextsign->next;
+ if (!ZZ_ListIterDone(jar->signers, ctx->nextsign)) {
+ PORT_Assert(ctx->nextsign->thing != NULL);
+ signer = (JAR_Signer *)ctx->nextsign->thing->data;
+ PORT_Assert(signer != NULL);
+ ctx->next = NULL;
+ continue;
+ }
+ }
+ *it = NULL;
+ return -1;
+ }
+
+ /* if the signer changed, still need to fill in the "next" link */
+ if (ctx->nextsign && ctx->next == NULL) {
+ switch (finding) {
+ case jarTypeSF:
+ ctx->next = ZZ_ListHead(signer->sf);
+ break;
+
+ case jarTypeSign:
+ ctx->next = ZZ_ListHead(signer->certs);
+ break;
+ }
+ }
+ PORT_Assert(ctx->next != NULL);
+ if (ctx->next == NULL) {
+ *it = NULL;
+ return -1;
+ }
+ while (!ZZ_ListIterDone(list, ctx->next)) {
+ *it = ctx->next->thing;
+ ctx->next = ctx->next->next;
+ if (!*it || (*it)->type != finding)
+ continue;
+ if (ctx->pattern && *ctx->pattern) {
+ if (PORT_RegExpSearch((*it)->pathname, ctx->pattern))
+ continue;
+ }
+ /* We have a valid match. If this is a jarTypeSign
+ return the certificate instead.. */
+ if (ctx->finding == jarTypeSign) {
+ JAR_Item *itt;
+
+ /* just the first one for now */
+ if (jar_find_first_cert(signer, jarTypeSign, &itt) >= 0) {
+ *it = itt;
+ return 0;
+ }
+ continue;
+ }
+ return 0;
+ }
+ } /* end while */
+}
+
+static int
+jar_find_first_cert(JAR_Signer *signer, int type, JAR_Item **it)
+{
+ ZZLink *link;
+ ZZList *list = signer->certs;
+ int status = JAR_ERR_PNF;
+
+ *it = NULL;
+ if (ZZ_ListEmpty(list)) {
+ /* empty list */
+ return JAR_ERR_PNF;
+ }
+
+ for (link = ZZ_ListHead(list);
+ !ZZ_ListIterDone(list, link);
+ link = link->next) {
+ if (link->thing->type == type) {
+ *it = link->thing;
+ status = 0;
+ break;
+ }
+ }
+ return status;
+}
+
+JAR_Signer *
+JAR_new_signer(void)
+{
+ JAR_Signer *signer = (JAR_Signer *)PORT_ZAlloc(sizeof(JAR_Signer));
+ if (signer == NULL)
+ goto loser;
+
+ /* certs */
+ signer->certs = ZZ_NewList();
+ if (signer->certs == NULL)
+ goto loser;
+
+ /* sf */
+ signer->sf = ZZ_NewList();
+ if (signer->sf == NULL)
+ goto loser;
+ return signer;
+
+loser:
+ if (signer) {
+ if (signer->certs)
+ ZZ_DestroyList(signer->certs);
+ if (signer->sf)
+ ZZ_DestroyList(signer->sf);
+ PORT_Free(signer);
+ }
+ return NULL;
+}
+
+void
+JAR_destroy_signer(JAR_Signer *signer)
+{
+ if (signer) {
+ if (signer->owner)
+ PORT_Free(signer->owner);
+ if (signer->digest)
+ PORT_Free(signer->digest);
+ jar_destroy_list(signer->sf);
+ ZZ_DestroyList(signer->sf);
+ jar_destroy_list(signer->certs);
+ ZZ_DestroyList(signer->certs);
+ PORT_Free(signer);
+ }
+}
+
+JAR_Signer *
+jar_get_signer(JAR *jar, char *basename)
+{
+ JAR_Item *it;
+ JAR_Context *ctx = JAR_find(jar, NULL, jarTypeOwner);
+ JAR_Signer *candidate;
+ JAR_Signer *signer = NULL;
+
+ if (ctx == NULL)
+ return NULL;
+
+ while (JAR_find_next(ctx, &it) >= 0) {
+ candidate = (JAR_Signer *)it->data;
+ if (*basename == '*' || !PORT_Strcmp(candidate->owner, basename)) {
+ signer = candidate;
+ break;
+ }
+ }
+ JAR_find_end(ctx);
+ return signer;
+}
+
+/*
+ * J A R _ g e t _ f i l e n a m e
+ *
+ * Returns the filename associated with
+ * a JAR structure.
+ *
+ */
+char *
+JAR_get_filename(JAR *jar)
+{
+ return jar->filename;
+}
+
+/*
+ * J A R _ g e t _ u r l
+ *
+ * Returns the URL associated with
+ * a JAR structure. Nobody really uses this now.
+ *
+ */
+char *
+JAR_get_url(JAR *jar)
+{
+ return jar->url;
+}
+
+/*
+ * J A R _ s e t _ c a l l b a c k
+ *
+ * Register some manner of callback function for this jar.
+ *
+ */
+int
+JAR_set_callback(int type, JAR *jar, jar_settable_callback_fn *fn)
+{
+ if (type == JAR_CB_SIGNAL) {
+ jar->signal = fn;
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * Callbacks
+ *
+ */
+
+/* To return an error string */
+char *(*jar_fn_GetString)(int) = NULL;
+
+/* To return an MWContext for Java */
+void *(*jar_fn_FindSomeContext)(void) = NULL;
+
+/* To fabricate an MWContext for FE_GetPassword */
+void *(*jar_fn_GetInitContext)(void) = NULL;
+
+void
+JAR_init_callbacks(char *(*string_cb)(int),
+ void *(*find_cx)(void),
+ void *(*init_cx)(void))
+{
+ jar_fn_GetString = string_cb;
+ jar_fn_FindSomeContext = find_cx;
+ jar_fn_GetInitContext = init_cx;
+}
+
+/*
+ * J A R _ g e t _ e r r o r
+ *
+ * This is provided to map internal JAR errors to strings for
+ * the Java console. Also, a DLL may call this function if it does
+ * not have access to the XP_GetString function.
+ *
+ * These strings aren't UI, since they are Java console only.
+ *
+ */
+char *
+JAR_get_error(int status)
+{
+ char *errstring = NULL;
+
+ switch (status) {
+ case JAR_ERR_GENERAL:
+ errstring = "General JAR file error";
+ break;
+
+ case JAR_ERR_FNF:
+ errstring = "JAR file not found";
+ break;
+
+ case JAR_ERR_CORRUPT:
+ errstring = "Corrupt JAR file";
+ break;
+
+ case JAR_ERR_MEMORY:
+ errstring = "Out of memory";
+ break;
+
+ case JAR_ERR_DISK:
+ errstring = "Disk error (perhaps out of space)";
+ break;
+
+ case JAR_ERR_ORDER:
+ errstring = "Inconsistent files in META-INF directory";
+ break;
+
+ case JAR_ERR_SIG:
+ errstring = "Invalid digital signature file";
+ break;
+
+ case JAR_ERR_METADATA:
+ errstring = "JAR metadata failed verification";
+ break;
+
+ case JAR_ERR_ENTRY:
+ errstring = "No Manifest entry for this JAR entry";
+ break;
+
+ case JAR_ERR_HASH:
+ errstring = "Invalid Hash of this JAR entry";
+ break;
+
+ case JAR_ERR_PK7:
+ errstring = "Strange PKCS7 or RSA failure";
+ break;
+
+ case JAR_ERR_PNF:
+ errstring = "Path not found inside JAR file";
+ break;
+
+ default:
+ if (jar_fn_GetString) {
+ errstring = jar_fn_GetString(status);
+ } else {
+ /* this is not a normal situation, and would only be
+ called in cases of improper initialization */
+ char *err = (char *)PORT_Alloc(40);
+ if (err)
+ PR_snprintf(err, 39, "Error %d\n", status); /* leak me! */
+ else
+ err = "Error! Bad! Out of memory!";
+ return err;
+ }
+ break;
+ }
+ return errstring;
+}
diff --git a/security/nss/lib/jar/jar.gyp b/security/nss/lib/jar/jar.gyp
new file mode 100644
index 000000000..e38b4ab99
--- /dev/null
+++ b/security/nss/lib/jar/jar.gyp
@@ -0,0 +1,76 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'jar',
+ 'type': 'static_library',
+ 'sources': [
+ 'jar-ds.c',
+ 'jar.c',
+ 'jarfile.c',
+ 'jarint.c',
+ 'jarsign.c',
+ 'jarver.c'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ]
+ }
+ ],
+ 'target_defaults': {
+ 'defines': [
+ 'MOZILLA_CLIENT=1',
+ ],
+ 'conditions': [
+ [ 'OS=="win"', {
+ 'configurations': {
+ 'x86_Base': {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'PreprocessorDefinitions': [
+ 'NSS_X86_OR_X64',
+ 'NSS_X86',
+ ],
+ },
+ },
+ },
+ 'x64_Base': {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'PreprocessorDefinitions': [
+ 'NSS_USE_64',
+ 'NSS_X86_OR_X64',
+ 'NSS_X64',
+ ],
+ },
+ },
+ },
+ },
+ }, {
+ 'conditions': [
+ [ 'target_arch=="x64"', {
+ 'defines': [
+ 'NSS_USE_64',
+ 'NSS_X86_OR_X64',
+ 'NSS_X64',
+ ],
+ }],
+ [ 'target_arch=="ia32"', {
+ 'defines': [
+ 'NSS_X86_OR_X64',
+ 'NSS_X86',
+ ],
+ }],
+ ],
+ }],
+ ],
+ },
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/jar/jar.h b/security/nss/lib/jar/jar.h
new file mode 100644
index 000000000..d337cef37
--- /dev/null
+++ b/security/nss/lib/jar/jar.h
@@ -0,0 +1,372 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __JAR_h_
+#define __JAR_h_
+
+/*
+ * In general, any functions that return pointers
+ * have memory owned by the caller.
+ *
+ */
+
+/* security includes */
+#include "cert.h"
+#include "hasht.h"
+
+/* nspr 2.0 includes */
+#include "prio.h"
+
+#define ZHUGEP
+
+#include <stdio.h>
+
+/* various types */
+
+typedef enum {
+ jarTypeMF = 2,
+ jarTypeSF = 3,
+ jarTypeMeta = 6,
+ jarTypePhy = 7,
+ jarTypeSign = 10,
+ jarTypeSect = 11,
+ jarTypeOwner = 13
+} jarType;
+
+/* void data in ZZList's contain JAR_Item type */
+typedef struct JAR_Item_ {
+ char *pathname; /* relative. inside zip file */
+ jarType type; /* various types */
+ size_t size; /* size of data below */
+ void *data; /* totally opaque */
+} JAR_Item;
+
+/* hashes */
+typedef enum {
+ jarHashNone = 0,
+ jarHashBad = 1,
+ jarHashPresent = 2
+} jarHash;
+
+typedef struct JAR_Digest_ {
+ jarHash md5_status;
+ unsigned char md5[MD5_LENGTH];
+ jarHash sha1_status;
+ unsigned char sha1[SHA1_LENGTH];
+} JAR_Digest;
+
+/* physical archive formats */
+typedef enum {
+ jarArchGuess = 0,
+ jarArchNone = 1,
+ jarArchZip = 2,
+ jarArchTar = 3
+} jarArch;
+
+#include "jar-ds.h"
+
+struct JAR_;
+
+typedef int jar_settable_callback_fn(int status, struct JAR_ *jar,
+ const char *metafile, char *pathname,
+ char *errortext);
+
+/* jar object */
+typedef struct JAR_ {
+ jarArch format; /* physical archive format */
+
+ char *url; /* Where it came from */
+ char *filename; /* Disk location */
+ FILE *fp; /* For multiple extractions */
+ /* JAR_FILE */
+
+ /* various linked lists */
+ ZZList *manifest; /* Digests of MF sections */
+ ZZList *hashes; /* Digests of actual signed files */
+ ZZList *phy; /* Physical layout of JAR file */
+ ZZList *metainfo; /* Global metainfo */
+
+ JAR_Digest *globalmeta; /* digest of .MF global portion */
+
+ /* Below will change to a linked list to support multiple sigs */
+ int pkcs7; /* Enforced opaqueness */
+ int valid; /* PKCS7 signature validated */
+
+ ZZList *signers; /* the above, per signer */
+
+ /* Window context, very necessary for PKCS11 now */
+ void *mw; /* MWContext window context */
+
+ /* Signal callback function */
+ jar_settable_callback_fn *signal;
+} JAR;
+
+/*
+ * Iterator
+ *
+ * Context for iterative operations. Certain operations
+ * require iterating multiple linked lists because of
+ * multiple signers. "nextsign" is used for this purpose.
+ *
+ */
+typedef struct JAR_Context_ {
+ JAR *jar; /* Jar we are searching */
+ char *pattern; /* Regular expression */
+ jarType finding; /* Type of item to find */
+ ZZLink *next; /* Next item in find */
+ ZZLink *nextsign; /* Next signer, sometimes */
+} JAR_Context;
+
+typedef struct JAR_Signer_ {
+ int pkcs7; /* Enforced opaqueness */
+ int valid; /* PKCS7 signature validated */
+ char *owner; /* name of .RSA file */
+ JAR_Digest *digest; /* of .SF file */
+ ZZList *sf; /* Linked list of .SF file contents */
+ ZZList *certs; /* Signing information */
+} JAR_Signer;
+
+/* Meta informaton, or "policy", from the manifest file.
+ Right now just one tuple per JAR_Item. */
+typedef struct JAR_Metainfo_ {
+ char *header;
+ char *info;
+} JAR_Metainfo;
+
+/* This should not be global */
+typedef struct JAR_Physical_ {
+ unsigned char compression;
+ unsigned long offset;
+ unsigned long length;
+ unsigned long uncompressed_length;
+#if defined(XP_UNIX) || defined(XP_BEOS)
+ PRUint16 mode;
+#endif
+} JAR_Physical;
+
+typedef struct JAR_Cert_ {
+ size_t length;
+ void *key;
+ CERTCertificate *cert;
+} JAR_Cert;
+
+/* certificate stuff */
+typedef enum {
+ jarCertCompany = 1,
+ jarCertCA = 2,
+ jarCertSerial = 3,
+ jarCertExpires = 4,
+ jarCertNickname = 5,
+ jarCertFinger = 6,
+ jarCertJavaHack = 100
+} jarCert;
+
+/* callback types */
+#define JAR_CB_SIGNAL 1
+
+/*
+ * This is the base for the JAR error codes. It will
+ * change when these are incorporated into allxpstr.c,
+ * but right now they won't let me put them there.
+ *
+ */
+#ifndef SEC_ERR_BASE
+#define SEC_ERR_BASE (-0x2000)
+#endif
+
+#define JAR_BASE SEC_ERR_BASE + 300
+
+/* Jar specific error definitions */
+
+#define JAR_ERR_GENERAL (JAR_BASE + 1)
+#define JAR_ERR_FNF (JAR_BASE + 2)
+#define JAR_ERR_CORRUPT (JAR_BASE + 3)
+#define JAR_ERR_MEMORY (JAR_BASE + 4)
+#define JAR_ERR_DISK (JAR_BASE + 5)
+#define JAR_ERR_ORDER (JAR_BASE + 6)
+#define JAR_ERR_SIG (JAR_BASE + 7)
+#define JAR_ERR_METADATA (JAR_BASE + 8)
+#define JAR_ERR_ENTRY (JAR_BASE + 9)
+#define JAR_ERR_HASH (JAR_BASE + 10)
+#define JAR_ERR_PK7 (JAR_BASE + 11)
+#define JAR_ERR_PNF (JAR_BASE + 12)
+
+/* Function declarations */
+
+extern JAR *JAR_new(void);
+
+extern void PR_CALLBACK JAR_destroy(JAR *jar);
+
+extern char *JAR_get_error(int status);
+
+extern int JAR_set_callback(int type, JAR *jar, jar_settable_callback_fn *fn);
+
+extern void
+JAR_init_callbacks(char *(*string_cb)(int),
+ void *(*find_cx)(void),
+ void *(*init_cx)(void));
+
+/*
+ * JAR_set_context
+ *
+ * PKCS11 may require a password to be entered by the user
+ * before any crypto routines may be called. This will require
+ * a window context if used from inside Mozilla.
+ *
+ * Call this routine with your context before calling
+ * verifying or signing. If you have no context, call with NULL
+ * and one will be chosen for you.
+ *
+ */
+int JAR_set_context(JAR *jar, void /*MWContext*/ *mw);
+
+/*
+ * Iterative operations
+ *
+ * JAR_find sets up for repeated calls with JAR_find_next.
+ * I never liked findfirst and findnext, this is nicer.
+ *
+ * Pattern contains a relative pathname to match inside the
+ * archive. It is currently assumed to be "*".
+ *
+ * To use:
+ *
+ * JAR_Item *item;
+ * JAR_find (jar, "*.class", jarTypeMF);
+ * while (JAR_find_next (jar, &item) >= 0)
+ * { do stuff }
+ *
+ */
+
+/* Replacement functions with an external context */
+
+extern JAR_Context *JAR_find(JAR *jar, char *pattern, jarType type);
+
+extern int JAR_find_next(JAR_Context *ctx, JAR_Item **it);
+
+extern void JAR_find_end(JAR_Context *ctx);
+
+/*
+ * Function to parse manifest file:
+ *
+ * Many signatures may be attached to a single filename located
+ * inside the zip file. We only support one.
+ *
+ * Several manifests may be included in the zip file.
+ *
+ * You must pass the MANIFEST.MF file before any .SF files.
+ *
+ * Right now this returns a big ole list, privately in the jar structure.
+ * If you need to traverse it, use JAR_find if possible.
+ *
+ * The path is needed to determine what type of binary signature is
+ * being passed, though it is technically not needed for manifest files.
+ *
+ * When parsing an ASCII file, null terminate the ASCII raw_manifest
+ * prior to sending it, and indicate a length of 0. For binary digital
+ * signatures only, indicate the true length of the signature.
+ * (This is legacy behavior.)
+ *
+ * You may free the manifest after parsing it.
+ *
+ */
+
+extern int
+JAR_parse_manifest(JAR *jar, char *raw_manifest, long length, const char *path,
+ const char *url);
+
+/*
+ * Verify data (nonstreaming). The signature is actually
+ * checked by JAR_parse_manifest or JAR_pass_archive.
+ *
+ */
+
+extern JAR_Digest *PR_CALLBACK
+JAR_calculate_digest(void *data, long length);
+
+extern int PR_CALLBACK
+JAR_verify_digest(JAR *jar, const char *name, JAR_Digest *dig);
+
+extern int
+JAR_digest_file(char *filename, JAR_Digest *dig);
+
+/*
+ * Meta information
+ *
+ * Currently, since this call does not support passing of an owner
+ * (certificate, or physical name of the .sf file), it is restricted to
+ * returning information located in the manifest.mf file.
+ *
+ * Meta information is a name/value pair inside the archive file. Here,
+ * the name is passed in *header and value returned in **info.
+ *
+ * Pass a NULL as the name to retrieve metainfo from the global section.
+ *
+ * Data is returned in **info, of size *length. The return value
+ * will indicate if no data was found.
+ *
+ */
+
+extern int
+JAR_get_metainfo(JAR *jar, char *name, char *header, void **info,
+ unsigned long *length);
+
+extern char *JAR_get_filename(JAR *jar);
+
+extern char *JAR_get_url(JAR *jar);
+
+/* save the certificate with this fingerprint in persistent
+ storage, somewhere, for retrieval in a future session when there
+ is no corresponding JAR structure. */
+extern int PR_CALLBACK
+JAR_stash_cert(JAR *jar, long keylen, void *key);
+
+/* retrieve a certificate presumably stashed with the above
+ function, but may be any certificate. Type is &CERTCertificate */
+CERTCertificate *
+JAR_fetch_cert(long length, void *key);
+
+/*
+ * New functions to handle archives alone
+ * (call JAR_new beforehand)
+ *
+ * JAR_pass_archive acts much like parse_manifest. Certificates
+ * are returned in the JAR structure but as opaque data. When calling
+ * JAR_verified_extract you still need to decide which of these
+ * certificates to honor.
+ *
+ * Code to examine a JAR structure is in jarbert.c. You can obtain both
+ * a list of filenames and certificates from traversing the linked list.
+ *
+ */
+extern int
+JAR_pass_archive(JAR *jar, jarArch format, char *filename, const char *url);
+
+/*
+ * Same thing, but don't check signatures
+ */
+extern int
+JAR_pass_archive_unverified(JAR *jar, jarArch format, char *filename,
+ const char *url);
+
+/*
+ * Extracts a relative pathname from the archive and places it
+ * in the filename specified.
+ *
+ * Call JAR_set_nailed if you want to keep the file descriptors
+ * open between multiple calls to JAR_verify_extract.
+ *
+ */
+extern int
+JAR_verified_extract(JAR *jar, char *path, char *outpath);
+
+/*
+ * JAR_extract does no crypto checking. This can be used if you
+ * need to extract a manifest file or signature, etc.
+ *
+ */
+extern int
+JAR_extract(JAR *jar, char *path, char *outpath);
+
+#endif /* __JAR_h_ */
diff --git a/security/nss/lib/jar/jarfile.c b/security/nss/lib/jar/jarfile.c
new file mode 100644
index 000000000..e2470a121
--- /dev/null
+++ b/security/nss/lib/jar/jarfile.c
@@ -0,0 +1,966 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * JARFILE
+ *
+ * Parsing of a Jar file
+ */
+#define JAR_SIZE 256
+
+#include "jar.h"
+#include "jarint.h"
+#include "jarfile.h"
+
+/* commercial compression */
+#include "jzlib.h"
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+#include "sys/stat.h"
+#endif
+
+#include "sechash.h" /* for HASH_GetHashObject() */
+
+PR_STATIC_ASSERT(46 == sizeof(struct ZipCentral));
+PR_STATIC_ASSERT(30 == sizeof(struct ZipLocal));
+PR_STATIC_ASSERT(22 == sizeof(struct ZipEnd));
+PR_STATIC_ASSERT(512 == sizeof(union TarEntry));
+
+/* extracting */
+static int
+jar_guess_jar(const char *filename, JAR_FILE fp);
+
+static int
+jar_inflate_memory(unsigned int method, long *length, long expected_out_len,
+ char **data);
+
+static int
+jar_physical_extraction(JAR_FILE fp, char *outpath, unsigned long offset,
+ unsigned long length);
+
+static int
+jar_physical_inflate(JAR_FILE fp, char *outpath, unsigned long offset,
+ unsigned long length, unsigned int method);
+
+static int
+jar_verify_extract(JAR *jar, char *path, char *physical_path);
+
+static JAR_Physical *
+jar_get_physical(JAR *jar, char *pathname);
+
+static int
+jar_extract_manifests(JAR *jar, jarArch format, JAR_FILE fp);
+
+static int
+jar_extract_mf(JAR *jar, jarArch format, JAR_FILE fp, char *ext);
+
+/* indexing */
+static int
+jar_gen_index(JAR *jar, jarArch format, JAR_FILE fp);
+
+static int
+jar_listtar(JAR *jar, JAR_FILE fp);
+
+static int
+jar_listzip(JAR *jar, JAR_FILE fp);
+
+/* conversions */
+static int
+dosdate(char *date, const char *s);
+
+static int
+dostime(char *time, const char *s);
+
+#ifdef NSS_X86_OR_X64
+/* The following macros throw up warnings. */
+#if defined(__GNUC__) && !defined(NSS_NO_GCC48)
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+#define x86ShortToUint32(ii) ((const PRUint32) * ((const PRUint16 *)(ii)))
+#define x86LongToUint32(ii) (*(const PRUint32 *)(ii))
+#else
+static PRUint32
+x86ShortToUint32(const void *ii);
+
+static PRUint32
+x86LongToUint32(const void *ll);
+#endif
+
+static long
+octalToLong(const char *s);
+
+/*
+ * J A R _ p a s s _ a r c h i v e
+ *
+ * For use by naive clients. Slam an entire archive file
+ * into this function. We extract manifests, parse, index
+ * the archive file, and do whatever nastiness.
+ *
+ */
+int
+JAR_pass_archive(JAR *jar, jarArch format, char *filename, const char *url)
+{
+ JAR_FILE fp;
+ int status = 0;
+
+ if (filename == NULL)
+ return JAR_ERR_GENERAL;
+
+ if ((fp = JAR_FOPEN(filename, "rb")) != NULL) {
+ if (format == jarArchGuess)
+ format = (jarArch)jar_guess_jar(filename, fp);
+
+ jar->format = format;
+ jar->url = url ? PORT_Strdup(url) : NULL;
+ jar->filename = PORT_Strdup(filename);
+
+ status = jar_gen_index(jar, format, fp);
+ if (status == 0)
+ status = jar_extract_manifests(jar, format, fp);
+
+ JAR_FCLOSE(fp);
+ if (status < 0)
+ return status;
+
+ /* people were expecting it this way */
+ return jar->valid;
+ }
+ /* file not found */
+ return JAR_ERR_FNF;
+}
+
+/*
+ * J A R _ p a s s _ a r c h i v e _ u n v e r i f i e d
+ *
+ * Same as JAR_pass_archive, but doesn't parse signatures.
+ *
+ */
+int
+JAR_pass_archive_unverified(JAR *jar, jarArch format, char *filename,
+ const char *url)
+{
+ JAR_FILE fp;
+ int status = 0;
+
+ if (filename == NULL) {
+ return JAR_ERR_GENERAL;
+ }
+
+ if ((fp = JAR_FOPEN(filename, "rb")) != NULL) {
+ if (format == jarArchGuess) {
+ format = (jarArch)jar_guess_jar(filename, fp);
+ }
+
+ jar->format = format;
+ jar->url = url ? PORT_Strdup(url) : NULL;
+ jar->filename = PORT_Strdup(filename);
+
+ status = jar_gen_index(jar, format, fp);
+ if (status == 0) {
+ status = jar_extract_mf(jar, format, fp, "mf");
+ }
+
+ JAR_FCLOSE(fp);
+ if (status < 0) {
+ return status;
+ }
+
+ /* people were expecting it this way */
+ return jar->valid;
+ }
+ /* file not found */
+ return JAR_ERR_FNF;
+}
+
+/*
+ * J A R _ v e r i f i e d _ e x t r a c t
+ *
+ * Optimization: keep a file descriptor open
+ * inside the JAR structure, so we don't have to
+ * open the file 25 times to run java.
+ *
+ */
+
+int
+JAR_verified_extract(JAR *jar, char *path, char *outpath)
+{
+ int status = JAR_extract(jar, path, outpath);
+
+ if (status >= 0)
+ return jar_verify_extract(jar, path, outpath);
+ return status;
+}
+
+int
+JAR_extract(JAR *jar, char *path, char *outpath)
+{
+ int result;
+ JAR_Physical *phy;
+
+ if (jar->fp == NULL && jar->filename) {
+ jar->fp = (FILE *)JAR_FOPEN(jar->filename, "rb");
+ }
+ if (jar->fp == NULL) {
+ /* file not found */
+ return JAR_ERR_FNF;
+ }
+
+ phy = jar_get_physical(jar, path);
+ if (phy) {
+ if (phy->compression != 0 && phy->compression != 8) {
+ /* unsupported compression method */
+ result = JAR_ERR_CORRUPT;
+ }
+ if (phy->compression == 0) {
+ result = jar_physical_extraction((PRFileDesc *)jar->fp, outpath, phy->offset, phy->length);
+ } else {
+ result = jar_physical_inflate((PRFileDesc *)jar->fp, outpath,
+ phy->offset, phy->length,
+ (unsigned int)phy->compression);
+ }
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+ if (phy->mode)
+ chmod(outpath, 0400 | (mode_t)phy->mode);
+#endif
+ } else {
+ /* pathname not found in archive */
+ result = JAR_ERR_PNF;
+ }
+ return result;
+}
+
+/*
+ * p h y s i c a l _ e x t r a c t i o n
+ *
+ * This needs to be done in chunks of say 32k, instead of
+ * in one bulk calloc. (Necessary under Win16 platform.)
+ * This is done for uncompressed entries only.
+ *
+ */
+
+#define CHUNK 32768
+
+static int
+jar_physical_extraction(JAR_FILE fp, char *outpath, unsigned long offset,
+ unsigned long length)
+{
+ JAR_FILE out;
+ char *buffer = (char *)PORT_ZAlloc(CHUNK);
+ int status = 0;
+
+ if (buffer == NULL)
+ return JAR_ERR_MEMORY;
+
+ if ((out = JAR_FOPEN(outpath, "wb")) != NULL) {
+ unsigned long at = 0;
+
+ JAR_FSEEK(fp, offset, (PRSeekWhence)0);
+ while (at < length) {
+ long chunk = (at + CHUNK <= length) ? CHUNK : length - at;
+ if (JAR_FREAD(fp, buffer, chunk) != chunk) {
+ status = JAR_ERR_DISK;
+ break;
+ }
+ at += chunk;
+ if (JAR_FWRITE(out, buffer, chunk) < chunk) {
+ /* most likely a disk full error */
+ status = JAR_ERR_DISK;
+ break;
+ }
+ }
+ JAR_FCLOSE(out);
+ } else {
+ /* error opening output file */
+ status = JAR_ERR_DISK;
+ }
+ PORT_Free(buffer);
+ return status;
+}
+
+/*
+ * j a r _ p h y s i c a l _ i n f l a t e
+ *
+ * Inflate a range of bytes in a file, writing the inflated
+ * result to "outpath". Chunk based.
+ *
+ */
+/* input and output chunks differ, assume 4x compression */
+
+#define ICHUNK 8192
+#define OCHUNK 32768
+
+static int
+jar_physical_inflate(JAR_FILE fp, char *outpath, unsigned long offset, unsigned long length,
+ unsigned int method)
+{
+ char *inbuf, *outbuf;
+ int status = 0;
+ z_stream zs;
+ JAR_FILE out;
+
+ /* Raw inflate in zlib 1.1.4 needs an extra dummy byte at the end */
+ if ((inbuf = (char *)PORT_ZAlloc(ICHUNK + 1)) == NULL)
+ return JAR_ERR_MEMORY;
+
+ if ((outbuf = (char *)PORT_ZAlloc(OCHUNK)) == NULL) {
+ PORT_Free(inbuf);
+ return JAR_ERR_MEMORY;
+ }
+
+ PORT_Memset(&zs, 0, sizeof(zs));
+ status = inflateInit2(&zs, -MAX_WBITS);
+ if (status != Z_OK) {
+ PORT_Free(inbuf);
+ PORT_Free(outbuf);
+ return JAR_ERR_GENERAL;
+ }
+
+ if ((out = JAR_FOPEN(outpath, "wb")) != NULL) {
+ unsigned long at = 0;
+
+ JAR_FSEEK(fp, offset, (PRSeekWhence)0);
+ while (at < length) {
+ unsigned long chunk = (at + ICHUNK <= length) ? ICHUNK : length - at;
+ unsigned long tin;
+
+ if (JAR_FREAD(fp, inbuf, chunk) != chunk) {
+ /* incomplete read */
+ JAR_FCLOSE(out);
+ PORT_Free(inbuf);
+ PORT_Free(outbuf);
+ return JAR_ERR_CORRUPT;
+ }
+ at += chunk;
+ if (at == length) {
+ /* add an extra dummy byte at the end */
+ inbuf[chunk++] = 0xDD;
+ }
+ zs.next_in = (Bytef *)inbuf;
+ zs.avail_in = chunk;
+ zs.avail_out = OCHUNK;
+ tin = zs.total_in;
+ while ((zs.total_in - tin < chunk) || (zs.avail_out == 0)) {
+ unsigned long prev_total = zs.total_out;
+ unsigned long ochunk;
+
+ zs.next_out = (Bytef *)outbuf;
+ zs.avail_out = OCHUNK;
+ status = inflate(&zs, Z_NO_FLUSH);
+ if (status != Z_OK && status != Z_STREAM_END) {
+ /* error during decompression */
+ JAR_FCLOSE(out);
+ PORT_Free(inbuf);
+ PORT_Free(outbuf);
+ return JAR_ERR_CORRUPT;
+ }
+ ochunk = zs.total_out - prev_total;
+ if (JAR_FWRITE(out, outbuf, ochunk) < (long)ochunk) {
+ /* most likely a disk full error */
+ status = JAR_ERR_DISK;
+ break;
+ }
+ if (status == Z_STREAM_END)
+ break;
+ }
+ }
+ JAR_FCLOSE(out);
+ status = inflateEnd(&zs);
+ } else {
+ /* error opening output file */
+ status = JAR_ERR_DISK;
+ }
+ PORT_Free(inbuf);
+ PORT_Free(outbuf);
+ return status;
+}
+
+/*
+ * j a r _ i n f l a t e _ m e m o r y
+ *
+ * Call zlib to inflate the given memory chunk. It is re-XP_ALLOC'd,
+ * and thus appears to operate inplace to the caller.
+ *
+ */
+static int
+jar_inflate_memory(unsigned int method, long *length, long expected_out_len,
+ char **data)
+{
+ char *inbuf = *data;
+ char *outbuf = (char *)PORT_ZAlloc(expected_out_len);
+ long insz = *length;
+ int status;
+ z_stream zs;
+
+ if (outbuf == NULL)
+ return JAR_ERR_MEMORY;
+
+ PORT_Memset(&zs, 0, sizeof zs);
+ status = inflateInit2(&zs, -MAX_WBITS);
+ if (status < 0) {
+ /* error initializing zlib stream */
+ PORT_Free(outbuf);
+ return JAR_ERR_GENERAL;
+ }
+
+ zs.next_in = (Bytef *)inbuf;
+ zs.next_out = (Bytef *)outbuf;
+ zs.avail_in = insz;
+ zs.avail_out = expected_out_len;
+
+ status = inflate(&zs, Z_FINISH);
+ if (status != Z_OK && status != Z_STREAM_END) {
+ /* error during deflation */
+ PORT_Free(outbuf);
+ return JAR_ERR_GENERAL;
+ }
+
+ status = inflateEnd(&zs);
+ if (status != Z_OK) {
+ /* error during deflation */
+ PORT_Free(outbuf);
+ return JAR_ERR_GENERAL;
+ }
+ PORT_Free(*data);
+ *data = outbuf;
+ *length = zs.total_out;
+ return 0;
+}
+
+/*
+ * v e r i f y _ e x t r a c t
+ *
+ * Validate signature on the freshly extracted file.
+ *
+ */
+static int
+jar_verify_extract(JAR *jar, char *path, char *physical_path)
+{
+ int status;
+ JAR_Digest dig;
+
+ PORT_Memset(&dig, 0, sizeof dig);
+ status = JAR_digest_file(physical_path, &dig);
+ if (!status)
+ status = JAR_verify_digest(jar, path, &dig);
+ return status;
+}
+
+/*
+ * g e t _ p h y s i c a l
+ *
+ * Let's get physical.
+ * Obtains the offset and length of this file in the jar file.
+ *
+ */
+static JAR_Physical *
+jar_get_physical(JAR *jar, char *pathname)
+{
+ ZZLink *link;
+ ZZList *list = jar->phy;
+
+ if (ZZ_ListEmpty(list))
+ return NULL;
+
+ for (link = ZZ_ListHead(list);
+ !ZZ_ListIterDone(list, link);
+ link = link->next) {
+ JAR_Item *it = link->thing;
+
+ if (it->type == jarTypePhy &&
+ it->pathname && !PORT_Strcmp(it->pathname, pathname)) {
+ JAR_Physical *phy = (JAR_Physical *)it->data;
+ return phy;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * j a r _ e x t r a c t _ m a n i f e s t s
+ *
+ * Extract the manifest files and parse them,
+ * from an open archive file whose contents are known.
+ *
+ */
+static int
+jar_extract_manifests(JAR *jar, jarArch format, JAR_FILE fp)
+{
+ int status, signatures;
+
+ if (format != jarArchZip && format != jarArchTar)
+ return JAR_ERR_CORRUPT;
+
+ if ((status = jar_extract_mf(jar, format, fp, "mf")) < 0)
+ return status;
+ if (!status)
+ return JAR_ERR_ORDER;
+ if ((status = jar_extract_mf(jar, format, fp, "sf")) < 0)
+ return status;
+ if (!status)
+ return JAR_ERR_ORDER;
+ if ((status = jar_extract_mf(jar, format, fp, "rsa")) < 0)
+ return status;
+ signatures = status;
+ if ((status = jar_extract_mf(jar, format, fp, "dsa")) < 0)
+ return status;
+ if (!(signatures += status))
+ return JAR_ERR_SIG;
+ return 0;
+}
+
+/*
+ * j a r _ e x t r a c t _ m f
+ *
+ * Extracts manifest files based on an extension, which
+ * should be .MF, .SF, .RSA, etc. Order of the files is now no
+ * longer important when zipping jar files.
+ *
+ */
+static int
+jar_extract_mf(JAR *jar, jarArch format, JAR_FILE fp, char *ext)
+{
+ ZZLink *link;
+ ZZList *list = jar->phy;
+ int ret = 0;
+
+ if (ZZ_ListEmpty(list))
+ return JAR_ERR_PNF;
+
+ for (link = ZZ_ListHead(list);
+ ret >= 0 && !ZZ_ListIterDone(list, link);
+ link = link->next) {
+ JAR_Item *it = link->thing;
+
+ if (it->type == jarTypePhy &&
+ !PORT_Strncmp(it->pathname, "META-INF", 8)) {
+ JAR_Physical *phy = (JAR_Physical *)it->data;
+ char *fn = it->pathname + 8;
+ char *e;
+ char *manifest;
+ long length;
+ int num, status;
+
+ if (PORT_Strlen(it->pathname) < 8)
+ continue;
+
+ if (*fn == '/' || *fn == '\\')
+ fn++;
+ if (*fn == 0) {
+ /* just a directory entry */
+ continue;
+ }
+
+ /* skip to extension */
+ for (e = fn; *e && *e != '.'; e++)
+ /* yip */;
+
+ /* and skip dot */
+ if (*e == '.')
+ e++;
+ if (PORT_Strcasecmp(ext, e)) {
+ /* not the right extension */
+ continue;
+ }
+ if (phy->length == 0 || phy->length > 0xFFFF) {
+ /* manifest files cannot be zero length or too big! */
+ /* the 0xFFFF limit is per J2SE SDK */
+ return JAR_ERR_CORRUPT;
+ }
+
+ /* Read in the manifest and parse it */
+ /* Raw inflate in zlib 1.1.4 needs an extra dummy byte at the end */
+ manifest = (char *)PORT_ZAlloc(phy->length + 1);
+ if (!manifest)
+ return JAR_ERR_MEMORY;
+
+ JAR_FSEEK(fp, phy->offset, (PRSeekWhence)0);
+ num = JAR_FREAD(fp, manifest, phy->length);
+ if (num != phy->length) {
+ /* corrupt archive file */
+ PORT_Free(manifest);
+ return JAR_ERR_CORRUPT;
+ }
+
+ if (phy->compression == 8) {
+ length = phy->length;
+ /* add an extra dummy byte at the end */
+ manifest[length++] = 0xDD;
+ status = jar_inflate_memory((unsigned int)phy->compression,
+ &length,
+ phy->uncompressed_length,
+ &manifest);
+ if (status < 0) {
+ PORT_Free(manifest);
+ return status;
+ }
+ } else if (phy->compression) {
+ /* unsupported compression method */
+ PORT_Free(manifest);
+ return JAR_ERR_CORRUPT;
+ } else
+ length = phy->length;
+
+ status = JAR_parse_manifest(jar, manifest, length,
+ it->pathname, "url");
+ PORT_Free(manifest);
+ if (status < 0)
+ ret = status;
+ else
+ ++ret;
+ } else if (it->type == jarTypePhy) {
+ /* ordinary file */
+ }
+ }
+ return ret;
+}
+
+/*
+ * j a r _ g e n _ i n d e x
+ *
+ * Generate an index for the various types of
+ * known archive files. Right now .ZIP and .TAR
+ *
+ */
+static int
+jar_gen_index(JAR *jar, jarArch format, JAR_FILE fp)
+{
+ int result = JAR_ERR_CORRUPT;
+
+ JAR_FSEEK(fp, 0, (PRSeekWhence)0);
+ switch (format) {
+ case jarArchZip:
+ result = jar_listzip(jar, fp);
+ break;
+
+ case jarArchTar:
+ result = jar_listtar(jar, fp);
+ break;
+
+ case jarArchGuess:
+ case jarArchNone:
+ return JAR_ERR_GENERAL;
+ }
+ JAR_FSEEK(fp, 0, (PRSeekWhence)0);
+ return result;
+}
+
+/*
+ * j a r _ l i s t z i p
+ *
+ * List the physical contents of a Phil Katz
+ * style .ZIP file into the JAR linked list.
+ *
+ */
+static int
+jar_listzip(JAR *jar, JAR_FILE fp)
+{
+ ZZLink *ent;
+ JAR_Item *it = NULL;
+ JAR_Physical *phy = NULL;
+ struct ZipLocal *Local = PORT_ZNew(struct ZipLocal);
+ struct ZipCentral *Central = PORT_ZNew(struct ZipCentral);
+ struct ZipEnd *End = PORT_ZNew(struct ZipEnd);
+
+ int err = 0;
+ long pos = 0L;
+ unsigned int compression;
+ unsigned int filename_len, extra_len;
+
+ char filename[JAR_SIZE];
+ char date[9], time[9];
+ char sig[4];
+
+ if (!Local || !Central || !End) {
+ /* out of memory */
+ err = JAR_ERR_MEMORY;
+ goto loser;
+ }
+
+ while (1) {
+ PRUint32 sigVal;
+ JAR_FSEEK(fp, pos, (PRSeekWhence)0);
+
+ if (JAR_FREAD(fp, sig, sizeof sig) != sizeof sig) {
+ /* zip file ends prematurely */
+ err = JAR_ERR_CORRUPT;
+ goto loser;
+ }
+
+ JAR_FSEEK(fp, pos, (PRSeekWhence)0);
+ sigVal = x86LongToUint32(sig);
+ if (sigVal == LSIG) {
+ JAR_FREAD(fp, Local, sizeof *Local);
+
+ filename_len = x86ShortToUint32(Local->filename_len);
+ extra_len = x86ShortToUint32(Local->extrafield_len);
+ if (filename_len >= JAR_SIZE) {
+ /* corrupt zip file */
+ err = JAR_ERR_CORRUPT;
+ goto loser;
+ }
+
+ if (JAR_FREAD(fp, filename, filename_len) != filename_len) {
+ /* truncated archive file */
+ err = JAR_ERR_CORRUPT;
+ goto loser;
+ }
+ filename[filename_len] = 0;
+ /* Add this to our jar chain */
+ phy = PORT_ZNew(JAR_Physical);
+ if (phy == NULL) {
+ err = JAR_ERR_MEMORY;
+ goto loser;
+ }
+
+ /* We will index any file that comes our way, but when it comes
+ to actually extraction, compression must be 0 or 8 */
+ compression = x86ShortToUint32(Local->method);
+ phy->compression = (compression <= 255) ? compression : 222;
+ /* XXX 222 is bad magic. */
+
+ phy->offset = pos + (sizeof *Local) + filename_len + extra_len;
+ phy->length = x86LongToUint32(Local->size);
+ phy->uncompressed_length = x86LongToUint32(Local->orglen);
+
+ dosdate(date, Local->date);
+ dostime(time, Local->time);
+
+ it = PORT_ZNew(JAR_Item);
+ if (it == NULL) {
+ err = JAR_ERR_MEMORY;
+ goto loser;
+ }
+
+ it->pathname = PORT_Strdup(filename);
+ it->type = jarTypePhy;
+ it->data = (unsigned char *)phy;
+ it->size = sizeof(JAR_Physical);
+
+ ent = ZZ_NewLink(it);
+ if (ent == NULL) {
+ err = JAR_ERR_MEMORY;
+ goto loser;
+ }
+
+ ZZ_AppendLink(jar->phy, ent);
+ pos = phy->offset + phy->length;
+ } else if (sigVal == CSIG) {
+ unsigned int attr = 0;
+ if (JAR_FREAD(fp, Central, sizeof *Central) != sizeof *Central) {
+ /* apparently truncated archive */
+ err = JAR_ERR_CORRUPT;
+ goto loser;
+ }
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+ /* with unix we need to locate any bits from
+ the protection mask in the external attributes. */
+ attr = Central->external_attributes[2]; /* magic */
+ if (attr) {
+ /* we have to read the filename, again */
+ filename_len = x86ShortToUint32(Central->filename_len);
+ if (filename_len >= JAR_SIZE) {
+ /* corrupt in central directory */
+ err = JAR_ERR_CORRUPT;
+ goto loser;
+ }
+
+ if (JAR_FREAD(fp, filename, filename_len) != filename_len) {
+ /* truncated in central directory */
+ err = JAR_ERR_CORRUPT;
+ goto loser;
+ }
+ filename[filename_len] = 0;
+
+ /* look up this name again */
+ phy = jar_get_physical(jar, filename);
+ if (phy) {
+ /* always allow access by self */
+ phy->mode = 0400 | attr;
+ }
+ }
+#endif
+ pos += sizeof(struct ZipCentral) +
+ x86ShortToUint32(Central->filename_len) +
+ x86ShortToUint32(Central->commentfield_len) +
+ x86ShortToUint32(Central->extrafield_len);
+ } else if (sigVal == ESIG) {
+ if (JAR_FREAD(fp, End, sizeof *End) != sizeof *End) {
+ err = JAR_ERR_CORRUPT;
+ goto loser;
+ }
+ break;
+ } else {
+ /* garbage in archive */
+ err = JAR_ERR_CORRUPT;
+ goto loser;
+ }
+ }
+
+loser:
+ if (Local)
+ PORT_Free(Local);
+ if (phy && it == NULL)
+ PORT_Free(phy);
+ if (Central)
+ PORT_Free(Central);
+ if (End)
+ PORT_Free(End);
+ return err;
+}
+
+/*
+ * j a r _ l i s t t a r
+ *
+ * List the physical contents of a Unix
+ * .tar file into the JAR linked list.
+ *
+ */
+static int
+jar_listtar(JAR *jar, JAR_FILE fp)
+{
+ char *s;
+ JAR_Physical *phy;
+ long pos = 0L;
+ long sz;
+ union TarEntry tarball;
+
+ while (1) {
+ JAR_FSEEK(fp, pos, (PRSeekWhence)0);
+
+ if (JAR_FREAD(fp, &tarball, sizeof tarball) < sizeof tarball)
+ break;
+
+ if (!*tarball.val.filename)
+ break;
+
+ sz = octalToLong(tarball.val.size);
+
+ /* Tag the end of filename */
+ s = tarball.val.filename;
+ while (*s && *s != ' ')
+ s++;
+ *s = 0;
+
+ /* Add to our linked list */
+ phy = PORT_ZNew(JAR_Physical);
+ if (phy == NULL)
+ return JAR_ERR_MEMORY;
+
+ phy->compression = 0;
+ phy->offset = pos + sizeof tarball;
+ phy->length = sz;
+
+ ADDITEM(jar->phy, jarTypePhy, tarball.val.filename, phy,
+ sizeof *phy);
+
+ /* Advance to next file entry */
+ sz = PR_ROUNDUP(sz, sizeof tarball);
+ pos += sz + sizeof tarball;
+ }
+
+ return 0;
+}
+
+/*
+ * d o s d a t e
+ *
+ * Not used right now, but keep it in here because
+ * it will be needed.
+ *
+ */
+static int
+dosdate(char *date, const char *s)
+{
+ PRUint32 num = x86ShortToUint32(s);
+
+ PR_snprintf(date, 9, "%02d-%02d-%02d", ((num >> 5) & 0x0F), (num & 0x1F),
+ ((num >> 9) + 80));
+ return 0;
+}
+
+/*
+ * d o s t i m e
+ *
+ * Not used right now, but keep it in here because
+ * it will be needed.
+ *
+ */
+static int
+dostime(char *time, const char *s)
+{
+ PRUint32 num = x86ShortToUint32(s);
+
+ PR_snprintf(time, 6, "%02d:%02d", ((num >> 11) & 0x1F),
+ ((num >> 5) & 0x3F));
+ return 0;
+}
+
+#ifndef NSS_X86_OR_X64
+/*
+ * Simulates an x86 (little endian, unaligned) ushort fetch from any address.
+ */
+static PRUint32
+x86ShortToUint32(const void *v)
+{
+ const unsigned char *ii = (const unsigned char *)v;
+ PRUint32 ret = (PRUint32)(ii[0]) | ((PRUint32)(ii[1]) << 8);
+ return ret;
+}
+
+/*
+ * Simulates an x86 (little endian, unaligned) uint fetch from any address.
+ */
+static PRUint32
+x86LongToUint32(const void *v)
+{
+ const unsigned char *ll = (const unsigned char *)v;
+ PRUint32 ret;
+
+ ret = ((((PRUint32)(ll[0])) << 0) |
+ (((PRUint32)(ll[1])) << 8) |
+ (((PRUint32)(ll[2])) << 16) |
+ (((PRUint32)(ll[3])) << 24));
+ return ret;
+}
+#endif
+
+/*
+ * ASCII octal to binary long.
+ * Used for integer encoding inside tar files.
+ *
+ */
+static long
+octalToLong(const char *s)
+{
+ long num = 0L;
+
+ while (*s == ' ')
+ s++;
+ while (*s >= '0' && *s <= '7') {
+ num <<= 3;
+ num += *s++ - '0';
+ }
+ return num;
+}
+
+/*
+ * g u e s s _ j a r
+ *
+ * Try to guess what kind of JAR file this is.
+ * Maybe tar, maybe zip. Look in the file for magic
+ * or at its filename.
+ *
+ */
+static int
+jar_guess_jar(const char *filename, JAR_FILE fp)
+{
+ PRInt32 len = PORT_Strlen(filename);
+ const char *ext = filename + len - 4; /* 4 for ".tar" */
+
+ if (len >= 4 && !PL_strcasecmp(ext, ".tar"))
+ return jarArchTar;
+ return jarArchZip;
+}
diff --git a/security/nss/lib/jar/jarfile.h b/security/nss/lib/jar/jarfile.h
new file mode 100644
index 000000000..52d4f1fc7
--- /dev/null
+++ b/security/nss/lib/jar/jarfile.h
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * JARFILE.H
+ *
+ * Certain constants and structures for the archive format.
+ *
+ */
+
+/* ZIP */
+struct ZipLocal { /* 30 bytes */
+ char signature[4];
+ char word[2];
+ char bitflag[2];
+ char method[2];
+ char time[2];
+ char date[2];
+ char crc32[4];
+ char size[4];
+ char orglen[4];
+ char filename_len[2];
+ char extrafield_len[2];
+};
+
+struct ZipCentral { /* 46 bytes */
+ char signature[4];
+ char version_made_by[2];
+ char version[2];
+ char bitflag[2];
+ char method[2];
+ char time[2];
+ char date[2];
+ char crc32[4];
+ char size[4];
+ char orglen[4];
+ char filename_len[2];
+ char extrafield_len[2];
+ char commentfield_len[2];
+ char diskstart_number[2];
+ char internal_attributes[2];
+ char external_attributes[4];
+ char localhdr_offset[4];
+};
+
+struct ZipEnd { /* 22 bytes */
+ char signature[4];
+ char disk_nr[2];
+ char start_central_dir[2];
+ char total_entries_disk[2];
+ char total_entries_archive[2];
+ char central_dir_size[4];
+ char offset_central_dir[4];
+ char commentfield_len[2];
+};
+
+#define LSIG 0x04034B50l
+#define CSIG 0x02014B50l
+#define ESIG 0x06054B50l
+
+/* TAR */
+union TarEntry { /* 512 bytes */
+ struct header { /* 257 bytes */
+ char filename[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char time[12];
+ char checksum[8];
+ char linkflag;
+ char linkname[100];
+ } val;
+ char buffer[512];
+};
diff --git a/security/nss/lib/jar/jarint.c b/security/nss/lib/jar/jarint.c
new file mode 100644
index 000000000..b0ef7fb21
--- /dev/null
+++ b/security/nss/lib/jar/jarint.c
@@ -0,0 +1,52 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Internal libjar routines.
+ */
+
+#include "jar.h"
+#include "jarint.h"
+
+/*-----------------------------------------------------------------------
+ * JAR_FOPEN_to_PR_Open
+ * Translate JAR_FOPEN arguments to PR_Open arguments
+ */
+PRFileDesc*
+JAR_FOPEN_to_PR_Open(const char* name, const char* mode)
+{
+
+ PRIntn prflags = 0, prmode = 0;
+
+ /* Get read/write flags */
+ if (strchr(mode, 'r') && !strchr(mode, '+')) {
+ prflags |= PR_RDONLY;
+ } else if ((strchr(mode, 'w') || strchr(mode, 'a')) &&
+ !strchr(mode, '+')) {
+ prflags |= PR_WRONLY;
+ } else {
+ prflags |= PR_RDWR;
+ }
+
+ /* Create a new file? */
+ if (strchr(mode, 'w') || strchr(mode, 'a')) {
+ prflags |= PR_CREATE_FILE;
+ }
+
+ /* Append? */
+ if (strchr(mode, 'a')) {
+ prflags |= PR_APPEND;
+ }
+
+ /* Truncate? */
+ if (strchr(mode, 'w')) {
+ prflags |= PR_TRUNCATE;
+ }
+
+ /* We can't do umask because it isn't XP. Choose some default
+ mode for created files */
+ prmode = 0755;
+
+ return PR_Open(name, prflags, prmode);
+}
diff --git a/security/nss/lib/jar/jarint.h b/security/nss/lib/jar/jarint.h
new file mode 100644
index 000000000..21aecef89
--- /dev/null
+++ b/security/nss/lib/jar/jarint.h
@@ -0,0 +1,54 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* JAR internal routines */
+
+#include "nspr.h"
+#include "key.h"
+#include "base64.h"
+
+extern CERTCertDBHandle *JAR_open_database(void);
+
+extern int JAR_close_database(CERTCertDBHandle *certdb);
+
+extern int jar_close_key_database(void *keydb);
+
+extern void *jar_open_key_database(void);
+
+extern JAR_Signer *JAR_new_signer(void);
+
+extern void JAR_destroy_signer(JAR_Signer *signer);
+
+extern JAR_Signer *jar_get_signer(JAR *jar, char *basename);
+
+extern int
+jar_append(ZZList *list, int type, char *pathname, void *data, size_t size);
+
+/* Translate fopen mode arg to PR_Open flags and mode */
+PRFileDesc *
+JAR_FOPEN_to_PR_Open(const char *name, const char *mode);
+
+#define ADDITEM(list, type, pathname, data, size) \
+ { \
+ int err = jar_append(list, type, pathname, data, size); \
+ if (err < 0) \
+ return err; \
+ }
+
+/* Here is some ugliness in the event it is necessary to link
+ with NSPR 1.0 libraries, which do not include an FSEEK. It is
+ difficult to fudge an FSEEK into 1.0 so we use stdio. */
+
+/* nspr 2.0 suite */
+#define JAR_FILE PRFileDesc *
+#define JAR_FOPEN(fn, mode) JAR_FOPEN_to_PR_Open(fn, mode)
+#define JAR_FCLOSE PR_Close
+#define JAR_FSEEK PR_Seek
+#define JAR_FREAD PR_Read
+#define JAR_FWRITE PR_Write
+
+int
+jar_create_pk7(CERTCertDBHandle *certdb, void *keydb,
+ CERTCertificate *cert, char *password, JAR_FILE infp,
+ JAR_FILE outfp);
diff --git a/security/nss/lib/jar/jarnav.c b/security/nss/lib/jar/jarnav.c
new file mode 100644
index 000000000..8b72a52d8
--- /dev/null
+++ b/security/nss/lib/jar/jarnav.c
@@ -0,0 +1,63 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * JARNAV.C
+ *
+ * JAR stuff needed for client only.
+ *
+ */
+
+#include "jar.h"
+#include "jarint.h"
+
+/* from proto.h */
+extern MWContext *FE_GetInitContext(void);
+
+/* To return an MWContext for Java */
+static MWContext *(*jar_fn_FindSomeContext)(void) = NULL;
+
+/* To fabricate an MWContext for FE_GetPassword */
+static MWContext *(*jar_fn_GetInitContext)(void) = NULL;
+
+/*
+ * J A R _ i n i t
+ *
+ * Initialize the JAR functions.
+ *
+ */
+
+void
+JAR_init(void)
+{
+ JAR_init_callbacks(XP_GetString, NULL, NULL);
+}
+
+/*
+ * J A R _ s e t _ c o n t e x t
+ *
+ * Set the jar window context for use by PKCS11, since
+ * it may be needed to prompt the user for a password.
+ *
+ */
+int
+JAR_set_context(JAR *jar, MWContext *mw)
+{
+ if (mw) {
+ jar->mw = mw;
+ } else {
+ /* jar->mw = XP_FindSomeContext(); */
+ jar->mw = NULL;
+ /*
+ * We can't find a context because we're in startup state and none
+ * exist yet. go get an FE_InitContext that only works at
+ * initialization time.
+ */
+ /* Turn on the mac when we get the FE_ function */
+ if (jar->mw == NULL) {
+ jar->mw = jar_fn_GetInitContext();
+ }
+ }
+ return 0;
+}
diff --git a/security/nss/lib/jar/jarsign.c b/security/nss/lib/jar/jarsign.c
new file mode 100644
index 000000000..601a7fd04
--- /dev/null
+++ b/security/nss/lib/jar/jarsign.c
@@ -0,0 +1,250 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * JARSIGN
+ *
+ * Routines used in signing archives.
+ */
+
+#include "jar.h"
+#include "jarint.h"
+#include "secpkcs7.h"
+#include "pk11func.h"
+#include "sechash.h"
+
+/* from libevent.h */
+typedef void (*ETVoidPtrFunc)(void *data);
+
+/* key database wrapper */
+/* static SECKEYKeyDBHandle *jar_open_key_database (void); */
+/* CHUNQ is our bite size */
+
+#define CHUNQ 64000
+#define FILECHUNQ 32768
+
+/*
+ * J A R _ c a l c u l a t e _ d i g e s t
+ *
+ * Quick calculation of a digest for
+ * the specified block of memory. Will calculate
+ * for all supported algorithms, now MD5.
+ *
+ * This version supports huge pointers for WIN16.
+ *
+ */
+JAR_Digest *PR_CALLBACK
+JAR_calculate_digest(void *data, long length)
+{
+ PK11Context *md5 = 0;
+ PK11Context *sha1 = 0;
+ JAR_Digest *dig = PORT_ZNew(JAR_Digest);
+ long chunq;
+ unsigned int md5_length, sha1_length;
+
+ if (dig == NULL) {
+ /* out of memory allocating digest */
+ return NULL;
+ }
+
+ md5 = PK11_CreateDigestContext(SEC_OID_MD5);
+ if (md5 == NULL) {
+ PORT_ZFree(dig, sizeof(JAR_Digest));
+ return NULL;
+ }
+ sha1 = PK11_CreateDigestContext(SEC_OID_SHA1);
+ if (sha1 == NULL) {
+ PK11_DestroyContext(md5, PR_TRUE);
+ /* added due to bug Bug 1250214 - prevent the 2nd memory leak */
+ PORT_ZFree(dig, sizeof(JAR_Digest));
+ return NULL;
+ }
+
+ if (length >= 0) {
+ PK11_DigestBegin(md5);
+ PK11_DigestBegin(sha1);
+
+ do {
+ chunq = length;
+
+ PK11_DigestOp(md5, (unsigned char *)data, chunq);
+ PK11_DigestOp(sha1, (unsigned char *)data, chunq);
+ length -= chunq;
+ data = ((char *)data + chunq);
+ } while (length > 0);
+
+ PK11_DigestFinal(md5, dig->md5, &md5_length, MD5_LENGTH);
+ PK11_DigestFinal(sha1, dig->sha1, &sha1_length, SHA1_LENGTH);
+
+ PK11_DestroyContext(md5, PR_TRUE);
+ PK11_DestroyContext(sha1, PR_TRUE);
+ }
+ return dig;
+}
+
+/*
+ * J A R _ d i g e s t _ f i l e
+ *
+ * Calculates the MD5 and SHA1 digests for a file
+ * present on disk, and returns these in JAR_Digest struct.
+ *
+ */
+int
+JAR_digest_file(char *filename, JAR_Digest *dig)
+{
+ JAR_FILE fp;
+ PK11Context *md5 = 0;
+ PK11Context *sha1 = 0;
+ unsigned char *buf = (unsigned char *)PORT_ZAlloc(FILECHUNQ);
+ int num;
+ unsigned int md5_length, sha1_length;
+
+ if (buf == NULL) {
+ /* out of memory */
+ return JAR_ERR_MEMORY;
+ }
+
+ if ((fp = JAR_FOPEN(filename, "rb")) == 0) {
+ /* perror (filename); FIX XXX XXX XXX XXX XXX XXX */
+ PORT_Free(buf);
+ return JAR_ERR_FNF;
+ }
+
+ md5 = PK11_CreateDigestContext(SEC_OID_MD5);
+ sha1 = PK11_CreateDigestContext(SEC_OID_SHA1);
+
+ if (md5 == NULL || sha1 == NULL) {
+ if (md5) {
+ PK11_DestroyContext(md5, PR_TRUE);
+ }
+ if (sha1) {
+ PK11_DestroyContext(sha1, PR_TRUE);
+ }
+ /* can't generate digest contexts */
+ PORT_Free(buf);
+ JAR_FCLOSE(fp);
+ return JAR_ERR_GENERAL;
+ }
+
+ PK11_DigestBegin(md5);
+ PK11_DigestBegin(sha1);
+
+ while (1) {
+ if ((num = JAR_FREAD(fp, buf, FILECHUNQ)) == 0)
+ break;
+
+ PK11_DigestOp(md5, buf, num);
+ PK11_DigestOp(sha1, buf, num);
+ }
+
+ PK11_DigestFinal(md5, dig->md5, &md5_length, MD5_LENGTH);
+ PK11_DigestFinal(sha1, dig->sha1, &sha1_length, SHA1_LENGTH);
+
+ PK11_DestroyContext(md5, PR_TRUE);
+ PK11_DestroyContext(sha1, PR_TRUE);
+
+ PORT_Free(buf);
+ JAR_FCLOSE(fp);
+
+ return 0;
+}
+
+/*
+ * J A R _ o p e n _ k e y _ d a t a b a s e
+ *
+ */
+
+void *
+jar_open_key_database(void)
+{
+ return NULL;
+}
+
+int
+jar_close_key_database(void *keydb)
+{
+ /* We never do close it */
+ return 0;
+}
+
+/*
+ * j a r _ c r e a t e _ p k 7
+ *
+ */
+
+static void
+jar_pk7_out(void *arg, const char *buf, unsigned long len)
+{
+ JAR_FWRITE((JAR_FILE)arg, buf, len);
+}
+
+int
+jar_create_pk7(CERTCertDBHandle *certdb, void *keydb, CERTCertificate *cert,
+ char *password, JAR_FILE infp, JAR_FILE outfp)
+{
+ SEC_PKCS7ContentInfo *cinfo;
+ const SECHashObject *hashObj;
+ void *mw = NULL;
+ void *hashcx;
+ unsigned int len;
+ int status = 0;
+ SECStatus rv;
+ SECItem digest;
+ unsigned char digestdata[32];
+ unsigned char buffer[4096];
+
+ if (outfp == NULL || infp == NULL || cert == NULL)
+ return JAR_ERR_GENERAL;
+
+ /* we sign with SHA */
+ hashObj = HASH_GetHashObject(HASH_AlgSHA1);
+
+ hashcx = (*hashObj->create)();
+ if (hashcx == NULL)
+ return JAR_ERR_GENERAL;
+
+ (*hashObj->begin)(hashcx);
+ while (1) {
+ int nb = JAR_FREAD(infp, buffer, sizeof buffer);
+ if (nb == 0) { /* eof */
+ break;
+ }
+ (*hashObj->update)(hashcx, buffer, nb);
+ }
+ (*hashObj->end)(hashcx, digestdata, &len, 32);
+ (*hashObj->destroy)(hashcx, PR_TRUE);
+
+ digest.data = digestdata;
+ digest.len = len;
+
+ /* signtool must use any old context it can find since it's
+ calling from inside javaland. */
+ PORT_SetError(0);
+ cinfo = SEC_PKCS7CreateSignedData(cert, certUsageObjectSigner, NULL,
+ SEC_OID_SHA1, &digest, NULL, mw);
+ if (cinfo == NULL)
+ return JAR_ERR_PK7;
+
+ rv = SEC_PKCS7IncludeCertChain(cinfo, NULL);
+ if (rv != SECSuccess) {
+ status = PORT_GetError();
+ SEC_PKCS7DestroyContentInfo(cinfo);
+ return status;
+ }
+
+ /* Having this here forces signtool to always include signing time. */
+ rv = SEC_PKCS7AddSigningTime(cinfo);
+ /* don't check error */
+ PORT_SetError(0);
+
+ /* if calling from mozilla thread*/
+ rv = SEC_PKCS7Encode(cinfo, jar_pk7_out, outfp, NULL, NULL, mw);
+ if (rv != SECSuccess)
+ status = PORT_GetError();
+ SEC_PKCS7DestroyContentInfo(cinfo);
+ if (rv != SECSuccess) {
+ return ((status < 0) ? status : JAR_ERR_GENERAL);
+ }
+ return 0;
+}
diff --git a/security/nss/lib/jar/jarver.c b/security/nss/lib/jar/jarver.c
new file mode 100644
index 000000000..38d73c21c
--- /dev/null
+++ b/security/nss/lib/jar/jarver.c
@@ -0,0 +1,1167 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * JARVER
+ *
+ * Jarnature Parsing & Verification
+ */
+
+#include "nssrenam.h"
+#include "jar.h"
+#include "jarint.h"
+#include "certdb.h"
+#include "certt.h"
+#include "secpkcs7.h"
+#include "secder.h"
+
+#define SZ 512
+
+static int
+jar_validate_pkcs7(JAR *jar, JAR_Signer *signer, char *data, long length);
+
+static void
+jar_catch_bytes(void *arg, const char *buf, unsigned long len);
+
+static int
+jar_gather_signers(JAR *jar, JAR_Signer *signer, SEC_PKCS7ContentInfo *cinfo);
+
+static char *
+jar_eat_line(int lines, int eating, char *data, long *len);
+
+static JAR_Digest *
+jar_digest_section(char *manifest, long length);
+
+static JAR_Digest *jar_get_mf_digest(JAR *jar, char *path);
+
+static int
+jar_parse_digital_signature(char *raw_manifest, JAR_Signer *signer,
+ long length, JAR *jar);
+
+static int
+jar_add_cert(JAR *jar, JAR_Signer *signer, int type, CERTCertificate *cert);
+
+static char *jar_basename(const char *path);
+
+static int
+jar_signal(int status, JAR *jar, const char *metafile, char *pathname);
+
+#ifdef DEBUG
+static int jar_insanity_check(char *data, long length);
+#endif
+
+int
+jar_parse_mf(JAR *jar, char *raw_manifest, long length,
+ const char *path, const char *url);
+
+int
+jar_parse_sf(JAR *jar, char *raw_manifest, long length,
+ const char *path, const char *url);
+
+int
+jar_parse_sig(JAR *jar, const char *path, char *raw_manifest,
+ long length);
+
+int
+jar_parse_any(JAR *jar, int type, JAR_Signer *signer,
+ char *raw_manifest, long length, const char *path,
+ const char *url);
+
+static int
+jar_internal_digest(JAR *jar, const char *path, char *x_name, JAR_Digest *dig);
+
+/*
+ * J A R _ p a r s e _ m a n i f e s t
+ *
+ * Pass manifest files to this function. They are
+ * decoded and placed into internal representations.
+ *
+ * Accepts both signature and manifest files. Use
+ * the same "jar" for both.
+ *
+ */
+int
+JAR_parse_manifest(JAR *jar, char *raw_manifest, long length,
+ const char *path, const char *url)
+{
+ int filename_free = 0;
+
+ /* fill in the path, if supplied. This is the location
+ of the jar file on disk, if known */
+
+ if (jar->filename == NULL && path) {
+ jar->filename = PORT_Strdup(path);
+ if (jar->filename == NULL)
+ return JAR_ERR_MEMORY;
+ filename_free = 1;
+ }
+
+ /* fill in the URL, if supplied. This is the place
+ from which the jar file was retrieved. */
+
+ if (jar->url == NULL && url) {
+ jar->url = PORT_Strdup(url);
+ if (jar->url == NULL) {
+ if (filename_free) {
+ PORT_Free(jar->filename);
+ }
+ return JAR_ERR_MEMORY;
+ }
+ }
+
+ /* Determine what kind of file this is from the META-INF
+ directory. It could be MF, SF, or a binary RSA/DSA file */
+
+ if (!PORT_Strncasecmp(raw_manifest, "Manifest-Version:", 17)) {
+ return jar_parse_mf(jar, raw_manifest, length, path, url);
+ } else if (!PORT_Strncasecmp(raw_manifest, "Signature-Version:", 18)) {
+ return jar_parse_sf(jar, raw_manifest, length, path, url);
+ } else {
+ /* This is probably a binary signature */
+ return jar_parse_sig(jar, path, raw_manifest, length);
+ }
+}
+
+/*
+ * j a r _ p a r s e _ s i g
+ *
+ * Pass some manner of RSA or DSA digital signature
+ * on, after checking to see if it comes at an appropriate state.
+ *
+ */
+int
+jar_parse_sig(JAR *jar, const char *path, char *raw_manifest,
+ long length)
+{
+ JAR_Signer *signer;
+ int status = JAR_ERR_ORDER;
+
+ if (length <= 128) {
+ /* signature is way too small */
+ return JAR_ERR_SIG;
+ }
+
+ /* make sure that MF and SF have already been processed */
+
+ if (jar->globalmeta == NULL)
+ return JAR_ERR_ORDER;
+
+ /* Determine whether or not this RSA file has
+ has an associated SF file */
+
+ if (path) {
+ char *owner;
+ owner = jar_basename(path);
+
+ if (owner == NULL)
+ return JAR_ERR_MEMORY;
+
+ signer = jar_get_signer(jar, owner);
+ PORT_Free(owner);
+ } else
+ signer = jar_get_signer(jar, "*");
+
+ if (signer == NULL)
+ return JAR_ERR_ORDER;
+
+ /* Do not pass a huge pointer to this function,
+ since the underlying security code is unaware. We will
+ never pass >64k through here. */
+
+ if (length > 64000) {
+ /* this digital signature is way too big */
+ return JAR_ERR_SIG;
+ }
+
+ /* don't expense unneeded calloc overhead on non-win16 */
+ status = jar_parse_digital_signature(raw_manifest, signer, length, jar);
+
+ return status;
+}
+
+/*
+ * j a r _ p a r s e _ m f
+ *
+ * Parse the META-INF/manifest.mf file, whose
+ * information applies to all signers.
+ *
+ */
+int
+jar_parse_mf(JAR *jar, char *raw_manifest, long length,
+ const char *path, const char *url)
+{
+ if (jar->globalmeta) {
+ /* refuse a second manifest file, if passed for some reason */
+ return JAR_ERR_ORDER;
+ }
+
+ /* remember a digest for the global section */
+ jar->globalmeta = jar_digest_section(raw_manifest, length);
+ if (jar->globalmeta == NULL)
+ return JAR_ERR_MEMORY;
+ return jar_parse_any(jar, jarTypeMF, NULL, raw_manifest, length,
+ path, url);
+}
+
+/*
+ * j a r _ p a r s e _ s f
+ *
+ * Parse META-INF/xxx.sf, a digitally signed file
+ * pointing to a subset of MF sections.
+ *
+ */
+int
+jar_parse_sf(JAR *jar, char *raw_manifest, long length,
+ const char *path, const char *url)
+{
+ JAR_Signer *signer = NULL;
+ int status = JAR_ERR_MEMORY;
+
+ if (jar->globalmeta == NULL) {
+ /* It is a requirement that the MF file be passed before the SF file */
+ return JAR_ERR_ORDER;
+ }
+
+ signer = JAR_new_signer();
+ if (signer == NULL)
+ goto loser;
+
+ if (path) {
+ signer->owner = jar_basename(path);
+ if (signer->owner == NULL)
+ goto loser;
+ }
+
+ /* check for priors. When someone doctors a jar file
+ to contain identical path entries, prevent the second
+ one from affecting JAR functions */
+ if (jar_get_signer(jar, signer->owner)) {
+ /* someone is trying to spoof us */
+ status = JAR_ERR_ORDER;
+ goto loser;
+ }
+
+ /* remember its digest */
+ signer->digest = JAR_calculate_digest(raw_manifest, length);
+ if (signer->digest == NULL)
+ goto loser;
+
+ /* Add this signer to the jar */
+ ADDITEM(jar->signers, jarTypeOwner, signer->owner, signer,
+ sizeof(JAR_Signer));
+
+ return jar_parse_any(jar, jarTypeSF, signer, raw_manifest, length,
+ path, url);
+
+loser:
+ if (signer)
+ JAR_destroy_signer(signer);
+ return status;
+}
+
+/*
+ * j a r _ p a r s e _ a n y
+ *
+ * Parse a MF or SF manifest file.
+ *
+ */
+int
+jar_parse_any(JAR *jar, int type, JAR_Signer *signer,
+ char *raw_manifest, long length, const char *path,
+ const char *url)
+{
+ int status;
+ long raw_len;
+ JAR_Digest *dig, *mfdig = NULL;
+ char line[SZ];
+ char x_name[SZ], x_md5[SZ], x_sha[SZ];
+ char *x_info;
+ char *sf_md5 = NULL, *sf_sha1 = NULL;
+
+ *x_name = 0;
+ *x_md5 = 0;
+ *x_sha = 0;
+
+ PORT_Assert(length > 0);
+ raw_len = length;
+
+#ifdef DEBUG
+ if ((status = jar_insanity_check(raw_manifest, raw_len)) < 0)
+ return status;
+#endif
+
+ /* null terminate the first line */
+ raw_manifest = jar_eat_line(0, PR_TRUE, raw_manifest, &raw_len);
+
+ /* skip over the preliminary section */
+ /* This is one section at the top of the file with global metainfo */
+ while (raw_len > 0) {
+ JAR_Metainfo *met;
+
+ raw_manifest = jar_eat_line(1, PR_TRUE, raw_manifest, &raw_len);
+ if (raw_len <= 0 || !*raw_manifest)
+ break;
+
+ met = PORT_ZNew(JAR_Metainfo);
+ if (met == NULL)
+ return JAR_ERR_MEMORY;
+
+ /* Parse out the header & info */
+ if (PORT_Strlen(raw_manifest) >= SZ) {
+ /* almost certainly nonsense */
+ PORT_Free(met);
+ continue;
+ }
+
+ PORT_Strcpy(line, raw_manifest);
+ x_info = line;
+
+ while (*x_info && *x_info != ' ' && *x_info != '\t' && *x_info != ':')
+ x_info++;
+
+ if (*x_info)
+ *x_info++ = 0;
+
+ while (*x_info == ' ' || *x_info == '\t')
+ x_info++;
+
+ /* metainfo (name, value) pair is now (line, x_info) */
+ met->header = PORT_Strdup(line);
+ met->info = PORT_Strdup(x_info);
+
+ if (type == jarTypeMF) {
+ ADDITEM(jar->metainfo, jarTypeMeta,
+ /* pathname */ NULL, met, sizeof(JAR_Metainfo));
+ }
+
+ /* For SF files, this metadata may be the digests
+ of the MF file, still in the "met" structure. */
+
+ if (type == jarTypeSF) {
+ if (!PORT_Strcasecmp(line, "MD5-Digest")) {
+ sf_md5 = (char *)met->info;
+ } else if (!PORT_Strcasecmp(line, "SHA1-Digest") ||
+ !PORT_Strcasecmp(line, "SHA-Digest")) {
+ sf_sha1 = (char *)met->info;
+ } else {
+ PORT_Free(met->info);
+ met->info = NULL;
+ }
+ }
+
+ if (type != jarTypeMF) {
+ PORT_Free(met->header);
+ if ((type != jarTypeSF || !jar->globalmeta) && met->info) {
+ PORT_Free(met->info);
+ }
+ PORT_Free(met);
+ }
+ }
+
+ if (type == jarTypeSF && jar->globalmeta) {
+ /* this is a SF file which may contain a digest of the manifest.mf's
+ global metainfo. */
+
+ int match = 0;
+ JAR_Digest *glob = jar->globalmeta;
+
+ if (sf_md5) {
+ unsigned int md5_length;
+ unsigned char *md5_digest;
+
+ md5_digest = ATOB_AsciiToData(sf_md5, &md5_length);
+ PORT_Assert(md5_length == MD5_LENGTH);
+ PORT_Free(sf_md5);
+
+ if (md5_length != MD5_LENGTH)
+ return JAR_ERR_CORRUPT;
+
+ match = PORT_Memcmp(md5_digest, glob->md5, MD5_LENGTH);
+ PORT_Free(md5_digest);
+ }
+
+ if (sf_sha1 && match == 0) {
+ unsigned int sha1_length;
+ unsigned char *sha1_digest;
+
+ sha1_digest = ATOB_AsciiToData(sf_sha1, &sha1_length);
+ PORT_Assert(sha1_length == SHA1_LENGTH);
+ PORT_Free(sf_sha1);
+
+ if (sha1_length != SHA1_LENGTH)
+ return JAR_ERR_CORRUPT;
+
+ match = PORT_Memcmp(sha1_digest, glob->sha1, SHA1_LENGTH);
+ PORT_Free(sha1_digest);
+ }
+
+ if (match != 0) {
+ /* global digest doesn't match, SF file therefore invalid */
+ jar->valid = JAR_ERR_METADATA;
+ return JAR_ERR_METADATA;
+ }
+ }
+
+ /* done with top section of global data */
+ while (raw_len > 0) {
+ *x_md5 = 0;
+ *x_sha = 0;
+ *x_name = 0;
+
+ /* If this is a manifest file, attempt to get a digest of the following
+ section, without damaging it. This digest will be saved later. */
+
+ if (type == jarTypeMF) {
+ char *sec;
+ long sec_len = raw_len;
+
+ if (!*raw_manifest || *raw_manifest == '\n') {
+ /* skip the blank line */
+ sec = jar_eat_line(1, PR_FALSE, raw_manifest, &sec_len);
+ } else
+ sec = raw_manifest;
+
+ if (sec_len > 0 && !PORT_Strncasecmp(sec, "Name:", 5)) {
+ if (type == jarTypeMF)
+ mfdig = jar_digest_section(sec, sec_len);
+ else
+ mfdig = NULL;
+ }
+ }
+
+ while (raw_len > 0) {
+ raw_manifest = jar_eat_line(1, PR_TRUE, raw_manifest, &raw_len);
+ if (raw_len <= 0 || !*raw_manifest)
+ break; /* blank line, done with this entry */
+
+ if (PORT_Strlen(raw_manifest) >= SZ) {
+ /* almost certainly nonsense */
+ continue;
+ }
+
+ /* Parse out the name/value pair */
+ PORT_Strcpy(line, raw_manifest);
+ x_info = line;
+
+ while (*x_info && *x_info != ' ' && *x_info != '\t' &&
+ *x_info != ':')
+ x_info++;
+
+ if (*x_info)
+ *x_info++ = 0;
+
+ while (*x_info == ' ' || *x_info == '\t')
+ x_info++;
+
+ if (!PORT_Strcasecmp(line, "Name"))
+ PORT_Strcpy(x_name, x_info);
+ else if (!PORT_Strcasecmp(line, "MD5-Digest"))
+ PORT_Strcpy(x_md5, x_info);
+ else if (!PORT_Strcasecmp(line, "SHA1-Digest") ||
+ !PORT_Strcasecmp(line, "SHA-Digest"))
+ PORT_Strcpy(x_sha, x_info);
+
+ /* Algorithm list is meta info we don't care about; keeping it out
+ of metadata saves significant space for large jar files */
+ else if (!PORT_Strcasecmp(line, "Digest-Algorithms") ||
+ !PORT_Strcasecmp(line, "Hash-Algorithms"))
+ continue;
+
+ /* Meta info is only collected for the manifest.mf file,
+ since the JAR_get_metainfo call does not support identity */
+ else if (type == jarTypeMF) {
+ JAR_Metainfo *met;
+
+ /* this is meta-data */
+ met = PORT_ZNew(JAR_Metainfo);
+ if (met == NULL)
+ return JAR_ERR_MEMORY;
+
+ /* metainfo (name, value) pair is now (line, x_info) */
+ if ((met->header = PORT_Strdup(line)) == NULL) {
+ PORT_Free(met);
+ return JAR_ERR_MEMORY;
+ }
+
+ if ((met->info = PORT_Strdup(x_info)) == NULL) {
+ PORT_Free(met->header);
+ PORT_Free(met);
+ return JAR_ERR_MEMORY;
+ }
+
+ ADDITEM(jar->metainfo, jarTypeMeta,
+ x_name, met, sizeof(JAR_Metainfo));
+ }
+ }
+
+ if (!*x_name) {
+ /* Whatever that was, it wasn't an entry, because we didn't get a
+ name. We don't really have anything, so don't record this. */
+ continue;
+ }
+
+ dig = PORT_ZNew(JAR_Digest);
+ if (dig == NULL)
+ return JAR_ERR_MEMORY;
+
+ if (*x_md5) {
+ unsigned int binary_length;
+ unsigned char *binary_digest;
+
+ binary_digest = ATOB_AsciiToData(x_md5, &binary_length);
+ PORT_Assert(binary_length == MD5_LENGTH);
+ if (binary_length != MD5_LENGTH) {
+ PORT_Free(dig);
+ return JAR_ERR_CORRUPT;
+ }
+ memcpy(dig->md5, binary_digest, MD5_LENGTH);
+ dig->md5_status = jarHashPresent;
+ PORT_Free(binary_digest);
+ }
+
+ if (*x_sha) {
+ unsigned int binary_length;
+ unsigned char *binary_digest;
+
+ binary_digest = ATOB_AsciiToData(x_sha, &binary_length);
+ PORT_Assert(binary_length == SHA1_LENGTH);
+ if (binary_length != SHA1_LENGTH) {
+ PORT_Free(dig);
+ return JAR_ERR_CORRUPT;
+ }
+ memcpy(dig->sha1, binary_digest, SHA1_LENGTH);
+ dig->sha1_status = jarHashPresent;
+ PORT_Free(binary_digest);
+ }
+
+ PORT_Assert(type == jarTypeMF || type == jarTypeSF);
+ if (type == jarTypeMF) {
+ ADDITEM(jar->hashes, jarTypeMF, x_name, dig, sizeof(JAR_Digest));
+ } else if (type == jarTypeSF) {
+ ADDITEM(signer->sf, jarTypeSF, x_name, dig, sizeof(JAR_Digest));
+ } else {
+ PORT_Free(dig);
+ return JAR_ERR_ORDER;
+ }
+
+ /* we're placing these calculated digests of manifest.mf
+ sections in a list where they can subsequently be forgotten */
+ if (type == jarTypeMF && mfdig) {
+ ADDITEM(jar->manifest, jarTypeSect,
+ x_name, mfdig, sizeof(JAR_Digest));
+ mfdig = NULL;
+ }
+
+ /* Retrieve our saved SHA1 digest from saved copy and check digests.
+ This is just comparing the digest of the MF section as indicated in
+ the SF file with the one we remembered from parsing the MF file */
+
+ if (type == jarTypeSF) {
+ if ((status = jar_internal_digest(jar, path, x_name, dig)) < 0)
+ return status;
+ }
+ }
+
+ return 0;
+}
+
+static int
+jar_internal_digest(JAR *jar, const char *path, char *x_name, JAR_Digest *dig)
+{
+ int cv;
+ int status;
+
+ JAR_Digest *savdig;
+
+ savdig = jar_get_mf_digest(jar, x_name);
+ if (savdig == NULL) {
+ /* no .mf digest for this pathname */
+ status = jar_signal(JAR_ERR_ENTRY, jar, path, x_name);
+ if (status < 0)
+ return 0; /* was continue; */
+ return status;
+ }
+
+ /* check for md5 consistency */
+ if (dig->md5_status) {
+ cv = PORT_Memcmp(savdig->md5, dig->md5, MD5_LENGTH);
+ /* md5 hash of .mf file is not what expected */
+ if (cv) {
+ status = jar_signal(JAR_ERR_HASH, jar, path, x_name);
+
+ /* bad hash, man */
+ dig->md5_status = jarHashBad;
+ savdig->md5_status = jarHashBad;
+
+ if (status < 0)
+ return 0; /* was continue; */
+ return status;
+ }
+ }
+
+ /* check for sha1 consistency */
+ if (dig->sha1_status) {
+ cv = PORT_Memcmp(savdig->sha1, dig->sha1, SHA1_LENGTH);
+ /* sha1 hash of .mf file is not what expected */
+ if (cv) {
+ status = jar_signal(JAR_ERR_HASH, jar, path, x_name);
+
+ /* bad hash, man */
+ dig->sha1_status = jarHashBad;
+ savdig->sha1_status = jarHashBad;
+
+ if (status < 0)
+ return 0; /* was continue; */
+ return status;
+ }
+ }
+ return 0;
+}
+
+#ifdef DEBUG
+/*
+ * j a r _ i n s a n i t y _ c h e c k
+ *
+ * Check for illegal characters (or possibly so)
+ * in the manifest files, to detect potential memory
+ * corruption by our neighbors. Debug only, since
+ * not I18N safe.
+ *
+ */
+static int
+jar_insanity_check(char *data, long length)
+{
+ int c;
+ long off;
+
+ for (off = 0; off < length; off++) {
+ c = data[off];
+ if (c == '\n' || c == '\r' || (c >= ' ' && c <= 128))
+ continue;
+ return JAR_ERR_CORRUPT;
+ }
+ return 0;
+}
+#endif
+
+/*
+ * j a r _ p a r s e _ d i g i t a l _ s i g n a t u r e
+ *
+ * Parse an RSA or DSA (or perhaps other) digital signature.
+ * Right now everything is PKCS7.
+ *
+ */
+static int
+jar_parse_digital_signature(char *raw_manifest, JAR_Signer *signer,
+ long length, JAR *jar)
+{
+ return jar_validate_pkcs7(jar, signer, raw_manifest, length);
+}
+
+/*
+ * j a r _ a d d _ c e r t
+ *
+ * Add information for the given certificate
+ * (or whatever) to the JAR linked list. A pointer
+ * is passed for some relevant reference, say
+ * for example the original certificate.
+ *
+ */
+static int
+jar_add_cert(JAR *jar, JAR_Signer *signer, int type, CERTCertificate *cert)
+{
+ JAR_Cert *fing;
+ unsigned char *keyData;
+
+ if (cert == NULL)
+ return JAR_ERR_ORDER;
+
+ fing = PORT_ZNew(JAR_Cert);
+ if (fing == NULL)
+ goto loser;
+
+ fing->cert = CERT_DupCertificate(cert);
+
+ /* get the certkey */
+ fing->length = cert->derIssuer.len + 2 + cert->serialNumber.len;
+ fing->key = keyData = (unsigned char *)PORT_ZAlloc(fing->length);
+ if (fing->key == NULL)
+ goto loser;
+ keyData[0] = ((cert->derIssuer.len) >> 8) & 0xff;
+ keyData[1] = ((cert->derIssuer.len) & 0xff);
+ PORT_Memcpy(&keyData[2], cert->derIssuer.data, cert->derIssuer.len);
+ PORT_Memcpy(&keyData[2 + cert->derIssuer.len], cert->serialNumber.data,
+ cert->serialNumber.len);
+
+ ADDITEM(signer->certs, type, NULL, fing, sizeof(JAR_Cert));
+ return 0;
+
+loser:
+ if (fing) {
+ if (fing->cert)
+ CERT_DestroyCertificate(fing->cert);
+ PORT_Free(fing);
+ }
+ return JAR_ERR_MEMORY;
+}
+
+/*
+ * e a t _ l i n e
+ *
+ * Reads and/or modifies input buffer "data" of length "*len".
+ * This function does zero, one or two of the following tasks:
+ * 1) if "lines" is non-zero, it reads and discards that many lines from
+ * the input. NUL characters are treated as end-of-line characters,
+ * not as end-of-input characters. The input is NOT NUL terminated.
+ * Note: presently, all callers pass either 0 or 1 for lines.
+ * 2) After skipping the specified number of input lines, if "eating" is
+ * non-zero, it finds the end of the next line of input and replaces
+ * the end of line character(s) with a NUL character.
+ * This function modifies the input buffer, containing the file, in place.
+ * This function handles PC, Mac, and Unix style text files.
+ * On entry, *len contains the maximum number of characters that this
+ * function should ever examine, starting with the character in *data.
+ * On return, *len is reduced by the number of characters skipped by the
+ * first task, if any;
+ * If lines is zero and eating is false, this function returns
+ * the value in the data argument, but otherwise does nothing.
+ */
+static char *
+jar_eat_line(int lines, int eating, char *data, long *len)
+{
+ char *start = data;
+ long maxLen = *len;
+
+ if (maxLen <= 0)
+ return start;
+
+#define GO_ON ((data - start) < maxLen)
+
+ /* Eat the requisite number of lines, if any;
+ prior to terminating the current line with a 0. */
+ for (/* yip */; lines > 0; lines--) {
+ while (GO_ON && *data && *data != '\r' && *data != '\n')
+ data++;
+
+ /* Eat any leading CR */
+ if (GO_ON && *data == '\r')
+ data++;
+
+ /* After the CR, ok to eat one LF */
+ if (GO_ON && *data == '\n')
+ data++;
+
+ /* If there are NULs, this function probably put them there */
+ while (GO_ON && !*data)
+ data++;
+ }
+ maxLen -= data - start; /* we have this many characters left. */
+ *len = maxLen;
+ start = data; /* now start again here. */
+ if (maxLen > 0 && eating) {
+ /* Terminate this line with a 0 */
+ while (GO_ON && *data && *data != '\n' && *data != '\r')
+ data++;
+
+ /* If not past the end, we are allowed to eat one CR */
+ if (GO_ON && *data == '\r')
+ *data++ = 0;
+
+ /* After the CR (if any), if not past the end, ok to eat one LF */
+ if (GO_ON && *data == '\n')
+ *data++ = 0;
+ }
+ return start;
+}
+#undef GO_ON
+
+/*
+ * j a r _ d i g e s t _ s e c t i o n
+ *
+ * Return the digests of the next section of the manifest file.
+ * Does not damage the manifest file, unlike parse_manifest.
+ *
+ */
+static JAR_Digest *
+jar_digest_section(char *manifest, long length)
+{
+ long global_len;
+ char *global_end;
+
+ global_end = manifest;
+ global_len = length;
+
+ while (global_len > 0) {
+ global_end = jar_eat_line(1, PR_FALSE, global_end, &global_len);
+ if (global_len > 0 && (*global_end == 0 || *global_end == '\n'))
+ break;
+ }
+ return JAR_calculate_digest(manifest, global_end - manifest);
+}
+
+/*
+ * J A R _ v e r i f y _ d i g e s t
+ *
+ * Verifies that a precalculated digest matches the
+ * expected value in the manifest.
+ *
+ */
+int PR_CALLBACK
+JAR_verify_digest(JAR *jar, const char *name, JAR_Digest *dig)
+{
+ JAR_Item *it;
+ JAR_Digest *shindig;
+ ZZLink *link;
+ ZZList *list = jar->hashes;
+ int result1 = 0;
+ int result2 = 0;
+
+ if (jar->valid < 0) {
+ /* signature not valid */
+ return JAR_ERR_SIG;
+ }
+ if (ZZ_ListEmpty(list)) {
+ /* empty list */
+ return JAR_ERR_PNF;
+ }
+
+ for (link = ZZ_ListHead(list);
+ !ZZ_ListIterDone(list, link);
+ link = link->next) {
+ it = link->thing;
+ if (it->type == jarTypeMF &&
+ it->pathname && !PORT_Strcmp(it->pathname, name)) {
+ shindig = (JAR_Digest *)it->data;
+ if (shindig->md5_status) {
+ if (shindig->md5_status == jarHashBad)
+ return JAR_ERR_HASH;
+ result1 = memcmp(dig->md5, shindig->md5, MD5_LENGTH);
+ }
+ if (shindig->sha1_status) {
+ if (shindig->sha1_status == jarHashBad)
+ return JAR_ERR_HASH;
+ result2 = memcmp(dig->sha1, shindig->sha1, SHA1_LENGTH);
+ }
+ return (result1 == 0 && result2 == 0) ? 0 : JAR_ERR_HASH;
+ }
+ }
+ return JAR_ERR_PNF;
+}
+
+/*
+ * J A R _ f e t c h _ c e r t
+ *
+ * Given an opaque identifier of a certificate,
+ * return the full certificate.
+ *
+ * The new function, which retrieves by key.
+ *
+ */
+CERTCertificate *
+JAR_fetch_cert(long length, void *key)
+{
+ CERTIssuerAndSN issuerSN;
+ CERTCertificate *cert = NULL;
+ CERTCertDBHandle *certdb;
+
+ certdb = JAR_open_database();
+ if (certdb) {
+ unsigned char *keyData = (unsigned char *)key;
+ issuerSN.derIssuer.len = (keyData[0] << 8) + keyData[0];
+ issuerSN.derIssuer.data = &keyData[2];
+ issuerSN.serialNumber.len = length - (2 + issuerSN.derIssuer.len);
+ issuerSN.serialNumber.data = &keyData[2 + issuerSN.derIssuer.len];
+ cert = CERT_FindCertByIssuerAndSN(certdb, &issuerSN);
+ JAR_close_database(certdb);
+ }
+ return cert;
+}
+
+/*
+ * j a r _ g e t _ m f _ d i g e s t
+ *
+ * Retrieve a corresponding saved digest over a section
+ * of the main manifest file.
+ *
+ */
+static JAR_Digest *
+jar_get_mf_digest(JAR *jar, char *pathname)
+{
+ JAR_Item *it;
+ JAR_Digest *dig;
+ ZZLink *link;
+ ZZList *list = jar->manifest;
+
+ if (ZZ_ListEmpty(list))
+ return NULL;
+
+ for (link = ZZ_ListHead(list);
+ !ZZ_ListIterDone(list, link);
+ link = link->next) {
+ it = link->thing;
+ if (it->type == jarTypeSect &&
+ it->pathname && !PORT_Strcmp(it->pathname, pathname)) {
+ dig = (JAR_Digest *)it->data;
+ return dig;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * j a r _ b a s e n a m e
+ *
+ * Return the basename -- leading components of path stripped off,
+ * extension ripped off -- of a path.
+ *
+ */
+static char *
+jar_basename(const char *path)
+{
+ char *pith, *e, *basename, *ext;
+
+ if (path == NULL)
+ return PORT_Strdup("");
+
+ pith = PORT_Strdup(path);
+ basename = pith;
+ while (1) {
+ for (e = basename; *e && *e != '/' && *e != '\\'; e++)
+ /* yip */;
+ if (*e)
+ basename = ++e;
+ else
+ break;
+ }
+
+ if ((ext = PORT_Strrchr(basename, '.')) != NULL)
+ *ext = 0;
+
+ /* We already have the space allocated */
+ PORT_Strcpy(pith, basename);
+ return pith;
+}
+
+/*
+ * + + + + + + + + + + + + + + +
+ *
+ * CRYPTO ROUTINES FOR JAR
+ *
+ * The following functions are the cryptographic
+ * interface to PKCS7 for Jarnatures.
+ *
+ * + + + + + + + + + + + + + + +
+ *
+ */
+
+/*
+ * j a r _ c a t c h _ b y t e s
+ *
+ * In the event signatures contain enveloped data, it will show up here.
+ * But note that the lib/pkcs7 routines aren't ready for it.
+ *
+ */
+static void
+jar_catch_bytes(void *arg, const char *buf, unsigned long len)
+{
+ /* Actually this should never be called, since there is
+ presumably no data in the signature itself. */
+}
+
+/*
+ * j a r _ v a l i d a t e _ p k c s 7
+ *
+ * Validate (and decode, if necessary) a binary pkcs7
+ * signature in DER format.
+ *
+ */
+static int
+jar_validate_pkcs7(JAR *jar, JAR_Signer *signer, char *data, long length)
+{
+
+ SEC_PKCS7ContentInfo *cinfo = NULL;
+ SEC_PKCS7DecoderContext *dcx;
+ PRBool goodSig;
+ int status = 0;
+ SECItem detdig;
+
+ PORT_Assert(jar != NULL && signer != NULL);
+
+ if (jar == NULL || signer == NULL)
+ return JAR_ERR_ORDER;
+
+ signer->valid = JAR_ERR_SIG;
+
+ /* We need a context if we can get one */
+ dcx = SEC_PKCS7DecoderStart(jar_catch_bytes, NULL /*cb_arg*/,
+ NULL /*getpassword*/, jar->mw,
+ NULL, NULL, NULL);
+ if (dcx == NULL) {
+ /* strange pkcs7 failure */
+ return JAR_ERR_PK7;
+ }
+
+ SEC_PKCS7DecoderUpdate(dcx, data, length);
+ cinfo = SEC_PKCS7DecoderFinish(dcx);
+ if (cinfo == NULL) {
+ /* strange pkcs7 failure */
+ return JAR_ERR_PK7;
+ }
+ if (SEC_PKCS7ContentIsEncrypted(cinfo)) {
+ /* content was encrypted, fail */
+ return JAR_ERR_PK7;
+ }
+ if (SEC_PKCS7ContentIsSigned(cinfo) == PR_FALSE) {
+ /* content was not signed, fail */
+ return JAR_ERR_PK7;
+ }
+
+ PORT_SetError(0);
+
+ /* use SHA1 only */
+ detdig.len = SHA1_LENGTH;
+ detdig.data = signer->digest->sha1;
+ goodSig = SEC_PKCS7VerifyDetachedSignature(cinfo,
+ certUsageObjectSigner,
+ &detdig, HASH_AlgSHA1,
+ PR_FALSE);
+ jar_gather_signers(jar, signer, cinfo);
+ if (goodSig == PR_TRUE) {
+ /* signature is valid */
+ signer->valid = 0;
+ } else {
+ status = PORT_GetError();
+ PORT_Assert(status < 0);
+ if (status >= 0)
+ status = JAR_ERR_SIG;
+ jar->valid = status;
+ signer->valid = status;
+ }
+ jar->pkcs7 = PR_TRUE;
+ signer->pkcs7 = PR_TRUE;
+ SEC_PKCS7DestroyContentInfo(cinfo);
+ return status;
+}
+
+/*
+ * j a r _ g a t h e r _ s i g n e r s
+ *
+ * Add the single signer of this signature to the
+ * certificate linked list.
+ *
+ */
+static int
+jar_gather_signers(JAR *jar, JAR_Signer *signer, SEC_PKCS7ContentInfo *cinfo)
+{
+ int result;
+ CERTCertificate *cert;
+ CERTCertDBHandle *certdb;
+ SEC_PKCS7SignedData *sdp = cinfo->content.signedData;
+ SEC_PKCS7SignerInfo **pksigners, *pksigner;
+
+ if (sdp == NULL)
+ return JAR_ERR_PK7;
+
+ pksigners = sdp->signerInfos;
+ /* permit exactly one signer */
+ if (pksigners == NULL || pksigners[0] == NULL || pksigners[1] != NULL)
+ return JAR_ERR_PK7;
+
+ pksigner = *pksigners;
+ cert = pksigner->cert;
+
+ if (cert == NULL)
+ return JAR_ERR_PK7;
+
+ certdb = JAR_open_database();
+ if (certdb == NULL)
+ return JAR_ERR_GENERAL;
+
+ result = jar_add_cert(jar, signer, jarTypeSign, cert);
+ JAR_close_database(certdb);
+ return result;
+}
+
+/*
+ * j a r _ o p e n _ d a t a b a s e
+ *
+ * Open the certificate database,
+ * for use by JAR functions.
+ *
+ */
+CERTCertDBHandle *
+JAR_open_database(void)
+{
+ return CERT_GetDefaultCertDB();
+}
+
+/*
+ * j a r _ c l o s e _ d a t a b a s e
+ *
+ * Close the certificate database.
+ * For use by JAR functions.
+ *
+ */
+int
+JAR_close_database(CERTCertDBHandle *certdb)
+{
+ return 0;
+}
+
+/*
+ * j a r _ s i g n a l
+ *
+ * Nonfatal errors come here to callback Java.
+ *
+ */
+static int
+jar_signal(int status, JAR *jar, const char *metafile, char *pathname)
+{
+ char *errstring = JAR_get_error(status);
+ if (jar->signal) {
+ (*jar->signal)(status, jar, metafile, pathname, errstring);
+ return 0;
+ }
+ return status;
+}
+
+/*
+ * j a r _ a p p e n d
+ *
+ * Tack on an element to one of a JAR's linked
+ * lists, with rudimentary error handling.
+ *
+ */
+int
+jar_append(ZZList *list, int type, char *pathname, void *data, size_t size)
+{
+ JAR_Item *it = PORT_ZNew(JAR_Item);
+ ZZLink *entity;
+
+ if (it == NULL)
+ goto loser;
+
+ if (pathname) {
+ it->pathname = PORT_Strdup(pathname);
+ if (it->pathname == NULL)
+ goto loser;
+ }
+
+ it->type = (jarType)type;
+ it->data = (unsigned char *)data;
+ it->size = size;
+ entity = ZZ_NewLink(it);
+ if (entity) {
+ ZZ_AppendLink(list, entity);
+ return 0;
+ }
+
+loser:
+ if (it) {
+ if (it->pathname)
+ PORT_Free(it->pathname);
+ PORT_Free(it);
+ }
+ return JAR_ERR_MEMORY;
+}
diff --git a/security/nss/lib/jar/jzconf.h b/security/nss/lib/jar/jzconf.h
new file mode 100644
index 000000000..7687eb3a5
--- /dev/null
+++ b/security/nss/lib/jar/jzconf.h
@@ -0,0 +1,189 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+/* This file was modified since it was taken from the zlib distribution */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#define deflateInit_ z_deflateInit_
+#define deflate z_deflate
+#define deflateEnd z_deflateEnd
+#define inflateInit_ z_inflateInit_
+#define inflate z_inflate
+#define inflateEnd z_inflateEnd
+#define deflateInit2_ z_deflateInit2_
+#define deflateSetDictionary z_deflateSetDictionary
+#define deflateCopy z_deflateCopy
+#define deflateReset z_deflateReset
+#define deflateParams z_deflateParams
+#define inflateInit2_ z_inflateInit2_
+#define inflateSetDictionary z_inflateSetDictionary
+#define inflateSync z_inflateSync
+#define inflateReset z_inflateReset
+#define compress z_compress
+#define uncompress z_uncompress
+#define adler32 z_adler32
+#define crc32 z_crc32
+#define get_crc_table z_get_crc_table
+
+#define Byte z_Byte
+#define uInt z_uInt
+#define uLong z_uLong
+#define Bytef z_Bytef
+#define charf z_charf
+#define intf z_intf
+#define uIntf z_uIntf
+#define uLongf z_uLongf
+#define voidpf z_voidpf
+#define voidp z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+#ifndef __32BIT__
+#define __32BIT__
+#endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+#define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+#define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32) || defined(XP_OS2)) && !defined(STDC)
+#define STDC
+#endif
+#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
+#define STDC
+#endif
+
+#ifndef STDC
+#ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#define const
+#endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) || defined(THINK_C) || defined(__SC__)
+#define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#ifdef MAXSEG_64K
+#define MAX_MEM_LEVEL 8
+#else
+#define MAX_MEM_LEVEL 9
+#endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+#define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ 1 << (windowBits+2) + 1 << (memLevel+9)
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+/* Type declarations */
+
+#ifndef OF /* function prototypes */
+#ifdef STDC
+#define OF(args) args
+#else
+#define OF(args) ()
+#endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+/* MSC small or medium model */
+#define SMALL_MEDIUM
+#ifdef _MSC_VER
+#define FAR __far
+#else
+#define FAR far
+#endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+#ifndef __32BIT__
+#define SMALL_MEDIUM
+#define FAR __far
+#endif
+#endif
+#ifndef FAR
+#define FAR
+#endif
+
+typedef unsigned char Byte; /* 8 bits */
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
+/* Borland C/C++ ignores FAR inside typedef */
+#define Bytef Byte FAR
+#else
+typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+typedef void FAR *voidpf;
+typedef void *voidp;
+#else
+typedef Byte FAR *voidpf;
+typedef Byte *voidp;
+#endif
+
+#ifdef MOZILLA_CLIENT
+#include "prtypes.h"
+#else
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
+#include <windows.h>
+#define EXPORT WINAPI
+#else
+#define EXPORT
+#endif
+
+#define PR_PUBLIC_API(type) type
+
+#endif /* MOZILLA_CLIENT */
+
+#endif /* _ZCONF_H */
diff --git a/security/nss/lib/jar/jzlib.h b/security/nss/lib/jar/jzlib.h
new file mode 100644
index 000000000..92d3d5b21
--- /dev/null
+++ b/security/nss/lib/jar/jzlib.h
@@ -0,0 +1,916 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.0.4, Jul 24th, 1996.
+
+ Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ gzip@prep.ai.mit.edu madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+/* This file was modified since it was taken from the zlib distribution */
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef MOZILLA_CLIENT
+#include "jzconf.h"
+#else
+#include "zconf.h"
+#endif
+
+#define ZLIB_VERSION "1.0.4"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms may be added later and will have the same
+ stream interface.
+
+ For compression the application must provide the output buffer and
+ may optionally provide the input buffer for optimization. For decompression,
+ the application must provide the input buffer and may optionally provide
+ the output buffer for optimization.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The library does not install any signal handler. It is recommended to
+ add at least a handler for SIGSEGV when decompressing; the library checks
+ the consistency of the input data whenever possible but may go nuts
+ for some forms of corrupted input.
+*/
+
+typedef voidpf(*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void(*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: ascii or binary */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+/* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+/* basic functions */
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(const char *)
+zlibVersion(void);
+#else
+extern const char *EXPORT zlibVersion OF((void));
+#endif
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+extern int EXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+deflate(z_streamp strm, int flush);
+#else
+extern int EXPORT deflate OF((z_streamp strm, int flush));
+#endif
+/*
+ Performs one or both of the following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
+ block is terminated and flushed to the output buffer so that the
+ decompressor can get all input data available so far. For method 9, a future
+ variant on method 8, the current block will be flushed but not terminated.
+ Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
+ output is byte aligned (the compressor can clear its internal bit buffer)
+ and the current block is always terminated; this can be useful if the
+ compressor has to be restarted from scratch after an interruption (in which
+ case the internal state of the compressor may be lost).
+ If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
+ special marker is output and the compression dictionary is discarded; this
+ is useful to allow the decompressor to synchronize if one compressed block
+ has been damaged (see inflateSync below). Flushing degrades compression and
+ so should be used only when necessary. Using Z_FULL_FLUSH too often can
+ seriously degrade the compression. If deflate returns with avail_out == 0,
+ this function must be called again with the same value of the flush
+ parameter and more output space (updated avail_out), until the flush is
+ complete (deflate returns with non-zero avail_out).
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+deflateEnd(z_streamp strm);
+#else
+extern int EXPORT deflateEnd OF((z_streamp strm));
+#endif
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+/*
+extern int EXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller. If
+ zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
+ allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
+ with the version assumed by the caller. msg is set to null if there is no
+ error message. inflateInit does not perform any decompression: this will be
+ done by inflate().
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+inflate(z_streamp strm, int flush);
+#else
+extern int EXPORT inflate OF((z_streamp strm, int flush));
+#endif
+/*
+ Performs one or both of the following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH, inflate flushes as much
+ output as possible to the output buffer. The flushing behavior of inflate is
+ not specified for values of the flush parameter other than Z_PARTIAL_FLUSH
+ and Z_FINISH, but the current implementation actually flushes as much output
+ as possible anyway.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ inflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if the end of the
+ compressed data has been reached and all uncompressed output has been
+ produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
+ inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
+ Z_STREAM_ERROR if the stream structure was inconsistent (for example if
+ next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in
+ the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
+ application may then call inflateSync to look for a good compression block.
+ In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
+ dictionary chosen by the compressor.
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+inflateEnd(z_streamp strm);
+#else
+extern int EXPORT inflateEnd OF((z_streamp strm));
+#endif
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+/* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+extern int EXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library. (Method 9 will allow a 64K history buffer and
+ partial block flushes.)
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library (the value 16 will be allowed for method 9). Larger
+ values of this parameter result in better compression at the expense of
+ memory usage. The default value is 15 if deflateInit is used instead.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match). Filtered data consists mostly of small values with a
+ somewhat random distribution. In this case, the compression algorithm is
+ tuned to compress them better. The effect of Z_FILTERED is to force more
+ Huffman coding and less string matching; it is somewhat intermediate
+ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+ the compression ratio but not the correctness of the compressed output even
+ if it is not set appropriately.
+
+ If next_in is not null, the library will use this buffer to hold also
+ some history information; the buffer must either hold the entire input
+ data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
+ is null, the library will allocate its own history buffer (and leave next_in
+ null). next_out need not be provided here but must be provided by the
+ application for the next call of deflate().
+
+ If the history buffer is provided by the application, next_in must
+ must never be changed by the application since the compressor maintains
+ information inside this buffer from call to call; the application
+ must provide more input only by increasing avail_in. next_in is always
+ reset by the library in this case.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ an invalid method). msg is set to null if there is no error message.
+ deflateInit2 does not perform any compression: this will be done by
+ deflate().
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+deflateSetDictionary(z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength);
+#else
+extern int EXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+#endif
+/*
+ Initializes the compression dictionary (history buffer) from the given
+ byte sequence without producing any compressed output. This function must
+ be called immediately after deflateInit or deflateInit2, before any call
+ of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and
+ can be predicted with good accuracy; the data can then be compressed better
+ than with the default empty dictionary. In this version of the library,
+ only the last 32K bytes of the dictionary are used.
+ Upon return of this function, strm->adler is set to the Adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The Adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.)
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state
+ is inconsistent (for example if deflate has already been called for this
+ stream). deflateSetDictionary does not perform any compression: this will
+ be done by deflate().
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+deflateCopy(z_streamp dest, z_streamp source);
+#else
+extern int EXPORT deflateCopy OF((z_streamp dest, z_streamp source));
+#endif
+/*
+ Sets the destination stream as a complete copy of the source stream. If
+ the source stream is using an application-supplied history buffer, a new
+ buffer is allocated for the destination stream. The compressed output
+ buffer is always application-supplied. It's the responsibility of the
+ application to provide the correct values of next_out and avail_out for the
+ next call of deflate.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+deflateReset(z_streamp strm);
+#else
+extern int EXPORT deflateReset OF((z_streamp strm));
+#endif
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+deflateParams(z_streamp strm, int level, int strategy);
+#else
+extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
+#endif
+/*
+ Dynamically update the compression level and compression strategy.
+ This can be used to switch between compression and straight copy of
+ the input data, or to switch to a different kind of input data requiring
+ a different strategy. If the compression level is changed, the input
+ available so far is compressed with the old level (and may be flushed);
+ the new level will take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+/*
+extern int EXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with more compression options. The
+ fields next_out, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library (the value 16 will be allowed soon). The
+ default value is 15 if inflateInit is used instead. If a compressed stream
+ with a larger window size is given as input, inflate() will return with
+ the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ If next_out is not null, the library will use this buffer for the history
+ buffer; the buffer must either be large enough to hold the entire output
+ data, or have at least 1<<windowBits bytes. If next_out is null, the
+ library will allocate its own buffer (and leave next_out null). next_in
+ need not be provided here but must be provided by the application for the
+ next call of inflate().
+
+ If the history buffer is provided by the application, next_out must
+ never be changed by the application since the decompressor maintains
+ history information inside this buffer from call to call; the application
+ can only reset next_out to the beginning of the history buffer when
+ avail_out is zero and all output has been consumed.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ windowBits < 8). msg is set to null if there is no error message.
+ inflateInit2 does not perform any decompression: this will be done by
+ inflate().
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+inflateSetDictionary(z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength);
+#else
+extern int EXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+#endif
+/*
+ Initializes the decompression dictionary (history buffer) from the given
+ uncompressed byte sequence. This function must be called immediately after
+ a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
+ by the compressor can be determined from the Adler32 value returned by this
+ call of inflate. The compressor and decompressor must use exactly the same
+ dictionary (see deflateSetDictionary).
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect Adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+inflateSync(z_streamp strm);
+#else
+extern int EXPORT inflateSync OF((z_streamp strm));
+#endif
+/*
+ Skips invalid compressed data until the special marker (see deflate()
+ above) can be found, or until all available input is skipped. No output
+ is provided.
+
+ inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no marker has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+inflateReset(z_streamp strm);
+#else
+extern int EXPORT inflateReset OF((z_streamp strm));
+#endif
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+/* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level, window size,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+compress(Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen);
+#else
+extern int EXPORT compress OF((Bytef * dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+#endif
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+uncompress(Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen);
+#else
+extern int EXPORT uncompress OF((Bytef * dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+#endif
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+typedef voidp gzFile;
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(gzFile)
+gzopen(const char *path, const char *mode);
+#else
+extern gzFile EXPORT gzopen OF((const char *path, const char *mode));
+#endif
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9"). gzopen can be used to read a file which is not in gzip format;
+ in this case gzread will directly read from the file without decompression.
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(gzFile)
+gzdopen(int fd, const char *mode);
+#else
+extern gzFile EXPORT gzdopen OF((int fd, const char *mode));
+#endif
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+gzread(gzFile file, voidp buf, unsigned len);
+#else
+extern int EXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+#endif
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+gzwrite(gzFile file, const voidp buf, unsigned len);
+#else
+extern int EXPORT gzwrite OF((gzFile file, const voidp buf, unsigned len));
+#endif
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+gzflush(gzFile file, int flush);
+#else
+extern int EXPORT gzflush OF((gzFile file, int flush));
+#endif
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+gzclose(gzFile file);
+#else
+extern int EXPORT gzclose OF((gzFile file));
+#endif
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(const char *)
+gzerror(gzFile file, int *errnum);
+#else
+extern const char *EXPORT gzerror OF((gzFile file, int *errnum));
+#endif
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+/* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(uLong)
+adler32(uLong adler, const Bytef *buf, uInt len);
+#else
+extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+#endif
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(uLong)
+crc32(uLong crc, const Bytef *buf, uInt len);
+#else
+extern uLong EXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+#endif
+/*
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+/* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+#ifdef MOZILLA_CLIENT
+PR_EXTERN(int)
+deflateInit(z_streamp strm, int level, const char *version,
+ int stream_size);
+PR_EXTERN(int)
+inflateInit_(z_streamp strm, const char *version,
+ int stream_size);
+PR_EXTERN(int)
+deflateInit2_(z_streamp strm, int level, int method,
+ int windowBits, int memLevel, int strategy,
+ const char *version, int stream_size);
+PR_EXTERN(int)
+inflateInit2_(z_streamp strm, int windowBits,
+ const char *version, int stream_size);
+#else
+extern int EXPORT deflateInit_ OF((z_streamp strm, int level, const char *version,
+ int stream_size));
+extern int EXPORT inflateInit_ OF((z_streamp strm, const char *version,
+ int stream_size));
+extern int EXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel, int strategy,
+ const char *version, int stream_size));
+extern int EXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+#endif /* MOZILLA_CLIENT */
+
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm), (level), (method), (windowBits), (memLevel), \
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+struct internal_state {
+ int dummy;
+}; /* hack for buggy compilers */
+#endif
+
+uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/security/nss/lib/jar/manifest.mn b/security/nss/lib/jar/manifest.mn
new file mode 100644
index 000000000..5b516886a
--- /dev/null
+++ b/security/nss/lib/jar/manifest.mn
@@ -0,0 +1,25 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MODULE = nss
+
+LIBRARY_NAME = jar
+
+CORE_DEPTH = ../..
+
+CSRCS = \
+ jarver.c \
+ jarsign.c \
+ jar.c \
+ jar-ds.c \
+ jarfile.c \
+ jarint.c \
+ $(NULL)
+
+EXPORTS = jar.h jar-ds.h jarfile.h
+
+DEFINES = -DMOZILLA_CLIENT=1
+
+# This part of the code, including all sub-dirs, can be optimized for size
+export ALLOW_OPT_CODE_SIZE = 1