Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / jar / jar.c
blob6d575a036209eaa09e03b3c61a62c94ced3a953e
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 * JAR.C
40 * Jarnature.
41 * Routines common to signing and validating.
45 #include "jar.h"
46 #include "jarint.h"
48 static void jar_destroy_list (ZZList *list);
50 static int jar_find_first_cert
51 (JAR_Signer *signer, int type, JAR_Item **it);
54 * J A R _ n e w
56 * Create a new instantiation of a manifest representation.
57 * Use this as a token to any calls to this API.
61 JAR *JAR_new (void)
63 JAR *jar;
65 if ((jar = (JAR*)PORT_ZAlloc (sizeof (JAR))) == NULL)
66 goto loser;
68 if ((jar->manifest = ZZ_NewList()) == NULL)
69 goto loser;
71 if ((jar->hashes = ZZ_NewList()) == NULL)
72 goto loser;
74 if ((jar->phy = ZZ_NewList()) == NULL)
75 goto loser;
77 if ((jar->metainfo = ZZ_NewList()) == NULL)
78 goto loser;
80 if ((jar->signers = ZZ_NewList()) == NULL)
81 goto loser;
83 return jar;
85 loser:
87 if (jar)
89 if (jar->manifest)
90 ZZ_DestroyList (jar->manifest);
92 if (jar->hashes)
93 ZZ_DestroyList (jar->hashes);
95 if (jar->phy)
96 ZZ_DestroyList (jar->phy);
98 if (jar->metainfo)
99 ZZ_DestroyList (jar->metainfo);
101 if (jar->signers)
102 ZZ_DestroyList (jar->signers);
104 PORT_Free (jar);
107 return NULL;
111 * J A R _ d e s t r o y
113 * Godzilla.
117 void PR_CALLBACK JAR_destroy (JAR *jar)
119 PORT_Assert( jar != NULL );
121 if (jar == NULL)
122 return;
124 if (jar->fp) JAR_FCLOSE ((PRFileDesc*)jar->fp);
126 if (jar->url) PORT_Free (jar->url);
127 if (jar->filename) PORT_Free (jar->filename);
129 /* Free the linked list elements */
131 jar_destroy_list (jar->manifest);
132 ZZ_DestroyList (jar->manifest);
134 jar_destroy_list (jar->hashes);
135 ZZ_DestroyList (jar->hashes);
137 jar_destroy_list (jar->phy);
138 ZZ_DestroyList (jar->phy);
140 jar_destroy_list (jar->metainfo);
141 ZZ_DestroyList (jar->metainfo);
143 jar_destroy_list (jar->signers);
144 ZZ_DestroyList (jar->signers);
146 PORT_Free (jar);
149 static void jar_destroy_list (ZZList *list)
151 ZZLink *link, *oldlink;
153 JAR_Item *it;
155 JAR_Physical *phy;
156 JAR_Digest *dig;
157 JAR_Cert *fing;
158 JAR_Metainfo *met;
159 JAR_Signer *signer;
161 if (list && !ZZ_ListEmpty (list))
163 link = ZZ_ListHead (list);
165 while (!ZZ_ListIterDone (list, link))
167 it = link->thing;
168 if (!it) goto next;
170 if (it->pathname) PORT_Free (it->pathname);
172 switch (it->type)
174 case jarTypeMeta:
176 met = (JAR_Metainfo *) it->data;
177 if (met)
179 if (met->header) PORT_Free (met->header);
180 if (met->info) PORT_Free (met->info);
181 PORT_Free (met);
183 break;
185 case jarTypePhy:
187 phy = (JAR_Physical *) it->data;
188 if (phy)
189 PORT_Free (phy);
190 break;
192 case jarTypeSign:
194 fing = (JAR_Cert *) it->data;
195 if (fing)
197 if (fing->cert)
198 CERT_DestroyCertificate (fing->cert);
199 if (fing->key)
200 PORT_Free (fing->key);
201 PORT_Free (fing);
203 break;
205 case jarTypeSect:
206 case jarTypeMF:
207 case jarTypeSF:
209 dig = (JAR_Digest *) it->data;
210 if (dig)
212 PORT_Free (dig);
214 break;
216 case jarTypeOwner:
218 signer = (JAR_Signer *) it->data;
220 if (signer)
221 JAR_destroy_signer (signer);
223 break;
225 default:
227 /* PORT_Assert( 1 != 2 ); */
228 break;
231 PORT_Free (it);
233 next:
235 oldlink = link;
236 link = link->next;
238 ZZ_DestroyLink (oldlink);
244 * J A R _ g e t _ m e t a i n f o
246 * Retrieve meta information from the manifest file.
247 * It doesn't matter whether it's from .MF or .SF, does it?
251 int JAR_get_metainfo
252 (JAR *jar, char *name, char *header, void **info, unsigned long *length)
254 JAR_Item *it;
256 ZZLink *link;
257 ZZList *list;
259 JAR_Metainfo *met;
261 PORT_Assert( jar != NULL && header != NULL );
263 if (jar == NULL || header == NULL)
264 return JAR_ERR_PNF;
266 list = jar->metainfo;
268 if (ZZ_ListEmpty (list))
269 return JAR_ERR_PNF;
271 for (link = ZZ_ListHead (list);
272 !ZZ_ListIterDone (list, link);
273 link = link->next)
275 it = link->thing;
276 if (it->type == jarTypeMeta)
278 if ((name && !it->pathname) || (!name && it->pathname))
279 continue;
281 if (name && it->pathname && strcmp (it->pathname, name))
282 continue;
284 met = (JAR_Metainfo *) it->data;
286 if (!PORT_Strcasecmp (met->header, header))
288 *info = PORT_Strdup (met->info);
289 *length = PORT_Strlen (met->info);
290 return 0;
295 return JAR_ERR_PNF;
299 * J A R _ f i n d
301 * Establish the search pattern for use
302 * by JAR_find_next, to traverse the filenames
303 * or certificates in the JAR structure.
305 * See jar.h for a description on how to use.
309 JAR_Context *JAR_find (JAR *jar, char *pattern, jarType type)
311 JAR_Context *ctx;
313 PORT_Assert( jar != NULL );
315 if (!jar)
316 return NULL;
318 ctx = (JAR_Context *) PORT_ZAlloc (sizeof (JAR_Context));
320 if (ctx == NULL)
321 return NULL;
323 ctx->jar = jar;
325 if (pattern)
327 if ((ctx->pattern = PORT_Strdup (pattern)) == NULL)
329 PORT_Free (ctx);
330 return NULL;
334 ctx->finding = type;
336 switch (type)
338 case jarTypeMF: ctx->next = ZZ_ListHead (jar->hashes);
339 break;
341 case jarTypeSF:
342 case jarTypeSign: ctx->next = NULL;
343 ctx->nextsign = ZZ_ListHead (jar->signers);
344 break;
346 case jarTypeSect: ctx->next = ZZ_ListHead (jar->manifest);
347 break;
349 case jarTypePhy: ctx->next = ZZ_ListHead (jar->phy);
350 break;
352 case jarTypeOwner: if (jar->signers)
353 ctx->next = ZZ_ListHead (jar->signers);
354 else
355 ctx->next = NULL;
356 break;
358 case jarTypeMeta: ctx->next = ZZ_ListHead (jar->metainfo);
359 break;
361 default: PORT_Assert( 1 != 2);
362 break;
365 return ctx;
369 * J A R _ f i n d _ e n d
371 * Destroy the find iterator context.
375 void JAR_find_end (JAR_Context *ctx)
377 PORT_Assert( ctx != NULL );
379 if (ctx)
381 if (ctx->pattern)
382 PORT_Free (ctx->pattern);
383 PORT_Free (ctx);
388 * J A R _ f i n d _ n e x t
390 * Return the next item of the given type
391 * from one of the JAR linked lists.
395 int JAR_find_next (JAR_Context *ctx, JAR_Item **it)
397 JAR *jar;
398 ZZList *list = NULL;
400 int finding;
402 JAR_Signer *signer = NULL;
404 PORT_Assert( ctx != NULL );
405 PORT_Assert( ctx->jar != NULL );
407 jar = ctx->jar;
409 /* Internally, convert jarTypeSign to jarTypeSF, and return
410 the actual attached certificate later */
412 finding = (ctx->finding == jarTypeSign) ? jarTypeSF : ctx->finding;
414 if (ctx->nextsign)
416 if (ZZ_ListIterDone (jar->signers, ctx->nextsign))
418 *it = NULL;
419 return -1;
421 PORT_Assert (ctx->nextsign->thing != NULL);
422 signer = (JAR_Signer*)ctx->nextsign->thing->data;
426 /* Find out which linked list to traverse. Then if
427 necessary, advance to the next linked list. */
429 while (1)
431 switch (finding)
433 case jarTypeSign: /* not any more */
434 PORT_Assert( finding != jarTypeSign );
435 list = signer->certs;
436 break;
438 case jarTypeSect: list = jar->manifest;
439 break;
441 case jarTypePhy: list = jar->phy;
442 break;
444 case jarTypeSF: /* signer, not jar */
445 PORT_Assert( signer != NULL );
446 list = signer->sf;
447 break;
449 case jarTypeMF: list = jar->hashes;
450 break;
452 case jarTypeOwner: list = jar->signers;
453 break;
455 case jarTypeMeta: list = jar->metainfo;
456 break;
458 default: PORT_Assert( 1 != 2 );
459 break;
462 if (list == NULL)
464 *it = NULL;
465 return -1;
468 /* When looping over lists of lists, advance
469 to the next signer. This is done when multiple
470 signers are possible. */
472 if (ZZ_ListIterDone (list, ctx->next))
474 if (ctx->nextsign && jar->signers)
476 ctx->nextsign = ctx->nextsign->next;
477 if (!ZZ_ListIterDone (jar->signers, ctx->nextsign))
479 PORT_Assert (ctx->nextsign->thing != NULL);
481 signer = (JAR_Signer*)ctx->nextsign->thing->data;
482 PORT_Assert( signer != NULL );
484 ctx->next = NULL;
485 continue;
488 *it = NULL;
489 return -1;
492 /* if the signer changed, still need to fill
493 in the "next" link */
495 if (ctx->nextsign && ctx->next == NULL)
497 switch (finding)
499 case jarTypeSF:
501 ctx->next = ZZ_ListHead (signer->sf);
502 break;
504 case jarTypeSign:
506 ctx->next = ZZ_ListHead (signer->certs);
507 break;
511 PORT_Assert( ctx->next != NULL );
514 while (!ZZ_ListIterDone (list, ctx->next))
516 *it = ctx->next->thing;
517 ctx->next = ctx->next->next;
519 if (!*it || (*it)->type != finding)
520 continue;
522 if (ctx->pattern && *ctx->pattern)
524 if (PORT_Strcmp ((*it)->pathname, ctx->pattern))
525 continue;
528 /* We have a valid match. If this is a jarTypeSign
529 return the certificate instead.. */
531 if (ctx->finding == jarTypeSign)
533 JAR_Item *itt;
535 /* just the first one for now */
536 if (jar_find_first_cert (signer, jarTypeSign, &itt) >= 0)
538 *it = itt;
539 return 0;
542 continue;
545 return 0;
548 } /* end while */
551 static int jar_find_first_cert
552 (JAR_Signer *signer, int type, JAR_Item **it)
554 ZZLink *link;
555 ZZList *list;
557 int status = JAR_ERR_PNF;
559 list = signer->certs;
561 *it = NULL;
563 if (ZZ_ListEmpty (list))
565 /* empty list */
566 return JAR_ERR_PNF;
569 for (link = ZZ_ListHead (list);
570 !ZZ_ListIterDone (list, link);
571 link = link->next)
573 if (link->thing->type == type)
575 *it = link->thing;
576 status = 0;
577 break;
581 return status;
584 JAR_Signer *JAR_new_signer (void)
586 JAR_Signer *signer;
588 signer = (JAR_Signer *) PORT_ZAlloc (sizeof (JAR_Signer));
590 if (signer == NULL)
591 goto loser;
594 /* certs */
595 signer->certs = ZZ_NewList();
597 if (signer->certs == NULL)
598 goto loser;
601 /* sf */
602 signer->sf = ZZ_NewList();
604 if (signer->sf == NULL)
605 goto loser;
608 return signer;
611 loser:
613 if (signer)
615 if (signer->certs)
616 ZZ_DestroyList (signer->certs);
618 if (signer->sf)
619 ZZ_DestroyList (signer->sf);
621 PORT_Free (signer);
624 return NULL;
627 void JAR_destroy_signer (JAR_Signer *signer)
629 if (signer)
631 if (signer->owner) PORT_Free (signer->owner);
632 if (signer->digest) PORT_Free (signer->digest);
634 jar_destroy_list (signer->sf);
635 ZZ_DestroyList (signer->sf);
637 jar_destroy_list (signer->certs);
638 ZZ_DestroyList (signer->certs);
640 PORT_Free (signer);
644 JAR_Signer *jar_get_signer (JAR *jar, char *basename)
646 JAR_Item *it;
647 JAR_Context *ctx;
649 JAR_Signer *candidate;
650 JAR_Signer *signer = NULL;
652 ctx = JAR_find (jar, NULL, jarTypeOwner);
654 if (ctx == NULL)
655 return NULL;
657 while (JAR_find_next (ctx, &it) >= 0)
659 candidate = (JAR_Signer *) it->data;
660 if (*basename == '*' || !PORT_Strcmp (candidate->owner, basename))
662 signer = candidate;
663 break;
667 JAR_find_end (ctx);
669 return signer;
673 * J A R _ g e t _ f i l e n a m e
675 * Returns the filename associated with
676 * a JAR structure.
680 char *JAR_get_filename (JAR *jar)
682 return jar->filename;
686 * J A R _ g e t _ u r l
688 * Returns the URL associated with
689 * a JAR structure. Nobody really uses this now.
693 char *JAR_get_url (JAR *jar)
695 return jar->url;
699 * J A R _ s e t _ c a l l b a c k
701 * Register some manner of callback function for this jar.
705 int JAR_set_callback (int type, JAR *jar,
706 int (*fn) (int status, JAR *jar,
707 const char *metafile, char *pathname, char *errortext))
709 if (type == JAR_CB_SIGNAL)
711 jar->signal = fn;
712 return 0;
714 else
715 return -1;
719 * Callbacks
723 /* To return an error string */
724 char *(*jar_fn_GetString) (int) = NULL;
726 /* To return an MWContext for Java */
727 void *(*jar_fn_FindSomeContext) (void) = NULL;
729 /* To fabricate an MWContext for FE_GetPassword */
730 void *(*jar_fn_GetInitContext) (void) = NULL;
732 void
733 JAR_init_callbacks
735 char *(*string_cb)(int),
736 void *(*find_cx)(void),
737 void *(*init_cx)(void)
740 jar_fn_GetString = string_cb;
741 jar_fn_FindSomeContext = find_cx;
742 jar_fn_GetInitContext = init_cx;
746 * J A R _ g e t _ e r r o r
748 * This is provided to map internal JAR errors to strings for
749 * the Java console. Also, a DLL may call this function if it does
750 * not have access to the XP_GetString function.
752 * These strings aren't UI, since they are Java console only.
756 char *JAR_get_error (int status)
758 char *errstring = NULL;
760 switch (status)
762 case JAR_ERR_GENERAL:
763 errstring = "General JAR file error";
764 break;
766 case JAR_ERR_FNF:
767 errstring = "JAR file not found";
768 break;
770 case JAR_ERR_CORRUPT:
771 errstring = "Corrupt JAR file";
772 break;
774 case JAR_ERR_MEMORY:
775 errstring = "Out of memory";
776 break;
778 case JAR_ERR_DISK:
779 errstring = "Disk error (perhaps out of space)";
780 break;
782 case JAR_ERR_ORDER:
783 errstring = "Inconsistent files in META-INF directory";
784 break;
786 case JAR_ERR_SIG:
787 errstring = "Invalid digital signature file";
788 break;
790 case JAR_ERR_METADATA:
791 errstring = "JAR metadata failed verification";
792 break;
794 case JAR_ERR_ENTRY:
795 errstring = "No Manifest entry for this JAR entry";
796 break;
798 case JAR_ERR_HASH:
799 errstring = "Invalid Hash of this JAR entry";
800 break;
802 case JAR_ERR_PK7:
803 errstring = "Strange PKCS7 or RSA failure";
804 break;
806 case JAR_ERR_PNF:
807 errstring = "Path not found inside JAR file";
808 break;
810 default:
811 if (jar_fn_GetString)
813 errstring = jar_fn_GetString (status);
815 else
817 /* this is not a normal situation, and would only be
818 called in cases of improper initialization */
820 char *err;
822 err = (char*)PORT_Alloc (40);
823 if (err)
824 PR_snprintf (err, 39, "Error %d\n", status);
825 else
826 err = "Error! Bad! Out of memory!";
828 return err;
830 break;
833 return errstring;