Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / jar / jarver.c
blobef7ebdd04297c9fa7e627a64263290fa07d10a5e
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 * JARVER
40 * Jarnature Parsing & Verification
43 #include "nssrenam.h"
44 #include "jar.h"
45 #include "jarint.h"
46 #include "certdb.h"
47 #include "certt.h"
48 #include "secpkcs7.h"
50 /*#include "cdbhdl.h" */
51 #include "secder.h"
53 /* to use huge pointers in win16 */
55 #if !defined(XP_WIN16)
56 #define xp_HUGE_MEMCPY PORT_Memcpy
57 #define xp_HUGE_STRCPY PORT_Strcpy
58 #define xp_HUGE_STRLEN PORT_Strlen
59 #define xp_HUGE_STRNCASECMP PORT_Strncasecmp
60 #else
61 #define xp_HUGE_MEMCPY hmemcpy
62 int xp_HUGE_STRNCASECMP (char ZHUGEP *buf, char *key, int len);
63 size_t xp_HUGE_STRLEN (char ZHUGEP *s);
64 char *xp_HUGE_STRCPY (char *to, char ZHUGEP *from);
65 #endif
67 /* from certdb.h */
68 #define CERTDB_USER (1<<6)
70 #define SZ 512
72 static int jar_validate_pkcs7
73 (JAR *jar, JAR_Signer *signer, char *data, long length);
75 static void jar_catch_bytes
76 (void *arg, const char *buf, unsigned long len);
78 static int jar_gather_signers
79 (JAR *jar, JAR_Signer *signer, SEC_PKCS7ContentInfo *cinfo);
81 static char ZHUGEP *jar_eat_line
82 (int lines, int eating, char ZHUGEP *data, long *len);
84 static JAR_Digest *jar_digest_section
85 (char ZHUGEP *manifest, long length);
87 static JAR_Digest *jar_get_mf_digest (JAR *jar, char *path);
89 static int jar_parse_digital_signature
90 (char *raw_manifest, JAR_Signer *signer, long length, JAR *jar);
92 static int jar_add_cert
93 (JAR *jar, JAR_Signer *signer, int type, CERTCertificate *cert);
95 static CERTCertificate *jar_get_certificate
96 (JAR *jar, long keylen, void *key, int *result);
98 static char *jar_cert_element (char *name, char *tag, int occ);
100 static char *jar_choose_nickname (CERTCertificate *cert);
102 static char *jar_basename (const char *path);
104 static int jar_signal
105 (int status, JAR *jar, const char *metafile, char *pathname);
107 #ifdef DEBUG
108 static int jar_insanity_check (char ZHUGEP *data, long length);
109 #endif
111 int jar_parse_mf
112 (JAR *jar, char ZHUGEP *raw_manifest,
113 long length, const char *path, const char *url);
115 int jar_parse_sf
116 (JAR *jar, char ZHUGEP *raw_manifest,
117 long length, const char *path, const char *url);
119 int jar_parse_sig
120 (JAR *jar, const char *path, char ZHUGEP *raw_manifest, long length);
122 int jar_parse_any
123 (JAR *jar, int type, JAR_Signer *signer, char ZHUGEP *raw_manifest,
124 long length, const char *path, const char *url);
126 static int jar_internal_digest
127 (JAR *jar, const char *path, char *x_name, JAR_Digest *dig);
130 * J A R _ p a r s e _ m a n i f e s t
132 * Pass manifest files to this function. They are
133 * decoded and placed into internal representations.
135 * Accepts both signature and manifest files. Use
136 * the same "jar" for both.
140 int JAR_parse_manifest
141 (JAR *jar, char ZHUGEP *raw_manifest,
142 long length, const char *path, const char *url)
144 int filename_free = 0;
146 #if defined(XP_WIN16)
147 PORT_Assert( !IsBadHugeReadPtr(raw_manifest, length) );
148 #endif
150 /* fill in the path, if supplied. This is a the location
151 of the jar file on disk, if known */
153 if (jar->filename == NULL && path)
155 jar->filename = PORT_Strdup (path);
156 if (jar->filename == NULL)
157 return JAR_ERR_MEMORY;
158 filename_free = 1;
161 /* fill in the URL, if supplied. This is the place
162 from which the jar file was retrieved. */
164 if (jar->url == NULL && url)
166 jar->url = PORT_Strdup (url);
167 if (jar->url == NULL)
169 if (filename_free)
171 PORT_Free (jar->filename);
173 return JAR_ERR_MEMORY;
177 /* Determine what kind of file this is from the META-INF
178 directory. It could be MF, SF, or a binary RSA/DSA file */
180 if (!xp_HUGE_STRNCASECMP (raw_manifest, "Manifest-Version:", 17))
182 return jar_parse_mf (jar, raw_manifest, length, path, url);
184 else if (!xp_HUGE_STRNCASECMP (raw_manifest, "Signature-Version:", 18))
186 return jar_parse_sf (jar, raw_manifest, length, path, url);
188 else
190 /* This is probably a binary signature */
191 return jar_parse_sig (jar, path, raw_manifest, length);
196 * j a r _ p a r s e _ s i g
198 * Pass some manner of RSA or DSA digital signature
199 * on, after checking to see if it comes at an appropriate state.
203 int jar_parse_sig
204 (JAR *jar, const char *path, char ZHUGEP *raw_manifest, long length)
206 JAR_Signer *signer;
207 int status = JAR_ERR_ORDER;
209 if (length <= 128)
211 /* signature is way too small */
212 return JAR_ERR_SIG;
215 /* make sure that MF and SF have already been processed */
217 if (jar->globalmeta == NULL)
218 return JAR_ERR_ORDER;
220 /* Determine whether or not this RSA file has
221 has an associated SF file */
223 if (path)
225 char *owner;
226 owner = jar_basename (path);
228 if (owner == NULL)
229 return JAR_ERR_MEMORY;
231 signer = jar_get_signer (jar, owner);
233 PORT_Free (owner);
235 else
236 signer = jar_get_signer (jar, "*");
238 if (signer == NULL)
239 return JAR_ERR_ORDER;
242 /* Do not pass a huge pointer to this function,
243 since the underlying security code is unaware. We will
244 never pass >64k through here. */
246 if (length > 64000)
248 /* this digital signature is way too big */
249 return JAR_ERR_SIG;
252 #ifdef XP_WIN16
254 * For Win16, copy the portion of the raw_buffer containing the digital
255 * signature into another buffer... This insures that the data will
256 * NOT cross a segment boundary. Therefore,
257 * jar_parse_digital_signature(...) does NOT need to deal with HUGE
258 * pointers...
262 unsigned char *manifest_copy;
264 manifest_copy = (unsigned char *) PORT_ZAlloc (length);
265 if (manifest_copy)
267 xp_HUGE_MEMCPY (manifest_copy, raw_manifest, length);
269 status = jar_parse_digital_signature
270 (manifest_copy, signer, length, jar);
272 PORT_Free (manifest_copy);
274 else
276 /* out of memory */
277 return JAR_ERR_MEMORY;
280 #else
281 /* don't expense unneeded calloc overhead on non-win16 */
282 status = jar_parse_digital_signature
283 (raw_manifest, signer, length, jar);
284 #endif
286 return status;
290 * j a r _ p a r s e _ m f
292 * Parse the META-INF/manifest.mf file, whose
293 * information applies to all signers.
297 int jar_parse_mf
298 (JAR *jar, char ZHUGEP *raw_manifest,
299 long length, const char *path, const char *url)
301 if (jar->globalmeta)
303 /* refuse a second manifest file, if passed for some reason */
304 return JAR_ERR_ORDER;
308 /* remember a digest for the global section */
310 jar->globalmeta = jar_digest_section (raw_manifest, length);
312 if (jar->globalmeta == NULL)
313 return JAR_ERR_MEMORY;
316 return jar_parse_any
317 (jar, jarTypeMF, NULL, raw_manifest, length, path, url);
321 * j a r _ p a r s e _ s f
323 * Parse META-INF/xxx.sf, a digitally signed file
324 * pointing to a subset of MF sections.
328 int jar_parse_sf
329 (JAR *jar, char ZHUGEP *raw_manifest,
330 long length, const char *path, const char *url)
332 JAR_Signer *signer = NULL;
333 int status = JAR_ERR_MEMORY;
335 if (jar->globalmeta == NULL)
337 /* It is a requirement that the MF file be passed before the SF file */
338 return JAR_ERR_ORDER;
341 signer = JAR_new_signer();
343 if (signer == NULL)
344 goto loser;
346 if (path)
348 signer->owner = jar_basename (path);
349 if (signer->owner == NULL)
350 goto loser;
354 /* check for priors. When someone doctors a jar file
355 to contain identical path entries, prevent the second
356 one from affecting JAR functions */
358 if (jar_get_signer (jar, signer->owner))
360 /* someone is trying to spoof us */
361 status = JAR_ERR_ORDER;
362 goto loser;
366 /* remember its digest */
368 signer->digest = JAR_calculate_digest (raw_manifest, length);
370 if (signer->digest == NULL)
371 goto loser;
373 /* Add this signer to the jar */
375 ADDITEM (jar->signers, jarTypeOwner,
376 signer->owner, signer, sizeof (JAR_Signer));
379 return jar_parse_any
380 (jar, jarTypeSF, signer, raw_manifest, length, path, url);
382 loser:
384 if (signer)
385 JAR_destroy_signer (signer);
387 return status;
391 * j a r _ p a r s e _ a n y
393 * Parse a MF or SF manifest file.
397 int jar_parse_any
398 (JAR *jar, int type, JAR_Signer *signer, char ZHUGEP *raw_manifest,
399 long length, const char *path, const char *url)
401 int status;
403 long raw_len;
405 JAR_Digest *dig, *mfdig = NULL;
407 char line [SZ];
408 char x_name [SZ], x_md5 [SZ], x_sha [SZ];
410 char *x_info;
412 char *sf_md5 = NULL, *sf_sha1 = NULL;
414 *x_name = 0;
415 *x_md5 = 0;
416 *x_sha = 0;
418 PORT_Assert( length > 0 );
419 raw_len = length;
421 #ifdef DEBUG
422 if ((status = jar_insanity_check (raw_manifest, raw_len)) < 0)
423 return status;
424 #endif
427 /* null terminate the first line */
428 raw_manifest = jar_eat_line (0, PR_TRUE, raw_manifest, &raw_len);
431 /* skip over the preliminary section */
432 /* This is one section at the top of the file with global metainfo */
434 while (raw_len)
436 JAR_Metainfo *met;
438 raw_manifest = jar_eat_line (1, PR_TRUE, raw_manifest, &raw_len);
439 if (!*raw_manifest) break;
441 met = (JAR_Metainfo*)PORT_ZAlloc (sizeof (JAR_Metainfo));
442 if (met == NULL)
443 return JAR_ERR_MEMORY;
445 /* Parse out the header & info */
447 if (xp_HUGE_STRLEN (raw_manifest) >= SZ)
449 /* almost certainly nonsense */
450 PORT_Free (met);
451 continue;
454 xp_HUGE_STRCPY (line, raw_manifest);
455 x_info = line;
457 while (*x_info && *x_info != ' ' && *x_info != '\t' && *x_info != ':')
458 x_info++;
460 if (*x_info) *x_info++ = 0;
462 while (*x_info == ' ' || *x_info == '\t')
463 x_info++;
465 /* metainfo (name, value) pair is now (line, x_info) */
467 met->header = PORT_Strdup (line);
468 met->info = PORT_Strdup (x_info);
470 if (type == jarTypeMF)
472 ADDITEM (jar->metainfo, jarTypeMeta,
473 /* pathname */ NULL, met, sizeof (JAR_Metainfo));
476 /* For SF files, this metadata may be the digests
477 of the MF file, still in the "met" structure. */
479 if (type == jarTypeSF)
481 if (!PORT_Strcasecmp (line, "MD5-Digest"))
482 sf_md5 = (char *) met->info;
484 if (!PORT_Strcasecmp (line, "SHA1-Digest") || !PORT_Strcasecmp (line, "SHA-Digest"))
485 sf_sha1 = (char *) met->info;
488 if (type != jarTypeMF)
490 PORT_Free (met->header);
491 if (type != jarTypeSF)
493 PORT_Free (met->info);
495 PORT_Free (met);
499 if (type == jarTypeSF && jar->globalmeta)
501 /* this is a SF file which may contain a digest of the manifest.mf's
502 global metainfo. */
504 int match = 0;
505 JAR_Digest *glob = jar->globalmeta;
507 if (sf_md5)
509 unsigned int md5_length;
510 unsigned char *md5_digest;
512 md5_digest = ATOB_AsciiToData (sf_md5, &md5_length);
513 PORT_Assert( md5_length == MD5_LENGTH );
515 if (md5_length != MD5_LENGTH)
516 return JAR_ERR_CORRUPT;
518 match = PORT_Memcmp (md5_digest, glob->md5, MD5_LENGTH);
521 if (sf_sha1 && match == 0)
523 unsigned int sha1_length;
524 unsigned char *sha1_digest;
526 sha1_digest = ATOB_AsciiToData (sf_sha1, &sha1_length);
527 PORT_Assert( sha1_length == SHA1_LENGTH );
529 if (sha1_length != SHA1_LENGTH)
530 return JAR_ERR_CORRUPT;
532 match = PORT_Memcmp (sha1_digest, glob->sha1, SHA1_LENGTH);
535 if (match != 0)
537 /* global digest doesn't match, SF file therefore invalid */
538 jar->valid = JAR_ERR_METADATA;
539 return JAR_ERR_METADATA;
543 /* done with top section of global data */
546 while (raw_len)
548 *x_md5 = 0;
549 *x_sha = 0;
550 *x_name = 0;
553 /* If this is a manifest file, attempt to get a digest of the following section,
554 without damaging it. This digest will be saved later. */
556 if (type == jarTypeMF)
558 char ZHUGEP *sec;
559 long sec_len = raw_len;
561 if (!*raw_manifest || *raw_manifest == '\n')
563 /* skip the blank line */
564 sec = jar_eat_line (1, PR_FALSE, raw_manifest, &sec_len);
566 else
567 sec = raw_manifest;
569 if (!xp_HUGE_STRNCASECMP (sec, "Name:", 5))
571 if (type == jarTypeMF)
572 mfdig = jar_digest_section (sec, sec_len);
573 else
574 mfdig = NULL;
579 while (raw_len)
581 raw_manifest = jar_eat_line (1, PR_TRUE, raw_manifest, &raw_len);
582 if (!*raw_manifest) break; /* blank line, done with this entry */
584 if (xp_HUGE_STRLEN (raw_manifest) >= SZ)
586 /* almost certainly nonsense */
587 continue;
591 /* Parse out the name/value pair */
593 xp_HUGE_STRCPY (line, raw_manifest);
594 x_info = line;
596 while (*x_info && *x_info != ' ' && *x_info != '\t' && *x_info != ':')
597 x_info++;
599 if (*x_info) *x_info++ = 0;
601 while (*x_info == ' ' || *x_info == '\t')
602 x_info++;
605 if (!PORT_Strcasecmp (line, "Name"))
606 PORT_Strcpy (x_name, x_info);
608 else if (!PORT_Strcasecmp (line, "MD5-Digest"))
609 PORT_Strcpy (x_md5, x_info);
611 else if (!PORT_Strcasecmp (line, "SHA1-Digest")
612 || !PORT_Strcasecmp (line, "SHA-Digest"))
614 PORT_Strcpy (x_sha, x_info);
617 /* Algorithm list is meta info we don't care about; keeping it out
618 of metadata saves significant space for large jar files */
620 else if (!PORT_Strcasecmp (line, "Digest-Algorithms")
621 || !PORT_Strcasecmp (line, "Hash-Algorithms"))
623 continue;
626 /* Meta info is only collected for the manifest.mf file,
627 since the JAR_get_metainfo call does not support identity */
629 else if (type == jarTypeMF)
631 JAR_Metainfo *met;
633 /* this is meta-data */
635 met = (JAR_Metainfo*)PORT_ZAlloc (sizeof (JAR_Metainfo));
637 if (met == NULL)
638 return JAR_ERR_MEMORY;
640 /* metainfo (name, value) pair is now (line, x_info) */
642 if ((met->header = PORT_Strdup (line)) == NULL)
644 PORT_Free (met);
645 return JAR_ERR_MEMORY;
648 if ((met->info = PORT_Strdup (x_info)) == NULL)
650 PORT_Free (met->header);
651 PORT_Free (met);
652 return JAR_ERR_MEMORY;
655 ADDITEM (jar->metainfo, jarTypeMeta,
656 x_name, met, sizeof (JAR_Metainfo));
660 if(!x_name || !*x_name) {
661 /* Whatever that was, it wasn't an entry, because we didn't get a name.
662 * We don't really have anything, so don't record this. */
663 continue;
666 dig = (JAR_Digest*)PORT_ZAlloc (sizeof (JAR_Digest));
667 if (dig == NULL)
668 return JAR_ERR_MEMORY;
670 if (*x_md5 )
672 unsigned int binary_length;
673 unsigned char *binary_digest;
675 binary_digest = ATOB_AsciiToData (x_md5, &binary_length);
676 PORT_Assert( binary_length == MD5_LENGTH );
678 if (binary_length != MD5_LENGTH)
680 PORT_Free (dig);
681 return JAR_ERR_CORRUPT;
684 memcpy (dig->md5, binary_digest, MD5_LENGTH);
685 dig->md5_status = jarHashPresent;
688 if (*x_sha )
690 unsigned int binary_length;
691 unsigned char *binary_digest;
693 binary_digest = ATOB_AsciiToData (x_sha, &binary_length);
694 PORT_Assert( binary_length == SHA1_LENGTH );
696 if (binary_length != SHA1_LENGTH)
698 PORT_Free (dig);
699 return JAR_ERR_CORRUPT;
702 memcpy (dig->sha1, binary_digest, SHA1_LENGTH);
703 dig->sha1_status = jarHashPresent;
706 PORT_Assert( type == jarTypeMF || type == jarTypeSF );
709 if (type == jarTypeMF)
711 ADDITEM (jar->hashes, jarTypeMF, x_name, dig, sizeof (JAR_Digest));
713 else if (type == jarTypeSF)
715 ADDITEM (signer->sf, jarTypeSF, x_name, dig, sizeof (JAR_Digest));
717 else
719 PORT_Free (dig);
720 return JAR_ERR_ORDER;
723 /* we're placing these calculated digests of manifest.mf
724 sections in a list where they can subsequently be forgotten */
726 if (type == jarTypeMF && mfdig)
728 ADDITEM (jar->manifest, jarTypeSect,
729 x_name, mfdig, sizeof (JAR_Digest));
731 mfdig = NULL;
735 /* Retrieve our saved SHA1 digest from saved copy and check digests.
736 This is just comparing the digest of the MF section as indicated in
737 the SF file with the one we remembered from parsing the MF file */
739 if (type == jarTypeSF)
741 if ((status = jar_internal_digest (jar, path, x_name, dig)) < 0)
742 return status;
746 return 0;
749 static int jar_internal_digest
750 (JAR *jar, const char *path, char *x_name, JAR_Digest *dig)
752 int cv;
753 int status;
755 JAR_Digest *savdig;
757 savdig = jar_get_mf_digest (jar, x_name);
759 if (savdig == NULL)
761 /* no .mf digest for this pathname */
762 status = jar_signal (JAR_ERR_ENTRY, jar, path, x_name);
763 if (status < 0)
764 return 0; /* was continue; */
765 else
766 return status;
769 /* check for md5 consistency */
770 if (dig->md5_status)
772 cv = PORT_Memcmp (savdig->md5, dig->md5, MD5_LENGTH);
773 /* md5 hash of .mf file is not what expected */
774 if (cv)
776 status = jar_signal (JAR_ERR_HASH, jar, path, x_name);
778 /* bad hash, man */
780 dig->md5_status = jarHashBad;
781 savdig->md5_status = jarHashBad;
783 if (status < 0)
784 return 0; /* was continue; */
785 else
786 return status;
790 /* check for sha1 consistency */
791 if (dig->sha1_status)
793 cv = PORT_Memcmp (savdig->sha1, dig->sha1, SHA1_LENGTH);
794 /* sha1 hash of .mf file is not what expected */
795 if (cv)
797 status = jar_signal (JAR_ERR_HASH, jar, path, x_name);
799 /* bad hash, man */
801 dig->sha1_status = jarHashBad;
802 savdig->sha1_status = jarHashBad;
804 if (status < 0)
805 return 0; /* was continue; */
806 else
807 return status;
810 return 0;
813 #ifdef DEBUG
815 * j a r _ i n s a n i t y _ c h e c k
817 * Check for illegal characters (or possibly so)
818 * in the manifest files, to detect potential memory
819 * corruption by our neighbors. Debug only, since
820 * not I18N safe.
824 static int jar_insanity_check (char ZHUGEP *data, long length)
826 int c;
827 long off;
829 for (off = 0; off < length; off++)
831 c = data [off];
833 if (c == '\n' || c == '\r' || (c >= ' ' && c <= 128))
834 continue;
836 return JAR_ERR_CORRUPT;
839 return 0;
841 #endif
844 * j a r _ p a r s e _ d i g i t a l _ s i g n a t u r e
846 * Parse an RSA or DSA (or perhaps other) digital signature.
847 * Right now everything is PKCS7.
851 static int jar_parse_digital_signature
852 (char *raw_manifest, JAR_Signer *signer, long length, JAR *jar)
854 #if defined(XP_WIN16)
855 PORT_Assert( LOWORD(raw_manifest) + length < 0xFFFF );
856 #endif
857 return jar_validate_pkcs7 (jar, signer, raw_manifest, length);
861 * j a r _ a d d _ c e r t
863 * Add information for the given certificate
864 * (or whatever) to the JAR linked list. A pointer
865 * is passed for some relevant reference, say
866 * for example the original certificate.
870 static int jar_add_cert
871 (JAR *jar, JAR_Signer *signer, int type, CERTCertificate *cert)
873 JAR_Cert *fing;
874 unsigned char *keyData;
876 if (cert == NULL)
877 return JAR_ERR_ORDER;
879 fing = (JAR_Cert*)PORT_ZAlloc (sizeof (JAR_Cert));
881 if (fing == NULL)
882 goto loser;
884 fing->cert = CERT_DupCertificate (cert);
886 /* get the certkey */
888 fing->length = cert->derIssuer.len + 2 + cert->serialNumber.len;
890 keyData = (unsigned char *) PORT_ZAlloc (fing->length);
891 fing->key = keyData;
893 if (fing->key == NULL)
894 goto loser;
895 keyData[0] = ((cert->derIssuer.len) >> 8) & 0xff;
896 keyData[1] = ((cert->derIssuer.len) & 0xff);
897 PORT_Memcpy (&keyData[2], cert->derIssuer.data, cert->derIssuer.len);
898 PORT_Memcpy (&keyData[2+cert->derIssuer.len], cert->serialNumber.data,
899 cert->serialNumber.len);
901 ADDITEM (signer->certs, type,
902 /* pathname */ NULL, fing, sizeof (JAR_Cert));
904 return 0;
906 loser:
908 if (fing)
910 if (fing->cert)
911 CERT_DestroyCertificate (fing->cert);
913 PORT_Free (fing);
916 return JAR_ERR_MEMORY;
920 * e a t _ l i n e
922 * Consume an ascii line from the top of a file kept
923 * in memory. This destroys the file in place. This function
924 * handles PC, Mac, and Unix style text files.
928 static char ZHUGEP *jar_eat_line
929 (int lines, int eating, char ZHUGEP *data, long *len)
931 char ZHUGEP *ret;
933 ret = data;
934 if (!*len) return ret;
936 /* Eat the requisite number of lines, if any;
937 prior to terminating the current line with a 0. */
939 for (/* yip */ ; lines; lines--)
941 while (*data && *data != '\n')
942 data++;
944 /* After the CR, ok to eat one LF */
946 if (*data == '\n')
947 data++;
949 /* If there are zeros, we put them there */
951 while (*data == 0 && data - ret < *len)
952 data++;
955 *len -= data - ret;
956 ret = data;
958 if (eating)
960 /* Terminate this line with a 0 */
962 while (*data && *data != '\n' && *data != '\r')
963 data++;
965 /* In any case we are allowed to eat CR */
967 if (*data == '\r')
968 *data++ = 0;
970 /* After the CR, ok to eat one LF */
972 if (*data == '\n')
973 *data++ = 0;
976 return ret;
980 * j a r _ d i g e s t _ s e c t i o n
982 * Return the digests of the next section of the manifest file.
983 * Does not damage the manifest file, unlike parse_manifest.
987 static JAR_Digest *jar_digest_section
988 (char ZHUGEP *manifest, long length)
990 long global_len;
991 char ZHUGEP *global_end;
993 global_end = manifest;
994 global_len = length;
996 while (global_len)
998 global_end = jar_eat_line (1, PR_FALSE, global_end, &global_len);
999 if (*global_end == 0 || *global_end == '\n')
1000 break;
1003 return JAR_calculate_digest (manifest, global_end - manifest);
1007 * J A R _ v e r i f y _ d i g e s t
1009 * Verifies that a precalculated digest matches the
1010 * expected value in the manifest.
1014 int PR_CALLBACK JAR_verify_digest
1015 (JAR *jar, const char *name, JAR_Digest *dig)
1017 JAR_Item *it;
1019 JAR_Digest *shindig;
1021 ZZLink *link;
1022 ZZList *list;
1024 int result1, result2;
1026 list = jar->hashes;
1028 result1 = result2 = 0;
1030 if (jar->valid < 0)
1032 /* signature not valid */
1033 return JAR_ERR_SIG;
1036 if (ZZ_ListEmpty (list))
1038 /* empty list */
1039 return JAR_ERR_PNF;
1042 for (link = ZZ_ListHead (list);
1043 !ZZ_ListIterDone (list, link);
1044 link = link->next)
1046 it = link->thing;
1047 if (it->type == jarTypeMF
1048 && it->pathname && !PORT_Strcmp (it->pathname, name))
1050 shindig = (JAR_Digest *) it->data;
1052 if (shindig->md5_status)
1054 if (shindig->md5_status == jarHashBad)
1055 return JAR_ERR_HASH;
1056 else
1057 result1 = memcmp (dig->md5, shindig->md5, MD5_LENGTH);
1060 if (shindig->sha1_status)
1062 if (shindig->sha1_status == jarHashBad)
1063 return JAR_ERR_HASH;
1064 else
1065 result2 = memcmp (dig->sha1, shindig->sha1, SHA1_LENGTH);
1068 return (result1 == 0 && result2 == 0) ? 0 : JAR_ERR_HASH;
1072 return JAR_ERR_PNF;
1076 * J A R _ c e r t _ a t t r i b u t e
1078 * Return the named certificate attribute from the
1079 * certificate specified by the given key.
1083 int PR_CALLBACK JAR_cert_attribute
1084 (JAR *jar, jarCert attrib, long keylen, void *key,
1085 void **result, unsigned long *length)
1087 int status = 0;
1088 char *ret = NULL;
1090 CERTCertificate *cert;
1092 CERTCertDBHandle *certdb;
1094 JAR_Digest *dig;
1095 SECItem hexme;
1097 *length = 0;
1099 if (attrib == 0 || key == 0)
1100 return JAR_ERR_GENERAL;
1102 if (attrib == jarCertJavaHack)
1104 cert = (CERTCertificate *) NULL;
1105 certdb = JAR_open_database();
1107 if (certdb)
1109 cert = CERT_FindCertByNickname (certdb, key);
1111 if (cert)
1113 *length = cert->certKey.len;
1115 *result = (void *) PORT_ZAlloc (*length);
1117 if (*result)
1118 PORT_Memcpy (*result, cert->certKey.data, *length);
1119 else
1121 JAR_close_database (certdb);
1122 return JAR_ERR_MEMORY;
1125 JAR_close_database (certdb);
1128 return cert ? 0 : JAR_ERR_GENERAL;
1131 if (jar && jar->pkcs7 == 0)
1132 return JAR_ERR_GENERAL;
1134 cert = jar_get_certificate (jar, keylen, key, &status);
1136 if (cert == NULL || status < 0)
1137 return JAR_ERR_GENERAL;
1139 #define SEP " <br> "
1140 #define SEPLEN (PORT_Strlen(SEP))
1142 switch (attrib)
1144 case jarCertCompany:
1146 ret = cert->subjectName;
1148 /* This is pretty ugly looking but only used
1149 here for this one purpose. */
1151 if (ret)
1153 int retlen = 0;
1155 char *cer_ou1, *cer_ou2, *cer_ou3;
1156 char *cer_cn, *cer_e, *cer_o, *cer_l;
1158 cer_cn = CERT_GetCommonName (&cert->subject);
1159 cer_e = CERT_GetCertEmailAddress (&cert->subject);
1160 cer_ou3 = jar_cert_element (ret, "OU=", 3);
1161 cer_ou2 = jar_cert_element (ret, "OU=", 2);
1162 cer_ou1 = jar_cert_element (ret, "OU=", 1);
1163 cer_o = CERT_GetOrgName (&cert->subject);
1164 cer_l = CERT_GetCountryName (&cert->subject);
1166 if (cer_cn) retlen += SEPLEN + PORT_Strlen (cer_cn);
1167 if (cer_e) retlen += SEPLEN + PORT_Strlen (cer_e);
1168 if (cer_ou1) retlen += SEPLEN + PORT_Strlen (cer_ou1);
1169 if (cer_ou2) retlen += SEPLEN + PORT_Strlen (cer_ou2);
1170 if (cer_ou3) retlen += SEPLEN + PORT_Strlen (cer_ou3);
1171 if (cer_o) retlen += SEPLEN + PORT_Strlen (cer_o);
1172 if (cer_l) retlen += SEPLEN + PORT_Strlen (cer_l);
1174 ret = (char *) PORT_ZAlloc (1 + retlen);
1176 if (cer_cn) { PORT_Strcpy (ret, cer_cn); PORT_Strcat (ret, SEP); }
1177 if (cer_e) { PORT_Strcat (ret, cer_e); PORT_Strcat (ret, SEP); }
1178 if (cer_ou1) { PORT_Strcat (ret, cer_ou1); PORT_Strcat (ret, SEP); }
1179 if (cer_ou2) { PORT_Strcat (ret, cer_ou2); PORT_Strcat (ret, SEP); }
1180 if (cer_ou3) { PORT_Strcat (ret, cer_ou3); PORT_Strcat (ret, SEP); }
1181 if (cer_o) { PORT_Strcat (ret, cer_o); PORT_Strcat (ret, SEP); }
1182 if (cer_l) PORT_Strcat (ret, cer_l);
1184 /* return here to avoid unsightly memory leak */
1186 *result = ret;
1187 *length = PORT_Strlen (ret);
1189 return 0;
1191 break;
1193 case jarCertCA:
1195 ret = cert->issuerName;
1197 if (ret)
1199 int retlen = 0;
1201 char *cer_ou1, *cer_ou2, *cer_ou3;
1202 char *cer_cn, *cer_e, *cer_o, *cer_l;
1204 /* This is pretty ugly looking but only used
1205 here for this one purpose. */
1207 cer_cn = CERT_GetCommonName (&cert->issuer);
1208 cer_e = CERT_GetCertEmailAddress (&cert->issuer);
1209 cer_ou3 = jar_cert_element (ret, "OU=", 3);
1210 cer_ou2 = jar_cert_element (ret, "OU=", 2);
1211 cer_ou1 = jar_cert_element (ret, "OU=", 1);
1212 cer_o = CERT_GetOrgName (&cert->issuer);
1213 cer_l = CERT_GetCountryName (&cert->issuer);
1215 if (cer_cn) retlen += SEPLEN + PORT_Strlen (cer_cn);
1216 if (cer_e) retlen += SEPLEN + PORT_Strlen (cer_e);
1217 if (cer_ou1) retlen += SEPLEN + PORT_Strlen (cer_ou1);
1218 if (cer_ou2) retlen += SEPLEN + PORT_Strlen (cer_ou2);
1219 if (cer_ou3) retlen += SEPLEN + PORT_Strlen (cer_ou3);
1220 if (cer_o) retlen += SEPLEN + PORT_Strlen (cer_o);
1221 if (cer_l) retlen += SEPLEN + PORT_Strlen (cer_l);
1223 ret = (char *) PORT_ZAlloc (1 + retlen);
1225 if (cer_cn) { PORT_Strcpy (ret, cer_cn); PORT_Strcat (ret, SEP); }
1226 if (cer_e) { PORT_Strcat (ret, cer_e); PORT_Strcat (ret, SEP); }
1227 if (cer_ou1) { PORT_Strcat (ret, cer_ou1); PORT_Strcat (ret, SEP); }
1228 if (cer_ou2) { PORT_Strcat (ret, cer_ou2); PORT_Strcat (ret, SEP); }
1229 if (cer_ou3) { PORT_Strcat (ret, cer_ou3); PORT_Strcat (ret, SEP); }
1230 if (cer_o) { PORT_Strcat (ret, cer_o); PORT_Strcat (ret, SEP); }
1231 if (cer_l) PORT_Strcat (ret, cer_l);
1233 /* return here to avoid unsightly memory leak */
1235 *result = ret;
1236 *length = PORT_Strlen (ret);
1238 return 0;
1241 break;
1243 case jarCertSerial:
1245 ret = CERT_Hexify (&cert->serialNumber, 1);
1246 break;
1248 case jarCertExpires:
1250 ret = DER_UTCDayToAscii (&cert->validity.notAfter);
1251 break;
1253 case jarCertNickname:
1255 ret = jar_choose_nickname (cert);
1256 break;
1258 case jarCertFinger:
1260 dig = JAR_calculate_digest
1261 ((char *) cert->derCert.data, cert->derCert.len);
1263 if (dig)
1265 hexme.len = sizeof (dig->md5);
1266 hexme.data = dig->md5;
1267 ret = CERT_Hexify (&hexme, 1);
1269 break;
1271 default:
1273 return JAR_ERR_GENERAL;
1276 *result = ret ? PORT_Strdup (ret) : NULL;
1277 *length = ret ? PORT_Strlen (ret) : 0;
1279 return 0;
1283 * j a r _ c e r t _ e l e m e n t
1285 * Retrieve an element from an x400ish ascii
1286 * designator, in a hackish sort of way. The right
1287 * thing would probably be to sort AVATags.
1291 static char *jar_cert_element (char *name, char *tag, int occ)
1293 if (name && tag)
1295 char *s;
1296 int found = 0;
1298 while (occ--)
1300 if (PORT_Strstr (name, tag))
1302 name = PORT_Strstr (name, tag) + PORT_Strlen (tag);
1303 found = 1;
1305 else
1307 name = PORT_Strstr (name, "=");
1308 if (name == NULL) return NULL;
1309 found = 0;
1313 if (!found) return NULL;
1315 /* must mangle only the copy */
1316 name = PORT_Strdup (name);
1318 /* advance to next equal */
1319 for (s = name; *s && *s != '='; s++)
1320 /* yip */ ;
1322 /* back up to previous comma */
1323 while (s > name && *s != ',') s--;
1325 /* zap the whitespace and return */
1326 *s = 0;
1329 return name;
1333 * j a r _ c h o o s e _ n i c k n a m e
1335 * Attempt to determine a suitable nickname for
1336 * a certificate with a computer-generated "tmpcertxxx"
1337 * nickname. It needs to be something a user can
1338 * understand, so try a few things.
1342 static char *jar_choose_nickname (CERTCertificate *cert)
1344 char *cert_cn;
1345 char *cert_o;
1346 char *cert_cn_o;
1348 int cn_o_length;
1350 /* is the existing name ok */
1352 if (cert->nickname && PORT_Strncmp (cert->nickname, "tmpcert", 7))
1353 return PORT_Strdup (cert->nickname);
1355 /* we have an ugly name here people */
1357 /* Try the CN */
1358 cert_cn = CERT_GetCommonName (&cert->subject);
1360 if (cert_cn)
1362 /* check for duplicate nickname */
1364 if (CERT_FindCertByNickname (CERT_GetDefaultCertDB(), cert_cn) == NULL)
1365 return cert_cn;
1367 /* Try the CN plus O */
1368 cert_o = CERT_GetOrgName (&cert->subject);
1370 cn_o_length = PORT_Strlen (cert_cn) + 3 + PORT_Strlen (cert_o) + 20;
1371 cert_cn_o = (char*)PORT_ZAlloc (cn_o_length);
1373 PR_snprintf (cert_cn_o, cn_o_length,
1374 "%s's %s Certificate", cert_cn, cert_o);
1376 if (CERT_FindCertByNickname (CERT_GetDefaultCertDB(), cert_cn_o) == NULL)
1378 PORT_Free (cert_cn_o);
1379 return cert_cn;
1381 PORT_Free (cert_cn_o);
1384 /* If all that failed, use the ugly nickname */
1385 return cert->nickname ? PORT_Strdup (cert->nickname) : NULL;
1389 * J A R _ c e r t _ h t m l
1391 * Return an HTML representation of the certificate
1392 * designated by the given fingerprint, in specified style.
1394 * JAR is optional, but supply it if you can in order
1395 * to optimize.
1399 char *JAR_cert_html
1400 (JAR *jar, int style, long keylen, void *key, int *result)
1402 CERTCertificate *cert;
1404 *result = -1;
1406 if (style != 0)
1407 return NULL;
1409 cert = jar_get_certificate (jar, keylen, key, result);
1411 if (cert == NULL || *result < 0)
1412 return NULL;
1414 *result = -1;
1416 return NULL;
1420 * J A R _ s t a s h _ c e r t
1422 * Stash the certificate pointed to by this
1423 * fingerprint, in persistent storage somewhere.
1427 extern int PR_CALLBACK JAR_stash_cert
1428 (JAR *jar, long keylen, void *key)
1430 int result = 0;
1432 char *nickname;
1433 CERTCertTrust trust;
1435 CERTCertDBHandle *certdb;
1436 CERTCertificate *cert, *newcert;
1438 cert = jar_get_certificate (jar, keylen, key, &result);
1440 if (result < 0)
1441 return result;
1443 if (cert == NULL)
1444 return JAR_ERR_GENERAL;
1446 if ((certdb = JAR_open_database()) == NULL)
1447 return JAR_ERR_GENERAL;
1449 /* Attempt to give a name to the newish certificate */
1450 nickname = jar_choose_nickname (cert);
1452 newcert = CERT_FindCertByNickname (certdb, nickname);
1454 if (newcert && newcert->isperm)
1456 /* already in permanant database */
1457 JAR_close_database (certdb);
1458 return 0;
1461 if (newcert) cert = newcert;
1463 /* FIX, since FindCert returns a bogus dbhandle
1464 set it ourselves */
1466 cert->dbhandle = certdb;
1468 if (nickname != NULL)
1470 PORT_Memset ((void *) &trust, 0, sizeof(trust));
1472 if (CERT_AddTempCertToPerm (cert, nickname, &trust) != SECSuccess)
1474 /* XXX might want to call PORT_GetError here */
1475 result = JAR_ERR_GENERAL;
1479 JAR_close_database (certdb);
1481 return result;
1485 * J A R _ f e t c h _ c e r t
1487 * Given an opaque identifier of a certificate,
1488 * return the full certificate.
1490 * The new function, which retrieves by key.
1494 void *JAR_fetch_cert (long length, void *key)
1496 CERTIssuerAndSN issuerSN;
1497 CERTCertificate *cert = NULL;
1499 CERTCertDBHandle *certdb;
1501 certdb = JAR_open_database();
1503 if (certdb)
1505 unsigned char *keyData = (unsigned char *)key;
1506 issuerSN.derIssuer.len = (keyData[0] << 8) + keyData[0];
1507 issuerSN.derIssuer.data = &keyData[2];
1508 issuerSN.serialNumber.len = length - (2 + issuerSN.derIssuer.len);
1509 issuerSN.serialNumber.data = &keyData[2+issuerSN.derIssuer.len];
1511 cert = CERT_FindCertByIssuerAndSN (certdb, &issuerSN);
1513 JAR_close_database (certdb);
1516 return (void *) cert;
1520 * j a r _ g e t _ m f _ d i g e s t
1522 * Retrieve a corresponding saved digest over a section
1523 * of the main manifest file.
1527 static JAR_Digest *jar_get_mf_digest (JAR *jar, char *pathname)
1529 JAR_Item *it;
1531 JAR_Digest *dig;
1533 ZZLink *link;
1534 ZZList *list;
1536 list = jar->manifest;
1538 if (ZZ_ListEmpty (list))
1539 return NULL;
1541 for (link = ZZ_ListHead (list);
1542 !ZZ_ListIterDone (list, link);
1543 link = link->next)
1545 it = link->thing;
1546 if (it->type == jarTypeSect
1547 && it->pathname && !PORT_Strcmp (it->pathname, pathname))
1549 dig = (JAR_Digest *) it->data;
1550 return dig;
1554 return NULL;
1558 * j a r _ b a s e n a m e
1560 * Return the basename -- leading components of path stripped off,
1561 * extension ripped off -- of a path.
1565 static char *jar_basename (const char *path)
1567 char *pith, *e, *basename, *ext;
1569 if (path == NULL)
1570 return PORT_Strdup ("");
1572 pith = PORT_Strdup (path);
1574 basename = pith;
1576 while (1)
1578 for (e = basename; *e && *e != '/' && *e != '\\'; e++)
1579 /* yip */ ;
1580 if (*e)
1581 basename = ++e;
1582 else
1583 break;
1586 if ((ext = PORT_Strrchr (basename, '.')) != NULL)
1587 *ext = 0;
1589 /* We already have the space allocated */
1590 PORT_Strcpy (pith, basename);
1592 return pith;
1596 * + + + + + + + + + + + + + + +
1598 * CRYPTO ROUTINES FOR JAR
1600 * The following functions are the cryptographic
1601 * interface to PKCS7 for Jarnatures.
1603 * + + + + + + + + + + + + + + +
1608 * j a r _ c a t c h _ b y t e s
1610 * In the event signatures contain enveloped data, it will show up here.
1611 * But note that the lib/pkcs7 routines aren't ready for it.
1615 static void jar_catch_bytes
1616 (void *arg, const char *buf, unsigned long len)
1618 /* Actually this should never be called, since there is
1619 presumably no data in the signature itself. */
1623 * j a r _ v a l i d a t e _ p k c s 7
1625 * Validate (and decode, if necessary) a binary pkcs7
1626 * signature in DER format.
1630 static int jar_validate_pkcs7
1631 (JAR *jar, JAR_Signer *signer, char *data, long length)
1633 SECItem detdig;
1635 SEC_PKCS7ContentInfo *cinfo = NULL;
1636 SEC_PKCS7DecoderContext *dcx;
1638 int status = 0;
1639 char *errstring = NULL;
1641 PORT_Assert( jar != NULL && signer != NULL );
1643 if (jar == NULL || signer == NULL)
1644 return JAR_ERR_ORDER;
1646 signer->valid = JAR_ERR_SIG;
1648 /* We need a context if we can get one */
1650 #ifdef MOZILLA_CLIENT_OLD
1651 if (jar->mw == NULL) {
1652 JAR_set_context (jar, NULL);
1654 #endif
1657 dcx = SEC_PKCS7DecoderStart
1658 (jar_catch_bytes, NULL /*cb_arg*/, NULL /*getpassword*/, jar->mw,
1659 NULL, NULL, NULL);
1661 if (dcx == NULL)
1663 /* strange pkcs7 failure */
1664 return JAR_ERR_PK7;
1667 SEC_PKCS7DecoderUpdate (dcx, data, length);
1668 cinfo = SEC_PKCS7DecoderFinish (dcx);
1670 if (cinfo == NULL)
1672 /* strange pkcs7 failure */
1673 return JAR_ERR_PK7;
1676 if (SEC_PKCS7ContentIsEncrypted (cinfo))
1678 /* content was encrypted, fail */
1679 return JAR_ERR_PK7;
1682 if (SEC_PKCS7ContentIsSigned (cinfo) == PR_FALSE)
1684 /* content was not signed, fail */
1685 return JAR_ERR_PK7;
1688 PORT_SetError (0);
1690 /* use SHA1 only */
1692 detdig.len = SHA1_LENGTH;
1693 detdig.data = signer->digest->sha1;
1695 if (SEC_PKCS7VerifyDetachedSignature
1696 (cinfo, certUsageObjectSigner, &detdig, HASH_AlgSHA1, PR_FALSE)==
1697 PR_TRUE)
1699 /* signature is valid */
1700 signer->valid = 0;
1701 jar_gather_signers (jar, signer, cinfo);
1703 else
1705 status = PORT_GetError();
1707 PORT_Assert( status < 0 );
1708 if (status >= 0) status = JAR_ERR_SIG;
1710 jar->valid = status;
1711 signer->valid = status;
1713 errstring = JAR_get_error (status);
1714 /*XP_TRACE(("JAR signature invalid (reason %d = %s)", status, errstring));*/
1717 jar->pkcs7 = PR_TRUE;
1718 signer->pkcs7 = PR_TRUE;
1720 SEC_PKCS7DestroyContentInfo (cinfo);
1722 return status;
1726 * j a r _ g a t h e r _ s i g n e r s
1728 * Add the single signer of this signature to the
1729 * certificate linked list.
1733 static int jar_gather_signers
1734 (JAR *jar, JAR_Signer *signer, SEC_PKCS7ContentInfo *cinfo)
1736 int result;
1738 CERTCertificate *cert;
1739 CERTCertDBHandle *certdb;
1741 SEC_PKCS7SignedData *sdp;
1742 SEC_PKCS7SignerInfo **pksigners, *pksigner;
1744 sdp = cinfo->content.signedData;
1746 if (sdp == NULL)
1747 return JAR_ERR_PK7;
1749 pksigners = sdp->signerInfos;
1751 /* permit exactly one signer */
1753 if (pksigners == NULL || pksigners [0] == NULL || pksigners [1] != NULL)
1754 return JAR_ERR_PK7;
1756 pksigner = *pksigners;
1757 cert = pksigner->cert;
1759 if (cert == NULL)
1760 return JAR_ERR_PK7;
1762 certdb = JAR_open_database();
1764 if (certdb == NULL)
1765 return JAR_ERR_GENERAL;
1767 result = jar_add_cert (jar, signer, jarTypeSign, cert);
1769 JAR_close_database (certdb);
1771 return result;
1775 * j a r _ o p e n _ d a t a b a s e
1777 * Open the certificate database,
1778 * for use by JAR functions.
1782 CERTCertDBHandle *JAR_open_database (void)
1784 CERTCertDBHandle *certdb;
1786 certdb = CERT_GetDefaultCertDB();
1788 return certdb;
1792 * j a r _ c l o s e _ d a t a b a s e
1794 * Close the certificate database.
1795 * For use by JAR functions.
1799 int JAR_close_database (CERTCertDBHandle *certdb)
1801 return 0;
1805 * j a r _ g e t _ c e r t i f i c a t e
1807 * Return the certificate referenced
1808 * by a given fingerprint, or NULL if not found.
1809 * Error code is returned in result.
1813 static CERTCertificate *jar_get_certificate
1814 (JAR *jar, long keylen, void *key, int *result)
1816 int found = 0;
1818 JAR_Item *it;
1819 JAR_Cert *fing = NULL;
1821 JAR_Context *ctx;
1823 if (jar == NULL)
1825 void *cert;
1826 cert = JAR_fetch_cert (keylen, key);
1827 *result = (cert == NULL) ? JAR_ERR_GENERAL : 0;
1828 return (CERTCertificate *) cert;
1831 ctx = JAR_find (jar, NULL, jarTypeSign);
1833 while (JAR_find_next (ctx, &it) >= 0)
1835 fing = (JAR_Cert *) it->data;
1837 if (keylen != fing->length)
1838 continue;
1840 PORT_Assert( keylen < 0xFFFF );
1841 if (!PORT_Memcmp (fing->key, key, keylen))
1843 found = 1;
1844 break;
1848 JAR_find_end (ctx);
1850 if (found == 0)
1852 *result = JAR_ERR_GENERAL;
1853 return NULL;
1856 PORT_Assert(fing != NULL);
1857 *result = 0;
1858 return fing->cert;
1862 * j a r _ s i g n a l
1864 * Nonfatal errors come here to callback Java.
1868 static int jar_signal
1869 (int status, JAR *jar, const char *metafile, char *pathname)
1871 char *errstring;
1873 errstring = JAR_get_error (status);
1875 if (jar->signal)
1877 (*jar->signal) (status, jar, metafile, pathname, errstring);
1878 return 0;
1881 return status;
1885 * j a r _ a p p e n d
1887 * Tack on an element to one of a JAR's linked
1888 * lists, with rudimentary error handling.
1892 int jar_append (ZZList *list, int type,
1893 char *pathname, void *data, size_t size)
1895 JAR_Item *it;
1896 ZZLink *entity;
1898 it = (JAR_Item*)PORT_ZAlloc (sizeof (JAR_Item));
1900 if (it == NULL)
1901 goto loser;
1903 if (pathname)
1905 it->pathname = PORT_Strdup (pathname);
1906 if (it->pathname == NULL)
1907 goto loser;
1910 it->type = (jarType)type;
1911 it->data = (unsigned char *) data;
1912 it->size = size;
1914 entity = ZZ_NewLink (it);
1916 if (entity)
1918 ZZ_AppendLink (list, entity);
1919 return 0;
1922 loser:
1924 if (it)
1926 if (it->pathname) PORT_Free (it->pathname);
1927 PORT_Free (it);
1930 return JAR_ERR_MEMORY;
1934 * W I N 1 6 s t u f f
1936 * These functions possibly belong in xp_mem.c, they operate
1937 * on huge string pointers for win16.
1941 #if defined(XP_WIN16)
1942 int xp_HUGE_STRNCASECMP (char ZHUGEP *buf, char *key, int len)
1944 while (len--)
1946 char c1, c2;
1948 c1 = *buf++;
1949 c2 = *key++;
1951 if (c1 >= 'a' && c1 <= 'z') c1 -= ('a' - 'A');
1952 if (c2 >= 'a' && c2 <= 'z') c2 -= ('a' - 'A');
1954 if (c1 != c2)
1955 return (c1 < c2) ? -1 : 1;
1957 return 0;
1960 size_t xp_HUGE_STRLEN (char ZHUGEP *s)
1962 size_t len = 0L;
1963 while (*s++) len++;
1964 return len;
1967 char *xp_HUGE_STRCPY (char *to, char ZHUGEP *from)
1969 char *ret = to;
1971 while (*from)
1972 *to++ = *from++;
1973 *to = 0;
1975 return ret;
1977 #endif