diff options
Diffstat (limited to 'security/nss/lib/jar/jarver.c')
-rw-r--r-- | security/nss/lib/jar/jarver.c | 2023 |
1 files changed, 0 insertions, 2023 deletions
diff --git a/security/nss/lib/jar/jarver.c b/security/nss/lib/jar/jarver.c deleted file mode 100644 index e20c4ea39..000000000 --- a/security/nss/lib/jar/jarver.c +++ /dev/null @@ -1,2023 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * JARVER - * - * Jarnature Parsing & Verification - */ - -#define USE_MOZ_THREAD - -#include "jar.h" -#include "jarint.h" - -#ifdef USE_MOZ_THREAD -#include "jarevil.h" -#endif -/*#include "cdbhdl.h" */ -#include "secder.h" - -/* to use huge pointers in win16 */ - -#if !defined(XP_WIN16) -#define xp_HUGE_MEMCPY PORT_Memcpy -#define xp_HUGE_STRCPY PORT_Strcpy -#define xp_HUGE_STRLEN PORT_Strlen -#define xp_HUGE_STRNCASECMP PORT_Strncasecmp -#else -#define xp_HUGE_MEMCPY hmemcpy -int xp_HUGE_STRNCASECMP (char ZHUGEP *buf, char *key, int len); -size_t xp_HUGE_STRLEN (char ZHUGEP *s); -char *xp_HUGE_STRCPY (char *to, char ZHUGEP *from); -#endif - -/* from certdb.h */ -#define CERTDB_USER (1<<6) - -#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 ZHUGEP *jar_eat_line - (int lines, int eating, char ZHUGEP *data, long *len); - -static JAR_Digest *jar_digest_section - (char ZHUGEP *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 CERTCertificate *jar_get_certificate - (JAR *jar, long keylen, void *key, int *result); - -static char *jar_cert_element (char *name, char *tag, int occ); - -static char *jar_choose_nickname (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 ZHUGEP *data, long length); -#endif - -int jar_parse_mf - (JAR *jar, char ZHUGEP *raw_manifest, - long length, const char *path, const char *url); - -int jar_parse_sf - (JAR *jar, char ZHUGEP *raw_manifest, - long length, const char *path, const char *url); - -int jar_parse_sig - (JAR *jar, const char *path, char ZHUGEP *raw_manifest, long length); - -int jar_parse_any - (JAR *jar, int type, JAR_Signer *signer, char ZHUGEP *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 ZHUGEP *raw_manifest, - long length, const char *path, const char *url) - { - -#if defined(XP_WIN16) - PORT_Assert( !IsBadHugeReadPtr(raw_manifest, length) ); -#endif - - /* fill in the path, if supplied. This is a 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; - } - - /* 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) - 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 (!xp_HUGE_STRNCASECMP (raw_manifest, "Manifest-Version:", 17)) - { - return jar_parse_mf (jar, raw_manifest, length, path, url); - } - else if (!xp_HUGE_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 ZHUGEP *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; - -#if 0 - /* XXX Turn this on to disable multiple signers */ - if (jar->digest == NULL) - return JAR_ERR_ORDER; -#endif - - /* 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; - } - -#ifdef XP_WIN16 - /* - * For Win16, copy the portion of the raw_buffer containing the digital - * signature into another buffer... This insures that the data will - * NOT cross a segment boundary. Therefore, - * jar_parse_digital_signature(...) does NOT need to deal with HUGE - * pointers... - */ - - { - unsigned char *manifest_copy; - - manifest_copy = (unsigned char *) PORT_ZAlloc (length); - if (manifest_copy) - { - xp_HUGE_MEMCPY (manifest_copy, raw_manifest, length); - - status = jar_parse_digital_signature - (manifest_copy, signer, length, jar); - - PORT_Free (manifest_copy); - } - else - { - /* out of memory */ - return JAR_ERR_MEMORY; - } - } -#else - /* don't expense unneeded calloc overhead on non-win16 */ - status = jar_parse_digital_signature - (raw_manifest, signer, length, jar); -#endif - - 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 ZHUGEP *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 ZHUGEP *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 ZHUGEP *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) - { - JAR_Metainfo *met; - - raw_manifest = jar_eat_line (1, PR_TRUE, raw_manifest, &raw_len); - if (!*raw_manifest) break; - - met = (JAR_Metainfo*)PORT_ZAlloc (sizeof (JAR_Metainfo)); - if (met == NULL) - return JAR_ERR_MEMORY; - - /* Parse out the header & info */ - - if (xp_HUGE_STRLEN (raw_manifest) >= SZ) - { - /* almost certainly nonsense */ - continue; - } - - xp_HUGE_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; - - if (!PORT_Strcasecmp (line, "SHA1-Digest") || !PORT_Strcasecmp (line, "SHA-Digest")) - sf_sha1 = (char *) met->info; - } - } - - 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 ); - - if (md5_length != MD5_LENGTH) - return JAR_ERR_CORRUPT; - - match = PORT_Memcmp (md5_digest, glob->md5, MD5_LENGTH); - } - - 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 ); - - if (sha1_length != SHA1_LENGTH) - return JAR_ERR_CORRUPT; - - match = PORT_Memcmp (sha1_digest, glob->sha1, SHA1_LENGTH); - } - - 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) - { - *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 ZHUGEP *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 (!xp_HUGE_STRNCASECMP (sec, "Name:", 5)) - { - if (type == jarTypeMF) - mfdig = jar_digest_section (sec, sec_len); - else - mfdig = NULL; - } - } - - - while (raw_len) - { - raw_manifest = jar_eat_line (1, PR_TRUE, raw_manifest, &raw_len); - if (!*raw_manifest) break; /* blank line, done with this entry */ - - if (xp_HUGE_STRLEN (raw_manifest) >= SZ) - { - /* almost certainly nonsense */ - continue; - } - - - /* Parse out the name/value pair */ - - xp_HUGE_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 = (JAR_Metainfo*)PORT_ZAlloc (sizeof (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) - return JAR_ERR_MEMORY; - - if ((met->info = PORT_Strdup (x_info)) == NULL) - return JAR_ERR_MEMORY; - - ADDITEM (jar->metainfo, jarTypeMeta, - x_name, met, sizeof (JAR_Metainfo)); - } - } - - if(!x_name || !*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 = (JAR_Digest*)PORT_ZAlloc (sizeof (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) - return JAR_ERR_CORRUPT; - - memcpy (dig->md5, binary_digest, MD5_LENGTH); - dig->md5_status = jarHashPresent; - } - - 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) - return JAR_ERR_CORRUPT; - - memcpy (dig->sha1, binary_digest, SHA1_LENGTH); - dig->sha1_status = jarHashPresent; - } - - 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 - 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; */ - else - 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; */ - else - 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; */ - else - 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 ZHUGEP *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) - { -#if defined(XP_WIN16) - PORT_Assert( LOWORD(raw_manifest) + length < 0xFFFF ); -#endif - 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 = (JAR_Cert*)PORT_ZAlloc (sizeof (JAR_Cert)); - - if (fing == NULL) - goto loser; - -#ifdef USE_MOZ_THREAD - fing->cert = jar_moz_dup (cert); -#else - fing->cert = CERT_DupCertificate (cert); -#endif - - /* get the certkey */ - - fing->length = cert->derIssuer.len + 2 + cert->serialNumber.len; - - keyData = (unsigned char *) PORT_ZAlloc (fing->length); - fing->key = keyData; - - 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, - /* pathname */ 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 - * - * Consume an ascii line from the top of a file kept - * in memory. This destroys the file in place. This function - * handles PC, Mac, and Unix style text files. - * - */ - -static char ZHUGEP *jar_eat_line - (int lines, int eating, char ZHUGEP *data, long *len) - { - char ZHUGEP *ret; - - ret = data; - if (!*len) return ret; - - /* Eat the requisite number of lines, if any; - prior to terminating the current line with a 0. */ - - for (/* yip */ ; lines; lines--) - { - while (*data && *data != '\n') - data++; - - /* After the CR, ok to eat one LF */ - - if (*data == '\n') - data++; - - /* If there are zeros, we put them there */ - - while (*data == 0 && data - ret < *len) - data++; - } - - *len -= data - ret; - ret = data; - - if (eating) - { - /* Terminate this line with a 0 */ - - while (*data && *data != '\n' && *data != '\r') - data++; - - /* In any case we are allowed to eat CR */ - - if (*data == '\r') - *data++ = 0; - - /* After the CR, ok to eat one LF */ - - if (*data == '\n') - *data++ = 0; - } - - return ret; - } - -/* - * 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 ZHUGEP *manifest, long length) - { - long global_len; - char ZHUGEP *global_end; - - global_end = manifest; - global_len = length; - - while (global_len) - { - global_end = jar_eat_line (1, PR_FALSE, global_end, &global_len); - if (*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; - - int result1, result2; - - list = jar->hashes; - - result1 = 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; - else - result1 = memcmp (dig->md5, shindig->md5, MD5_LENGTH); - } - - if (shindig->sha1_status) - { - if (shindig->sha1_status == jarHashBad) - return JAR_ERR_HASH; - else - result2 = memcmp (dig->sha1, shindig->sha1, SHA1_LENGTH); - } - - return (result1 == 0 && result2 == 0) ? 0 : JAR_ERR_HASH; - } - } - - return JAR_ERR_PNF; - } - -/* - * J A R _ c e r t _ a t t r i b u t e - * - * Return the named certificate attribute from the - * certificate specified by the given key. - * - */ - -int PR_CALLBACK JAR_cert_attribute - (JAR *jar, jarCert attrib, long keylen, void *key, - void **result, unsigned long *length) - { - int status = 0; - char *ret = NULL; - - CERTCertificate *cert; - - CERTCertDBHandle *certdb; - - JAR_Digest *dig; - SECItem hexme; - - *length = 0; - - if (attrib == 0 || key == 0) - return JAR_ERR_GENERAL; - - if (attrib == jarCertJavaHack) - { - cert = (CERTCertificate *) NULL; - certdb = JAR_open_database(); - - if (certdb) - { -#ifdef USE_MOZ_THREAD - cert = jar_moz_nickname (certdb, (char*)key); -#else - cert = CERT_FindCertByNickname (certdb, key); -#endif - - if (cert) - { - *length = cert->certKey.len; - - *result = (void *) PORT_ZAlloc (*length); - - if (*result) - PORT_Memcpy (*result, cert->certKey.data, *length); - else - return JAR_ERR_MEMORY; - } - JAR_close_database (certdb); - } - - return cert ? 0 : JAR_ERR_GENERAL; - } - - if (jar && jar->pkcs7 == 0) - return JAR_ERR_GENERAL; - - cert = jar_get_certificate (jar, keylen, key, &status); - - if (cert == NULL || status < 0) - return JAR_ERR_GENERAL; - -#define SEP " <br> " -#define SEPLEN (PORT_Strlen(SEP)) - - switch (attrib) - { - case jarCertCompany: - - ret = cert->subjectName; - - /* This is pretty ugly looking but only used - here for this one purpose. */ - - if (ret) - { - int retlen = 0; - - char *cer_ou1, *cer_ou2, *cer_ou3; - char *cer_cn, *cer_e, *cer_o, *cer_l; - - cer_cn = CERT_GetCommonName (&cert->subject); - cer_e = CERT_GetCertEmailAddress (&cert->subject); - cer_ou3 = jar_cert_element (ret, "OU=", 3); - cer_ou2 = jar_cert_element (ret, "OU=", 2); - cer_ou1 = jar_cert_element (ret, "OU=", 1); - cer_o = CERT_GetOrgName (&cert->subject); - cer_l = CERT_GetCountryName (&cert->subject); - - if (cer_cn) retlen += SEPLEN + PORT_Strlen (cer_cn); - if (cer_e) retlen += SEPLEN + PORT_Strlen (cer_e); - if (cer_ou1) retlen += SEPLEN + PORT_Strlen (cer_ou1); - if (cer_ou2) retlen += SEPLEN + PORT_Strlen (cer_ou2); - if (cer_ou3) retlen += SEPLEN + PORT_Strlen (cer_ou3); - if (cer_o) retlen += SEPLEN + PORT_Strlen (cer_o); - if (cer_l) retlen += SEPLEN + PORT_Strlen (cer_l); - - ret = (char *) PORT_ZAlloc (1 + retlen); - - if (cer_cn) { PORT_Strcpy (ret, cer_cn); PORT_Strcat (ret, SEP); } - if (cer_e) { PORT_Strcat (ret, cer_e); PORT_Strcat (ret, SEP); } - if (cer_ou1) { PORT_Strcat (ret, cer_ou1); PORT_Strcat (ret, SEP); } - if (cer_ou2) { PORT_Strcat (ret, cer_ou2); PORT_Strcat (ret, SEP); } - if (cer_ou3) { PORT_Strcat (ret, cer_ou3); PORT_Strcat (ret, SEP); } - if (cer_o) { PORT_Strcat (ret, cer_o); PORT_Strcat (ret, SEP); } - if (cer_l) PORT_Strcat (ret, cer_l); - - /* return here to avoid unsightly memory leak */ - - *result = ret; - *length = PORT_Strlen (ret); - - return 0; - } - break; - - case jarCertCA: - - ret = cert->issuerName; - - if (ret) - { - int retlen = 0; - - char *cer_ou1, *cer_ou2, *cer_ou3; - char *cer_cn, *cer_e, *cer_o, *cer_l; - - /* This is pretty ugly looking but only used - here for this one purpose. */ - - cer_cn = CERT_GetCommonName (&cert->issuer); - cer_e = CERT_GetCertEmailAddress (&cert->issuer); - cer_ou3 = jar_cert_element (ret, "OU=", 3); - cer_ou2 = jar_cert_element (ret, "OU=", 2); - cer_ou1 = jar_cert_element (ret, "OU=", 1); - cer_o = CERT_GetOrgName (&cert->issuer); - cer_l = CERT_GetCountryName (&cert->issuer); - - if (cer_cn) retlen += SEPLEN + PORT_Strlen (cer_cn); - if (cer_e) retlen += SEPLEN + PORT_Strlen (cer_e); - if (cer_ou1) retlen += SEPLEN + PORT_Strlen (cer_ou1); - if (cer_ou2) retlen += SEPLEN + PORT_Strlen (cer_ou2); - if (cer_ou3) retlen += SEPLEN + PORT_Strlen (cer_ou3); - if (cer_o) retlen += SEPLEN + PORT_Strlen (cer_o); - if (cer_l) retlen += SEPLEN + PORT_Strlen (cer_l); - - ret = (char *) PORT_ZAlloc (1 + retlen); - - if (cer_cn) { PORT_Strcpy (ret, cer_cn); PORT_Strcat (ret, SEP); } - if (cer_e) { PORT_Strcat (ret, cer_e); PORT_Strcat (ret, SEP); } - if (cer_ou1) { PORT_Strcat (ret, cer_ou1); PORT_Strcat (ret, SEP); } - if (cer_ou2) { PORT_Strcat (ret, cer_ou2); PORT_Strcat (ret, SEP); } - if (cer_ou3) { PORT_Strcat (ret, cer_ou3); PORT_Strcat (ret, SEP); } - if (cer_o) { PORT_Strcat (ret, cer_o); PORT_Strcat (ret, SEP); } - if (cer_l) PORT_Strcat (ret, cer_l); - - /* return here to avoid unsightly memory leak */ - - *result = ret; - *length = PORT_Strlen (ret); - - return 0; - } - - break; - - case jarCertSerial: - - ret = CERT_Hexify (&cert->serialNumber, 1); - break; - - case jarCertExpires: - - ret = DER_UTCDayToAscii (&cert->validity.notAfter); - break; - - case jarCertNickname: - - ret = jar_choose_nickname (cert); - break; - - case jarCertFinger: - - dig = JAR_calculate_digest - ((char *) cert->derCert.data, cert->derCert.len); - - if (dig) - { - hexme.len = sizeof (dig->md5); - hexme.data = dig->md5; - ret = CERT_Hexify (&hexme, 1); - } - break; - - default: - - return JAR_ERR_GENERAL; - } - - *result = ret ? PORT_Strdup (ret) : NULL; - *length = ret ? PORT_Strlen (ret) : 0; - - return 0; - } - -/* - * j a r _ c e r t _ e l e m e n t - * - * Retrieve an element from an x400ish ascii - * designator, in a hackish sort of way. The right - * thing would probably be to sort AVATags. - * - */ - -static char *jar_cert_element (char *name, char *tag, int occ) - { - if (name && tag) - { - char *s; - int found = 0; - - while (occ--) - { - if (PORT_Strstr (name, tag)) - { - name = PORT_Strstr (name, tag) + PORT_Strlen (tag); - found = 1; - } - else - { - name = PORT_Strstr (name, "="); - if (name == NULL) return NULL; - found = 0; - } - } - - if (!found) return NULL; - - /* must mangle only the copy */ - name = PORT_Strdup (name); - - /* advance to next equal */ - for (s = name; *s && *s != '='; s++) - /* yip */ ; - - /* back up to previous comma */ - while (s > name && *s != ',') s--; - - /* zap the whitespace and return */ - *s = 0; - } - - return name; - } - -/* - * j a r _ c h o o s e _ n i c k n a m e - * - * Attempt to determine a suitable nickname for - * a certificate with a computer-generated "tmpcertxxx" - * nickname. It needs to be something a user can - * understand, so try a few things. - * - */ - -static char *jar_choose_nickname (CERTCertificate *cert) - { - char *cert_cn; - char *cert_o; - char *cert_cn_o; - - int cn_o_length; - - /* is the existing name ok */ - - if (cert->nickname && PORT_Strncmp (cert->nickname, "tmpcert", 7)) - return PORT_Strdup (cert->nickname); - - /* we have an ugly name here people */ - - /* Try the CN */ - cert_cn = CERT_GetCommonName (&cert->subject); - - if (cert_cn) - { - /* check for duplicate nickname */ - -#ifdef USE_MOZ_THREAD - if (jar_moz_nickname (CERT_GetDefaultCertDB(), cert_cn) == NULL) -#else - if (CERT_FindCertByNickname (CERT_GetDefaultCertDB(), cert_cn) == NULL) -#endif - return cert_cn; - - /* Try the CN plus O */ - cert_o = CERT_GetOrgName (&cert->subject); - - cn_o_length = PORT_Strlen (cert_cn) + 3 + PORT_Strlen (cert_o) + 20; - cert_cn_o = (char*)PORT_ZAlloc (cn_o_length); - - PR_snprintf (cert_cn_o, cn_o_length, - "%s's %s Certificate", cert_cn, cert_o); - -#ifdef USE_MOZ_THREAD - if (jar_moz_nickname (CERT_GetDefaultCertDB(), cert_cn_o) == NULL) -#else - if (CERT_FindCertByNickname (CERT_GetDefaultCertDB(), cert_cn_o) == NULL) -#endif - return cert_cn; - } - - /* If all that failed, use the ugly nickname */ - return cert->nickname ? PORT_Strdup (cert->nickname) : NULL; - } - -/* - * J A R _ c e r t _ h t m l - * - * Return an HTML representation of the certificate - * designated by the given fingerprint, in specified style. - * - * JAR is optional, but supply it if you can in order - * to optimize. - * - */ - -char *JAR_cert_html - (JAR *jar, int style, long keylen, void *key, int *result) - { -#ifdef notdef - char *html; -#endif - CERTCertificate *cert; - - *result = -1; - - if (style != 0) - return NULL; - - cert = jar_get_certificate (jar, keylen, key, result); - - if (cert == NULL || *result < 0) - return NULL; - - *result = -1; - - return NULL; - -#ifdef notdef - html = CERT_HTMLCertInfo (cert, /* show images */ PR_TRUE, - /*show issuer*/PR_TRUE); - - if (html == NULL) - *result = -1; - - return html; -#endif - } - -/* - * J A R _ s t a s h _ c e r t - * - * Stash the certificate pointed to by this - * fingerprint, in persistent storage somewhere. - * - */ - -extern int PR_CALLBACK JAR_stash_cert - (JAR *jar, long keylen, void *key) - { - int result = 0; - - char *nickname; - CERTCertTrust trust; - - CERTCertDBHandle *certdb; - CERTCertificate *cert, *newcert; - - cert = jar_get_certificate (jar, keylen, key, &result); - - if (result < 0) - return result; - - if (cert == NULL) - return JAR_ERR_GENERAL; - - if ((certdb = JAR_open_database()) == NULL) - return JAR_ERR_GENERAL; - - /* Attempt to give a name to the newish certificate */ - nickname = jar_choose_nickname (cert); - -#ifdef USE_MOZ_THREAD - newcert = jar_moz_nickname (certdb, nickname); -#else - newcert = CERT_FindCertByNickname (certdb, nickname); -#endif - - if (newcert && newcert->isperm) - { - /* already in permanant database */ - return 0; - } - - if (newcert) cert = newcert; - - /* FIX, since FindCert returns a bogus dbhandle - set it ourselves */ - - cert->dbhandle = certdb; - -#if 0 - nickname = cert->subjectName; - if (nickname) - { - /* Not checking for a conflict here. But this should - be a new cert or it would have been found earlier. */ - - nickname = jar_cert_element (nickname, "CN=", 1); - - if (SEC_CertNicknameConflict (nickname, cert->dbhandle)) - { - /* conflict */ - nickname = PORT_Realloc (&nickname, PORT_Strlen (nickname) + 3); - - /* Beyond one copy, there are probably serious problems - so we will stop at two rather than counting.. */ - - PORT_Strcat (nickname, " #2"); - } - } -#endif - - if (nickname != NULL) - { - PORT_Memset ((void *) &trust, 0, sizeof(trust)); - -#ifdef USE_MOZ_THREAD - if (jar_moz_perm (cert, nickname, &trust) != SECSuccess) -#else - if (CERT_AddTempCertToPerm (cert, nickname, &trust) != SECSuccess) -#endif - { - /* XXX might want to call PORT_GetError here */ - result = JAR_ERR_GENERAL; - } - } - - JAR_close_database (certdb); - - return result; - } - -/* - * 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. - * - */ - -void *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]; - -#ifdef USE_MOZ_THREAD - cert = jar_moz_certkey (certdb, &issuerSN); -#else - cert = CERT_FindCertByIssuerAndSN (certdb, &issuerSN); -#endif - - JAR_close_database (certdb); - } - - return (void *) 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; - - 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) - { - SECItem detdig; - - SEC_PKCS7ContentInfo *cinfo = NULL; - SEC_PKCS7DecoderContext *dcx; - - int status = 0; - char *errstring = NULL; - - 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 */ - -#ifdef MOZILLA_CLIENT_OLD - if (jar->mw == NULL) { - JAR_set_context (jar, NULL); - } -#endif - - - 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; - -#ifdef USE_MOZ_THREAD - if (jar_moz_verify - (cinfo, certUsageObjectSigner, &detdig, HASH_AlgSHA1, PR_FALSE)== - SECSuccess) -#else - if (SEC_PKCS7VerifyDetachedSignature - (cinfo, certUsageObjectSigner, &detdig, HASH_AlgSHA1, PR_FALSE)== - PR_TRUE) -#endif - { - /* signature is valid */ - signer->valid = 0; - jar_gather_signers (jar, signer, cinfo); - } - else - { - status = PORT_GetError(); - - PORT_Assert( status < 0 ); - if (status >= 0) status = JAR_ERR_SIG; - - jar->valid = status; - signer->valid = status; - - errstring = JAR_get_error (status); - /*XP_TRACE(("JAR signature invalid (reason %d = %s)", status, errstring));*/ - } - - 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; - SEC_PKCS7SignerInfo **pksigners, *pksigner; - - sdp = cinfo->content.signedData; - - 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) - { - CERTCertDBHandle *certdb; - - certdb = CERT_GetDefaultCertDB(); - - return certdb; - } - -/* - * 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) - { -#ifdef notdef - CERTCertDBHandle *defaultdb; - - /* This really just retrieves the handle, nothing more */ - defaultdb = CERT_GetDefaultCertDB(); - - /* If there is no default db, it means we opened - the permanent database for some reason */ - - if (defaultdb == NULL && certdb != NULL) - CERT_ClosePermCertDB (certdb); -#endif - - return 0; - } - -/* - * j a r _ g e t _ c e r t i f i c a t e - * - * Return the certificate referenced - * by a given fingerprint, or NULL if not found. - * Error code is returned in result. - * - */ - -static CERTCertificate *jar_get_certificate - (JAR *jar, long keylen, void *key, int *result) - { - int found = 0; - - JAR_Item *it; - JAR_Cert *fing = NULL; - - JAR_Context *ctx; - - if (jar == NULL) - { - void *cert; - cert = JAR_fetch_cert (keylen, key); - *result = (cert == NULL) ? JAR_ERR_GENERAL : 0; - return (CERTCertificate *) cert; - } - - ctx = JAR_find (jar, NULL, jarTypeSign); - - while (JAR_find_next (ctx, &it) >= 0) - { - fing = (JAR_Cert *) it->data; - - if (keylen != fing->length) - continue; - - PORT_Assert( keylen < 0xFFFF ); - if (!PORT_Memcmp (fing->key, key, keylen)) - { - found = 1; - break; - } - } - - JAR_find_end (ctx); - - if (found == 0) - { - *result = JAR_ERR_GENERAL; - return NULL; - } - - PORT_Assert(fing != NULL); - *result = 0; - return fing->cert; - } - -/* - * 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; - - 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; - ZZLink *entity; - - it = (JAR_Item*)PORT_ZAlloc (sizeof (JAR_Item)); - - 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; - } - -/* - * W I N 1 6 s t u f f - * - * These functions possibly belong in xp_mem.c, they operate - * on huge string pointers for win16. - * - */ - -#if defined(XP_WIN16) -int xp_HUGE_STRNCASECMP (char ZHUGEP *buf, char *key, int len) - { - while (len--) - { - char c1, c2; - - c1 = *buf++; - c2 = *key++; - - if (c1 >= 'a' && c1 <= 'z') c1 -= ('a' - 'A'); - if (c2 >= 'a' && c2 <= 'z') c2 -= ('a' - 'A'); - - if (c1 != c2) - return (c1 < c2) ? -1 : 1; - } - return 0; - } - -size_t xp_HUGE_STRLEN (char ZHUGEP *s) - { - size_t len = 0L; - while (*s++) len++; - return len; - } - -char *xp_HUGE_STRCPY (char *to, char ZHUGEP *from) - { - char *ret = to; - - while (*from) - *to++ = *from++; - *to = 0; - - return ret; - } -#endif |