jar.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:16k
- /*
- * 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 Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
- /*
- * JAR.C
- *
- * Jarnature.
- * Routines common to signing and validating.
- *
- */
- #include "jar.h"
- #include "jarint.h"
- static void jar_destroy_list (ZZList *list);
- static int jar_find_first_cert
- (JAR_Signer *signer, int type, JAR_Item **it);
- /*
- * J A R _ n e w
- *
- * Create a new instantiation of a manifest representation.
- * Use this as a token to any calls to this API.
- *
- */
- JAR *JAR_new (void)
- {
- JAR *jar;
- if ((jar = (JAR*)PORT_ZAlloc (sizeof (JAR))) == NULL)
- goto loser;
- if ((jar->manifest = ZZ_NewList()) == NULL)
- goto loser;
- if ((jar->hashes = ZZ_NewList()) == NULL)
- goto loser;
- if ((jar->phy = ZZ_NewList()) == NULL)
- goto loser;
- if ((jar->metainfo = ZZ_NewList()) == NULL)
- goto loser;
- if ((jar->signers = ZZ_NewList()) == NULL)
- goto loser;
- return jar;
- loser:
- if (jar)
- {
- if (jar->manifest)
- ZZ_DestroyList (jar->manifest);
- if (jar->hashes)
- ZZ_DestroyList (jar->hashes);
- if (jar->phy)
- ZZ_DestroyList (jar->phy);
- if (jar->metainfo)
- ZZ_DestroyList (jar->metainfo);
- if (jar->signers)
- ZZ_DestroyList (jar->signers);
- PORT_Free (jar);
- }
- return NULL;
- }
- /*
- * J A R _ d e s t r o y
- *
- * Godzilla.
- *
- */
- void PR_CALLBACK JAR_destroy (JAR *jar)
- {
- JAR *z;
- PORT_Assert( jar != NULL );
- if (jar == NULL)
- return;
- if (jar->fp) JAR_FCLOSE ((PRFileDesc*)jar->fp);
- if (jar->url) PORT_Free (jar->url);
- if (jar->filename) PORT_Free (jar->filename);
- /* Free the linked list elements */
- jar_destroy_list (jar->manifest);
- ZZ_DestroyList (jar->manifest);
- jar_destroy_list (jar->hashes);
- ZZ_DestroyList (jar->hashes);
- jar_destroy_list (jar->phy);
- ZZ_DestroyList (jar->phy);
- jar_destroy_list (jar->metainfo);
- ZZ_DestroyList (jar->metainfo);
- jar_destroy_list (jar->signers);
- ZZ_DestroyList (jar->signers);
- PORT_Free (jar);
- }
- static void jar_destroy_list (ZZList *list)
- {
- ZZLink *link, *oldlink;
- JAR_Item *it;
- JAR_Physical *phy;
- JAR_Digest *dig;
- JAR_Cert *fing;
- JAR_Metainfo *met;
- JAR_Signer *signer;
- if (list && !ZZ_ListEmpty (list))
- {
- link = ZZ_ListHead (list);
- while (!ZZ_ListIterDone (list, link))
- {
- it = link->thing;
- if (!it) goto next;
- if (it->pathname) PORT_Free (it->pathname);
-
- switch (it->type)
- {
- case jarTypeMeta:
- met = (JAR_Metainfo *) it->data;
- if (met)
- {
- if (met->header) PORT_Free (met->header);
- if (met->info) PORT_Free (met->info);
- PORT_Free (met);
- }
- break;
- case jarTypePhy:
- phy = (JAR_Physical *) it->data;
- if (phy)
- PORT_Free (phy);
- break;
- case jarTypeSign:
- fing = (JAR_Cert *) it->data;
- if (fing)
- {
- if (fing->cert)
- CERT_DestroyCertificate (fing->cert);
- if (fing->key)
- PORT_Free (fing->key);
- PORT_Free (fing);
- }
- break;
- case jarTypeSect:
- case jarTypeMF:
- case jarTypeSF:
- dig = (JAR_Digest *) it->data;
- if (dig)
- {
- PORT_Free (dig);
- }
- break;
- case jarTypeOwner:
- signer = (JAR_Signer *) it->data;
- if (signer)
- JAR_destroy_signer (signer);
- break;
- default:
- /* PORT_Assert( 1 != 2 ); */
- break;
- }
- PORT_Free (it);
- next:
- oldlink = link;
- link = link->next;
- ZZ_DestroyLink (oldlink);
- }
- }
- }
- /*
- * J A R _ g e t _ m e t a i n f o
- *
- * Retrieve meta information from the manifest file.
- * It doesn't matter whether it's from .MF or .SF, does it?
- *
- */
- int JAR_get_metainfo
- (JAR *jar, char *name, char *header, void **info, unsigned long *length)
- {
- JAR_Item *it;
- ZZLink *link;
- ZZList *list;
- JAR_Metainfo *met;
- PORT_Assert( jar != NULL && header != NULL );
- if (jar == NULL || header == NULL)
- return JAR_ERR_PNF;
- list = jar->metainfo;
- if (ZZ_ListEmpty (list))
- return JAR_ERR_PNF;
- for (link = ZZ_ListHead (list);
- !ZZ_ListIterDone (list, link);
- link = link->next)
- {
- it = link->thing;
- if (it->type == jarTypeMeta)
- {
- if ((name && !it->pathname) || (!name && it->pathname))
- continue;
- if (name && it->pathname && strcmp (it->pathname, name))
- continue;
- met = (JAR_Metainfo *) it->data;
- if (!PORT_Strcasecmp (met->header, header))
- {
- *info = PORT_Strdup (met->info);
- *length = PORT_Strlen (met->info);
- return 0;
- }
- }
- }
- return JAR_ERR_PNF;
- }
- /*
- * J A R _ f i n d
- *
- * Establish the search pattern for use
- * by JAR_find_next, to traverse the filenames
- * or certificates in the JAR structure.
- *
- * See jar.h for a description on how to use.
- *
- */
- JAR_Context *JAR_find (JAR *jar, char *pattern, jarType type)
- {
- JAR_Context *ctx;
- PORT_Assert( jar != NULL );
- if (!jar)
- return NULL;
- ctx = (JAR_Context *) PORT_ZAlloc (sizeof (JAR_Context));
- if (ctx == NULL)
- return NULL;
- ctx->jar = jar;
- if (pattern)
- {
- if ((ctx->pattern = PORT_Strdup (pattern)) == NULL)
- {
- PORT_Free (ctx);
- return NULL;
- }
- }
- ctx->finding = type;
- switch (type)
- {
- case jarTypeMF: ctx->next = ZZ_ListHead (jar->hashes);
- break;
- case jarTypeSF:
- case jarTypeSign: ctx->next = NULL;
- ctx->nextsign = ZZ_ListHead (jar->signers);
- break;
- case jarTypeSect: ctx->next = ZZ_ListHead (jar->manifest);
- break;
- case jarTypePhy: ctx->next = ZZ_ListHead (jar->phy);
- break;
- case jarTypeOwner: if (jar->signers)
- ctx->next = ZZ_ListHead (jar->signers);
- else
- ctx->next = NULL;
- break;
- case jarTypeMeta: ctx->next = ZZ_ListHead (jar->metainfo);
- break;
- default: PORT_Assert( 1 != 2);
- break;
- }
- return ctx;
- }
- /*
- * J A R _ f i n d _ e n d
- *
- * Destroy the find iterator context.
- *
- */
- void JAR_find_end (JAR_Context *ctx)
- {
- PORT_Assert( ctx != NULL );
- if (ctx)
- {
- if (ctx->pattern)
- PORT_Free (ctx->pattern);
- PORT_Free (ctx);
- }
- }
- /*
- * J A R _ f i n d _ n e x t
- *
- * Return the next item of the given type
- * from one of the JAR linked lists.
- *
- */
- int JAR_find_next (JAR_Context *ctx, JAR_Item **it)
- {
- JAR *jar;
- ZZList *list;
- int finding;
- JAR_Signer *signer = NULL;
- PORT_Assert( ctx != NULL );
- PORT_Assert( ctx->jar != NULL );
- jar = ctx->jar;
- /* Internally, convert jarTypeSign to jarTypeSF, and return
- the actual attached certificate later */
- finding = (ctx->finding == jarTypeSign) ? jarTypeSF : ctx->finding;
- if (ctx->nextsign)
- {
- if (ZZ_ListIterDone (jar->signers, ctx->nextsign))
- {
- *it = NULL;
- return -1;
- }
- PORT_Assert (ctx->nextsign->thing != NULL);
- signer = (JAR_Signer*)ctx->nextsign->thing->data;
- }
- /* Find out which linked list to traverse. Then if
- necessary, advance to the next linked list. */
- while (1)
- {
- switch (finding)
- {
- case jarTypeSign: /* not any more */
- PORT_Assert( finding != jarTypeSign );
- list = signer->certs;
- break;
- case jarTypeSect: list = jar->manifest;
- break;
- case jarTypePhy: list = jar->phy;
- break;
- case jarTypeSF: /* signer, not jar */
- PORT_Assert( signer != NULL );
- list = signer->sf;
- break;
- case jarTypeMF: list = jar->hashes;
- break;
- case jarTypeOwner: list = jar->signers;
- break;
- case jarTypeMeta: list = jar->metainfo;
- break;
- default: PORT_Assert( 1 != 2 );
- break;
- }
- if (list == NULL)
- {
- *it = NULL;
- return -1;
- }
- /* When looping over lists of lists, advance
- to the next signer. This is done when multiple
- signers are possible. */
- if (ZZ_ListIterDone (list, ctx->next))
- {
- if (ctx->nextsign && jar->signers)
- {
- ctx->nextsign = ctx->nextsign->next;
- if (!ZZ_ListIterDone (jar->signers, ctx->nextsign))
- {
- PORT_Assert (ctx->nextsign->thing != NULL);
- signer = (JAR_Signer*)ctx->nextsign->thing->data;
- PORT_Assert( signer != NULL );
- ctx->next = NULL;
- continue;
- }
- }
- *it = NULL;
- return -1;
- }
- /* if the signer changed, still need to fill
- in the "next" link */
- if (ctx->nextsign && ctx->next == NULL)
- {
- switch (finding)
- {
- case jarTypeSF:
- ctx->next = ZZ_ListHead (signer->sf);
- break;
- case jarTypeSign:
- ctx->next = ZZ_ListHead (signer->certs);
- break;
- }
- }
- PORT_Assert( ctx->next != NULL );
- while (!ZZ_ListIterDone (list, ctx->next))
- {
- *it = ctx->next->thing;
- ctx->next = ctx->next->next;
- if (!it || !*it || (*it)->type != finding)
- continue;
- if (ctx->pattern && *ctx->pattern)
- {
- if (PORT_Strcmp ((*it)->pathname, ctx->pattern))
- continue;
- }
- /* We have a valid match. If this is a jarTypeSign
- return the certificate instead.. */
- if (ctx->finding == jarTypeSign)
- {
- JAR_Item *itt;
- /* just the first one for now */
- if (jar_find_first_cert (signer, jarTypeSign, &itt) >= 0)
- {
- *it = itt;
- return 0;
- }
- continue;
- }
- return 0;
- }
- } /* end while */
- }
- static int jar_find_first_cert
- (JAR_Signer *signer, int type, JAR_Item **it)
- {
- ZZLink *link;
- ZZList *list;
- int status = JAR_ERR_PNF;
- list = signer->certs;
- *it = NULL;
- if (ZZ_ListEmpty (list))
- {
- /* empty list */
- return JAR_ERR_PNF;
- }
- for (link = ZZ_ListHead (list);
- !ZZ_ListIterDone (list, link);
- link = link->next)
- {
- if (link->thing->type == type)
- {
- *it = link->thing;
- status = 0;
- break;
- }
- }
- return status;
- }
- JAR_Signer *JAR_new_signer (void)
- {
- JAR_Signer *signer;
- signer = (JAR_Signer *) PORT_ZAlloc (sizeof (JAR_Signer));
- if (signer == NULL)
- goto loser;
- /* certs */
- signer->certs = ZZ_NewList();
- if (signer->certs == NULL)
- goto loser;
- /* sf */
- signer->sf = ZZ_NewList();
- if (signer->sf == NULL)
- goto loser;
- return signer;
- loser:
- if (signer)
- {
- if (signer->certs)
- ZZ_DestroyList (signer->certs);
- if (signer->sf)
- ZZ_DestroyList (signer->sf);
- PORT_Free (signer);
- }
- return NULL;
- }
- void JAR_destroy_signer (JAR_Signer *signer)
- {
- if (signer)
- {
- if (signer->owner) PORT_Free (signer->owner);
- if (signer->digest) PORT_Free (signer->digest);
- jar_destroy_list (signer->sf);
- ZZ_DestroyList (signer->sf);
- jar_destroy_list (signer->certs);
- ZZ_DestroyList (signer->certs);
- PORT_Free (signer);
- }
- }
- JAR_Signer *jar_get_signer (JAR *jar, char *basename)
- {
- JAR_Item *it;
- JAR_Context *ctx;
- JAR_Signer *candidate;
- JAR_Signer *signer = NULL;
- ctx = JAR_find (jar, NULL, jarTypeOwner);
- if (ctx == NULL)
- return NULL;
- while (JAR_find_next (ctx, &it) >= 0)
- {
- candidate = (JAR_Signer *) it->data;
- if (*basename == '*' || !PORT_Strcmp (candidate->owner, basename))
- {
- signer = candidate;
- break;
- }
- }
- JAR_find_end (ctx);
- return signer;
- }
- /*
- * J A R _ g e t _ f i l e n a m e
- *
- * Returns the filename associated with
- * a JAR structure.
- *
- */
- char *JAR_get_filename (JAR *jar)
- {
- return jar->filename;
- }
- /*
- * J A R _ g e t _ u r l
- *
- * Returns the URL associated with
- * a JAR structure. Nobody really uses this now.
- *
- */
- char *JAR_get_url (JAR *jar)
- {
- return jar->url;
- }
- /*
- * J A R _ s e t _ c a l l b a c k
- *
- * Register some manner of callback function for this jar.
- *
- */
- int JAR_set_callback (int type, JAR *jar,
- int (*fn) (int status, JAR *jar,
- const char *metafile, char *pathname, char *errortext))
- {
- if (type == JAR_CB_SIGNAL)
- {
- jar->signal = fn;
- return 0;
- }
- else
- return -1;
- }
- /*
- * Callbacks
- *
- */
- /* To return an error string */
- char *(*jar_fn_GetString) (int) = NULL;
- /* To return an MWContext for Java */
- void *(*jar_fn_FindSomeContext) (void) = NULL;
- /* To fabricate an MWContext for FE_GetPassword */
- void *(*jar_fn_GetInitContext) (void) = NULL;
- void
- JAR_init_callbacks
- (
- char *(*string_cb)(int),
- void *(*find_cx)(void),
- void *(*init_cx)(void)
- )
- {
- jar_fn_GetString = string_cb;
- jar_fn_FindSomeContext = find_cx;
- jar_fn_GetInitContext = init_cx;
- }
- /*
- * J A R _ g e t _ e r r o r
- *
- * This is provided to map internal JAR errors to strings for
- * the Java console. Also, a DLL may call this function if it does
- * not have access to the XP_GetString function.
- *
- * These strings aren't UI, since they are Java console only.
- *
- */
- char *JAR_get_error (int status)
- {
- char *errstring = NULL;
- switch (status)
- {
- case JAR_ERR_GENERAL:
- errstring = "General JAR file error";
- break;
- case JAR_ERR_FNF:
- errstring = "JAR file not found";
- break;
- case JAR_ERR_CORRUPT:
- errstring = "Corrupt JAR file";
- break;
- case JAR_ERR_MEMORY:
- errstring = "Out of memory";
- break;
- case JAR_ERR_DISK:
- errstring = "Disk error (perhaps out of space)";
- break;
- case JAR_ERR_ORDER:
- errstring = "Inconsistent files in META-INF directory";
- break;
- case JAR_ERR_SIG:
- errstring = "Invalid digital signature file";
- break;
- case JAR_ERR_METADATA:
- errstring = "JAR metadata failed verification";
- break;
- case JAR_ERR_ENTRY:
- errstring = "No Manifest entry for this JAR entry";
- break;
- case JAR_ERR_HASH:
- errstring = "Invalid Hash of this JAR entry";
- break;
- case JAR_ERR_PK7:
- errstring = "Strange PKCS7 or RSA failure";
- break;
- case JAR_ERR_PNF:
- errstring = "Path not found inside JAR file";
- break;
- default:
- if (jar_fn_GetString)
- {
- errstring = jar_fn_GetString (status);
- }
- else
- {
- /* this is not a normal situation, and would only be
- called in cases of improper initialization */
- char *err;
- err = (char*)PORT_Alloc (40);
- if (err)
- PR_snprintf (err, 39, "Error %dn", status);
- else
- err = "Error! Bad! Out of memory!";
- return err;
- }
- break;
- }
- return errstring;
- }