Back to index

lightning-sunbird  0.9+nobinonly
jar.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  *  JAR.C
00039  *
00040  *  Jarnature.
00041  *  Routines common to signing and validating.
00042  *
00043  */
00044 
00045 #include "jar.h"
00046 #include "jarint.h"
00047 
00048 static void jar_destroy_list (ZZList *list);
00049 
00050 static int jar_find_first_cert 
00051     (JAR_Signer *signer, int type, JAR_Item **it);
00052 
00053 /*
00054  *  J A R _ n e w 
00055  *
00056  *  Create a new instantiation of a manifest representation.
00057  *  Use this as a token to any calls to this API.
00058  *
00059  */
00060 
00061 JAR *JAR_new (void)
00062   {
00063   JAR *jar;
00064 
00065   if ((jar = (JAR*)PORT_ZAlloc (sizeof (JAR))) == NULL)
00066     goto loser;
00067 
00068   if ((jar->manifest = ZZ_NewList()) == NULL)
00069     goto loser;
00070 
00071   if ((jar->hashes = ZZ_NewList()) == NULL)
00072     goto loser;
00073 
00074   if ((jar->phy = ZZ_NewList()) == NULL)
00075     goto loser;
00076 
00077   if ((jar->metainfo = ZZ_NewList()) == NULL)
00078     goto loser;
00079 
00080   if ((jar->signers = ZZ_NewList()) == NULL)
00081     goto loser;
00082 
00083   return jar;
00084 
00085 loser:
00086 
00087   if (jar)
00088     {
00089     if (jar->manifest)
00090       ZZ_DestroyList (jar->manifest);
00091 
00092     if (jar->hashes)
00093       ZZ_DestroyList (jar->hashes);
00094 
00095     if (jar->phy)
00096       ZZ_DestroyList (jar->phy);
00097 
00098     if (jar->metainfo)
00099       ZZ_DestroyList (jar->metainfo);
00100 
00101     if (jar->signers)
00102       ZZ_DestroyList (jar->signers);
00103 
00104     PORT_Free (jar);
00105     }
00106 
00107   return NULL;
00108   }
00109 
00110 /* 
00111  *  J A R _ d e s t r o y
00112  *
00113  *  Godzilla.
00114  *
00115  */
00116 
00117 void PR_CALLBACK JAR_destroy (JAR *jar)
00118   {
00119   PORT_Assert( jar != NULL );
00120 
00121   if (jar == NULL)
00122     return;
00123 
00124   if (jar->fp) JAR_FCLOSE ((PRFileDesc*)jar->fp);
00125 
00126   if (jar->url)      PORT_Free (jar->url);
00127   if (jar->filename) PORT_Free (jar->filename);
00128 
00129   /* Free the linked list elements */
00130 
00131   jar_destroy_list (jar->manifest);
00132   ZZ_DestroyList (jar->manifest);
00133 
00134   jar_destroy_list (jar->hashes);
00135   ZZ_DestroyList (jar->hashes);
00136 
00137   jar_destroy_list (jar->phy);
00138   ZZ_DestroyList (jar->phy);
00139 
00140   jar_destroy_list (jar->metainfo);
00141   ZZ_DestroyList (jar->metainfo);
00142 
00143   jar_destroy_list (jar->signers);
00144   ZZ_DestroyList (jar->signers);
00145 
00146   PORT_Free (jar);
00147   }
00148 
00149 static void jar_destroy_list (ZZList *list)
00150   {
00151   ZZLink *link, *oldlink;
00152 
00153   JAR_Item *it;
00154 
00155   JAR_Physical *phy;
00156   JAR_Digest *dig;
00157   JAR_Cert *fing;
00158   JAR_Metainfo *met;
00159   JAR_Signer *signer;
00160 
00161   if (list && !ZZ_ListEmpty (list))
00162     {
00163     link = ZZ_ListHead (list);
00164 
00165     while (!ZZ_ListIterDone (list, link))
00166       {
00167       it = link->thing;
00168       if (!it) goto next;
00169 
00170       if (it->pathname) PORT_Free (it->pathname);
00171  
00172       switch (it->type)
00173         {
00174         case jarTypeMeta:
00175 
00176           met = (JAR_Metainfo *) it->data;
00177           if (met)
00178             {
00179             if (met->header) PORT_Free (met->header);
00180             if (met->info) PORT_Free (met->info);
00181             PORT_Free (met);
00182             }
00183           break;
00184 
00185        case jarTypePhy:
00186 
00187           phy = (JAR_Physical *) it->data;
00188           if (phy)
00189             PORT_Free (phy);
00190           break;
00191 
00192         case jarTypeSign:
00193 
00194           fing = (JAR_Cert *) it->data;
00195           if (fing)
00196             {
00197             if (fing->cert)
00198               CERT_DestroyCertificate (fing->cert);
00199             if (fing->key)
00200               PORT_Free (fing->key);
00201             PORT_Free (fing);
00202             }
00203          break;
00204 
00205         case jarTypeSect:
00206         case jarTypeMF:
00207         case jarTypeSF:
00208 
00209           dig = (JAR_Digest *) it->data;
00210           if (dig)
00211             {
00212             PORT_Free (dig);
00213             }
00214           break;
00215 
00216         case jarTypeOwner:
00217 
00218           signer = (JAR_Signer *) it->data;
00219 
00220           if (signer)
00221             JAR_destroy_signer (signer);
00222 
00223           break;
00224 
00225         default:
00226 
00227           /* PORT_Assert( 1 != 2 ); */
00228           break;
00229         }
00230 
00231       PORT_Free (it);
00232 
00233     next:
00234 
00235       oldlink = link;
00236       link = link->next;
00237 
00238       ZZ_DestroyLink (oldlink);
00239       }
00240     }
00241   }
00242 
00243 /*
00244  *  J A R _ g e t _ m e t a i n f o
00245  *
00246  *  Retrieve meta information from the manifest file.
00247  *  It doesn't matter whether it's from .MF or .SF, does it?
00248  *
00249  */
00250 
00251 int JAR_get_metainfo
00252     (JAR *jar, char *name, char *header, void **info, unsigned long *length)
00253   {
00254   JAR_Item *it;
00255 
00256   ZZLink *link;
00257   ZZList *list;
00258 
00259   JAR_Metainfo *met;
00260 
00261   PORT_Assert( jar != NULL && header != NULL );
00262 
00263   if (jar == NULL || header == NULL)
00264     return JAR_ERR_PNF;
00265 
00266   list = jar->metainfo;
00267 
00268   if (ZZ_ListEmpty (list))
00269     return JAR_ERR_PNF;
00270 
00271   for (link = ZZ_ListHead (list); 
00272        !ZZ_ListIterDone (list, link); 
00273        link = link->next)
00274     {
00275     it = link->thing;
00276     if (it->type == jarTypeMeta)
00277       {
00278       if ((name && !it->pathname) || (!name && it->pathname))
00279         continue;
00280 
00281       if (name && it->pathname && strcmp (it->pathname, name))
00282         continue;
00283 
00284       met = (JAR_Metainfo *) it->data;
00285 
00286       if (!PORT_Strcasecmp (met->header, header))
00287         {
00288         *info = PORT_Strdup (met->info);
00289         *length = PORT_Strlen (met->info);
00290         return 0;
00291         }
00292       }
00293     }
00294 
00295   return JAR_ERR_PNF;
00296   }
00297 
00298 /*
00299  *  J A R _ f i n d
00300  *
00301  *  Establish the search pattern for use
00302  *  by JAR_find_next, to traverse the filenames
00303  *  or certificates in the JAR structure.
00304  *
00305  *  See jar.h for a description on how to use.
00306  *
00307  */
00308 
00309 JAR_Context *JAR_find (JAR *jar, char *pattern, jarType type)
00310   {
00311   JAR_Context *ctx;
00312 
00313   PORT_Assert( jar != NULL );
00314 
00315   if (!jar)
00316     return NULL;
00317 
00318   ctx = (JAR_Context *) PORT_ZAlloc (sizeof (JAR_Context));
00319 
00320   if (ctx == NULL)
00321     return NULL;
00322 
00323   ctx->jar = jar;
00324 
00325   if (pattern)
00326     {
00327     if ((ctx->pattern = PORT_Strdup (pattern)) == NULL)
00328       {
00329       PORT_Free (ctx);
00330       return NULL;
00331       }
00332     }
00333 
00334   ctx->finding = type;
00335 
00336   switch (type)
00337     {
00338     case jarTypeMF:     ctx->next = ZZ_ListHead (jar->hashes);
00339                         break;
00340 
00341     case jarTypeSF:
00342     case jarTypeSign:   ctx->next = NULL;
00343                         ctx->nextsign = ZZ_ListHead (jar->signers);
00344                         break;
00345 
00346     case jarTypeSect:   ctx->next = ZZ_ListHead (jar->manifest);
00347                         break;
00348 
00349     case jarTypePhy:    ctx->next = ZZ_ListHead (jar->phy);
00350                         break;
00351 
00352     case jarTypeOwner:  if (jar->signers)
00353                           ctx->next = ZZ_ListHead (jar->signers);
00354                         else
00355                           ctx->next = NULL;
00356                         break;
00357 
00358     case jarTypeMeta:   ctx->next = ZZ_ListHead (jar->metainfo);
00359                         break;
00360 
00361     default:            PORT_Assert( 1 != 2);
00362                         break;
00363     }
00364 
00365   return ctx;
00366   }
00367 
00368 /*
00369  *  J A R _ f i n d _ e n d
00370  *
00371  *  Destroy the find iterator context.
00372  *
00373  */
00374 
00375 void JAR_find_end (JAR_Context *ctx)
00376   {
00377   PORT_Assert( ctx != NULL );
00378 
00379   if (ctx)
00380     {
00381     if (ctx->pattern) 
00382       PORT_Free (ctx->pattern);
00383     PORT_Free (ctx);
00384     }
00385   }
00386 
00387 /*
00388  *  J A R _ f i n d _ n e x t
00389  *
00390  *  Return the next item of the given type
00391  *  from one of the JAR linked lists.
00392  *
00393  */
00394 
00395 int JAR_find_next (JAR_Context *ctx, JAR_Item **it)
00396   {
00397   JAR *jar;
00398   ZZList *list = NULL;
00399 
00400   int finding;
00401 
00402   JAR_Signer *signer = NULL;
00403 
00404   PORT_Assert( ctx != NULL );
00405   PORT_Assert( ctx->jar != NULL );
00406 
00407   jar = ctx->jar;
00408 
00409   /* Internally, convert jarTypeSign to jarTypeSF, and return
00410      the actual attached certificate later */
00411 
00412   finding = (ctx->finding == jarTypeSign) ? jarTypeSF : ctx->finding;
00413 
00414   if (ctx->nextsign)
00415     {
00416       if (ZZ_ListIterDone (jar->signers, ctx->nextsign))
00417        {
00418        *it = NULL;
00419        return -1;
00420        }
00421     PORT_Assert (ctx->nextsign->thing != NULL);
00422     signer = (JAR_Signer*)ctx->nextsign->thing->data;
00423     }
00424 
00425 
00426   /* Find out which linked list to traverse. Then if
00427      necessary, advance to the next linked list. */
00428 
00429   while (1)
00430     {
00431     switch (finding)
00432       {
00433       case jarTypeSign:    /* not any more */
00434                            PORT_Assert( finding != jarTypeSign );
00435                            list = signer->certs;
00436                            break;
00437 
00438       case jarTypeSect:    list = jar->manifest;
00439                            break;
00440 
00441       case jarTypePhy:     list = jar->phy;
00442                            break;
00443 
00444       case jarTypeSF:      /* signer, not jar */
00445                            PORT_Assert( signer != NULL );
00446                            list = signer->sf;
00447                            break;
00448 
00449       case jarTypeMF:      list = jar->hashes;
00450                            break;
00451 
00452       case jarTypeOwner:   list = jar->signers;
00453                            break;
00454 
00455       case jarTypeMeta:    list = jar->metainfo;
00456                            break;
00457 
00458       default:             PORT_Assert( 1 != 2 );
00459                            break;
00460       }
00461 
00462     if (list == NULL)
00463       {
00464       *it = NULL;
00465       return -1;
00466       }
00467 
00468     /* When looping over lists of lists, advance
00469        to the next signer. This is done when multiple
00470        signers are possible. */
00471 
00472     if (ZZ_ListIterDone (list, ctx->next))
00473       {
00474       if (ctx->nextsign && jar->signers) 
00475         {
00476         ctx->nextsign = ctx->nextsign->next;
00477         if (!ZZ_ListIterDone (jar->signers, ctx->nextsign)) 
00478           {
00479           PORT_Assert (ctx->nextsign->thing != NULL);
00480 
00481           signer = (JAR_Signer*)ctx->nextsign->thing->data;
00482           PORT_Assert( signer != NULL );
00483 
00484           ctx->next = NULL;
00485           continue;
00486           }
00487         }
00488       *it = NULL;
00489       return -1;
00490       }
00491 
00492     /* if the signer changed, still need to fill
00493        in the "next" link */
00494 
00495     if (ctx->nextsign && ctx->next == NULL)
00496       {
00497       switch (finding)
00498         {
00499         case jarTypeSF:
00500 
00501           ctx->next = ZZ_ListHead (signer->sf);
00502           break;
00503 
00504         case jarTypeSign:
00505 
00506           ctx->next = ZZ_ListHead (signer->certs);
00507           break;
00508         }
00509       }
00510 
00511     PORT_Assert( ctx->next != NULL );
00512 
00513 
00514     while (!ZZ_ListIterDone (list, ctx->next))
00515       {
00516       *it = ctx->next->thing;
00517       ctx->next = ctx->next->next;
00518 
00519       if (!it || !*it || (*it)->type != finding)
00520         continue;
00521 
00522       if (ctx->pattern && *ctx->pattern)
00523         {
00524         if (PORT_Strcmp ((*it)->pathname, ctx->pattern))
00525           continue;
00526         }
00527 
00528       /* We have a valid match. If this is a jarTypeSign
00529          return the certificate instead.. */
00530 
00531       if (ctx->finding == jarTypeSign)
00532         {
00533         JAR_Item *itt;
00534 
00535         /* just the first one for now */
00536         if (jar_find_first_cert (signer, jarTypeSign, &itt) >= 0) 
00537            {
00538            *it = itt;
00539            return 0;
00540            }
00541 
00542         continue;      
00543         }
00544 
00545       return 0;
00546       }
00547 
00548     } /* end while */
00549   }
00550 
00551 static int jar_find_first_cert 
00552     (JAR_Signer *signer, int type, JAR_Item **it)
00553   {
00554   ZZLink *link;
00555   ZZList *list;
00556 
00557   int status = JAR_ERR_PNF;
00558 
00559   list = signer->certs;
00560 
00561   *it = NULL;
00562 
00563   if (ZZ_ListEmpty (list))
00564     {
00565     /* empty list */
00566     return JAR_ERR_PNF;
00567     }
00568 
00569   for (link = ZZ_ListHead (list); 
00570        !ZZ_ListIterDone (list, link); 
00571        link = link->next)
00572     {
00573     if (link->thing->type == type)
00574       {
00575       *it = link->thing;
00576       status = 0;
00577       break;
00578       }
00579     }
00580 
00581   return status;
00582   }
00583 
00584 JAR_Signer *JAR_new_signer (void)
00585   {
00586   JAR_Signer *signer;
00587 
00588   signer = (JAR_Signer *) PORT_ZAlloc (sizeof (JAR_Signer));
00589 
00590   if (signer == NULL)
00591     goto loser;
00592 
00593 
00594   /* certs */
00595   signer->certs = ZZ_NewList();
00596 
00597   if (signer->certs == NULL)
00598     goto loser;
00599 
00600 
00601   /* sf */
00602   signer->sf = ZZ_NewList();
00603 
00604   if (signer->sf == NULL)
00605     goto loser;
00606 
00607 
00608   return signer;
00609 
00610 
00611 loser:
00612 
00613   if (signer)
00614     {
00615     if (signer->certs) 
00616       ZZ_DestroyList (signer->certs);
00617 
00618     if (signer->sf) 
00619       ZZ_DestroyList (signer->sf);
00620 
00621     PORT_Free (signer);
00622     }
00623 
00624   return NULL;
00625   }
00626 
00627 void JAR_destroy_signer (JAR_Signer *signer)
00628   {
00629   if (signer)
00630     {
00631     if (signer->owner) PORT_Free (signer->owner);
00632     if (signer->digest) PORT_Free (signer->digest);
00633 
00634     jar_destroy_list (signer->sf);
00635     ZZ_DestroyList (signer->sf);
00636 
00637     jar_destroy_list (signer->certs);
00638     ZZ_DestroyList (signer->certs);
00639 
00640     PORT_Free (signer);
00641     }
00642   }
00643 
00644 JAR_Signer *jar_get_signer (JAR *jar, char *basename)
00645   {
00646   JAR_Item *it;
00647   JAR_Context *ctx;
00648 
00649   JAR_Signer *candidate;
00650   JAR_Signer *signer = NULL;
00651 
00652   ctx = JAR_find (jar, NULL, jarTypeOwner);
00653 
00654   if (ctx == NULL)
00655     return NULL;
00656 
00657   while (JAR_find_next (ctx, &it) >= 0)
00658     {
00659     candidate = (JAR_Signer *) it->data;
00660     if (*basename == '*' || !PORT_Strcmp (candidate->owner, basename))
00661       {
00662       signer = candidate;
00663       break;
00664       }
00665     }
00666 
00667   JAR_find_end (ctx);
00668 
00669   return signer;
00670   }
00671 
00672 /*
00673  *  J A R _ g e t _ f i l e n a m e
00674  *
00675  *  Returns the filename associated with
00676  *  a JAR structure.
00677  *
00678  */
00679 
00680 char *JAR_get_filename (JAR *jar)
00681   {
00682   return jar->filename;
00683   }
00684 
00685 /*
00686  *  J A R _ g e t _ u r l
00687  *
00688  *  Returns the URL associated with
00689  *  a JAR structure. Nobody really uses this now.
00690  *
00691  */
00692 
00693 char *JAR_get_url (JAR *jar)
00694   {
00695   return jar->url;
00696   }
00697 
00698 /*
00699  *  J A R _ s e t _ c a l l b a c k
00700  *
00701  *  Register some manner of callback function for this jar. 
00702  *
00703  */
00704 
00705 int JAR_set_callback (int type, JAR *jar, 
00706       int (*fn) (int status, JAR *jar, 
00707          const char *metafile, char *pathname, char *errortext))
00708   {
00709   if (type == JAR_CB_SIGNAL)
00710     {
00711     jar->signal = fn;
00712     return 0;
00713     }
00714   else
00715     return -1;
00716   }
00717 
00718 /*
00719  *  Callbacks
00720  *
00721  */
00722 
00723 /* To return an error string */
00724 char *(*jar_fn_GetString) (int) = NULL;
00725 
00726 /* To return an MWContext for Java */
00727 void *(*jar_fn_FindSomeContext) (void) = NULL;
00728 
00729 /* To fabricate an MWContext for FE_GetPassword */
00730 void *(*jar_fn_GetInitContext) (void) = NULL;
00731 
00732 void
00733 JAR_init_callbacks
00734      ( 
00735      char *(*string_cb)(int), 
00736      void *(*find_cx)(void), 
00737      void *(*init_cx)(void) 
00738      )
00739   {
00740   jar_fn_GetString = string_cb;
00741   jar_fn_FindSomeContext = find_cx;
00742   jar_fn_GetInitContext = init_cx;
00743   }
00744 
00745 /*
00746  *  J A R _ g e t _ e r r o r
00747  *
00748  *  This is provided to map internal JAR errors to strings for
00749  *  the Java console. Also, a DLL may call this function if it does
00750  *  not have access to the XP_GetString function.
00751  *
00752  *  These strings aren't UI, since they are Java console only.
00753  *
00754  */
00755 
00756 char *JAR_get_error (int status)
00757   { 
00758   char *errstring = NULL;
00759 
00760   switch (status)
00761     {
00762     case JAR_ERR_GENERAL:
00763       errstring = "General JAR file error";
00764       break;
00765 
00766     case JAR_ERR_FNF:
00767       errstring = "JAR file not found";
00768       break;
00769 
00770     case JAR_ERR_CORRUPT:
00771       errstring = "Corrupt JAR file";
00772       break;
00773 
00774     case JAR_ERR_MEMORY:
00775       errstring = "Out of memory";
00776       break;
00777 
00778     case JAR_ERR_DISK:
00779       errstring = "Disk error (perhaps out of space)";
00780       break;
00781 
00782     case JAR_ERR_ORDER:
00783       errstring = "Inconsistent files in META-INF directory";
00784       break;
00785 
00786     case JAR_ERR_SIG:
00787       errstring = "Invalid digital signature file";
00788       break;
00789 
00790     case JAR_ERR_METADATA:
00791       errstring = "JAR metadata failed verification";
00792       break;
00793 
00794     case JAR_ERR_ENTRY:
00795       errstring = "No Manifest entry for this JAR entry";
00796       break;
00797 
00798     case JAR_ERR_HASH:
00799       errstring = "Invalid Hash of this JAR entry";
00800       break;
00801 
00802     case JAR_ERR_PK7:
00803       errstring = "Strange PKCS7 or RSA failure";
00804       break;
00805 
00806     case JAR_ERR_PNF:
00807       errstring = "Path not found inside JAR file";
00808       break;
00809 
00810     default:
00811       if (jar_fn_GetString)
00812         {
00813         errstring = jar_fn_GetString (status);
00814         }
00815       else
00816         {
00817         /* this is not a normal situation, and would only be
00818            called in cases of improper initialization */
00819 
00820         char *err;
00821 
00822         err = (char*)PORT_Alloc (40);
00823         if (err)
00824           PR_snprintf (err, 39,  "Error %d\n", status);
00825         else
00826           err = "Error! Bad! Out of memory!";
00827 
00828         return err;
00829         }
00830       break;
00831     }
00832 
00833   return errstring;
00834   }