jarver.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:44k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. /*
  34.  *  JARVER
  35.  *
  36.  *  Jarnature Parsing & Verification
  37.  */
  38. #define USE_MOZ_THREAD
  39. #include "jar.h"
  40. #include "jarint.h"
  41. #ifdef USE_MOZ_THREAD
  42. #include "jarevil.h"
  43. #endif
  44. #include "cdbhdl.h"
  45. /* to use huge pointers in win16 */
  46. #if !defined(XP_WIN16)
  47. #define xp_HUGE_MEMCPY PORT_Memcpy
  48. #define xp_HUGE_STRCPY PORT_Strcpy
  49. #define xp_HUGE_STRLEN PORT_Strlen
  50. #define xp_HUGE_STRNCASECMP PORT_Strncasecmp
  51. #else
  52. #define xp_HUGE_MEMCPY hmemcpy
  53. int xp_HUGE_STRNCASECMP (char ZHUGEP *buf, char *key, int len);
  54. size_t xp_HUGE_STRLEN (char ZHUGEP *s);
  55. char *xp_HUGE_STRCPY (char *to, char ZHUGEP *from);
  56. #endif
  57. /* from certdb.h */
  58. #define CERTDB_USER (1<<6)
  59. #if 0
  60. /* from certdb.h */
  61. extern PRBool SEC_CertNicknameConflict
  62.    (char *nickname, CERTCertDBHandle *handle);
  63. /* from certdb.h */
  64. extern SECStatus SEC_AddTempNickname
  65.    (CERTCertDBHandle *handle, char *nickname, SECItem *certKey);
  66. /* from certdb.h */
  67. typedef SECStatus (* PermCertCallback)(CERTCertificate *cert, SECItem *k, void *pdata);
  68. #endif
  69. /* from certdb.h */
  70. SECStatus SEC_TraversePermCerts
  71.    (CERTCertDBHandle *handle, PermCertCallback certfunc, void *udata);
  72. #define SZ 512
  73. static int jar_validate_pkcs7 
  74.      (JAR *jar, JAR_Signer *signer, char *data, long length);
  75. static int jar_decode (JAR *jar, char *data, long length);
  76. static void jar_catch_bytes
  77.      (void *arg, const char *buf, unsigned long len);
  78. static int jar_gather_signers
  79.      (JAR *jar, JAR_Signer *signer, SEC_PKCS7ContentInfo *cinfo);
  80. static char ZHUGEP *jar_eat_line 
  81.      (int lines, int eating, char ZHUGEP *data, long *len);
  82. static JAR_Digest *jar_digest_section 
  83.      (char ZHUGEP *manifest, long length);
  84. static JAR_Digest *jar_get_mf_digest (JAR *jar, char *path);
  85. static int jar_parse_digital_signature 
  86.      (char *raw_manifest, JAR_Signer *signer, long length, JAR *jar);
  87. static int jar_add_cert
  88.      (JAR *jar, JAR_Signer *signer, int type, CERTCertificate *cert);
  89. static CERTCertificate *jar_get_certificate
  90.             (JAR *jar, long keylen, void *key, int *result);
  91. static char *jar_cert_element (char *name, char *tag, int occ);
  92. static char *jar_choose_nickname (CERTCertificate *cert);
  93. static char *jar_basename (const char *path);
  94. static int jar_signal 
  95.      (int status, JAR *jar, const char *metafile, char *pathname);
  96. static int jar_insanity_check (char ZHUGEP *data, long length);
  97. int jar_parse_mf
  98.     (JAR *jar, char ZHUGEP *raw_manifest, 
  99.         long length, const char *path, const char *url);
  100. int jar_parse_sf
  101.     (JAR *jar, char ZHUGEP *raw_manifest, 
  102.         long length, const char *path, const char *url);
  103. int jar_parse_sig
  104.     (JAR *jar, const char *path, char ZHUGEP *raw_manifest, long length);
  105. int jar_parse_any
  106.     (JAR *jar, int type, JAR_Signer *signer, char ZHUGEP *raw_manifest, 
  107.         long length, const char *path, const char *url);
  108. static int jar_internal_digest 
  109.      (JAR *jar, const char *path, char *x_name, JAR_Digest *dig);
  110. /*
  111.  *  J A R _ p a r s e _ m a n i f e s t
  112.  * 
  113.  *  Pass manifest files to this function. They are
  114.  *  decoded and placed into internal representations.
  115.  * 
  116.  *  Accepts both signature and manifest files. Use
  117.  *  the same "jar" for both. 
  118.  *
  119.  */
  120. int JAR_parse_manifest 
  121.     (JAR *jar, char ZHUGEP *raw_manifest, 
  122.         long length, const char *path, const char *url)
  123.   {
  124. #if defined(XP_WIN16)
  125.     PORT_Assert( !IsBadHugeReadPtr(raw_manifest, length) );
  126. #endif
  127.   /* fill in the path, if supplied. This is a the location
  128.      of the jar file on disk, if known */
  129.   if (jar->filename == NULL && path)
  130.     {
  131.     jar->filename = PORT_Strdup (path);
  132.     if (jar->filename == NULL)
  133.       return JAR_ERR_MEMORY;
  134.     }
  135.   /* fill in the URL, if supplied. This is the place
  136.      from which the jar file was retrieved. */
  137.   if (jar->url == NULL && url)
  138.     {
  139.     jar->url = PORT_Strdup (url);
  140.     if (jar->url == NULL)
  141.       return JAR_ERR_MEMORY;
  142.     }
  143.   /* Determine what kind of file this is from the META-INF 
  144.      directory. It could be MF, SF, or a binary RSA/DSA file */
  145.   if (!xp_HUGE_STRNCASECMP (raw_manifest, "Manifest-Version:", 17))
  146.     {
  147.     return jar_parse_mf (jar, raw_manifest, length, path, url);
  148.     }
  149.   else if (!xp_HUGE_STRNCASECMP (raw_manifest, "Signature-Version:", 18))
  150.     {
  151.     return jar_parse_sf (jar, raw_manifest, length, path, url);
  152.     }
  153.   else
  154.     {
  155.     /* This is probably a binary signature */
  156.     return jar_parse_sig (jar, path, raw_manifest, length);
  157.     }
  158.   }
  159. /*
  160.  *  j a r _ p a r s e _ s i g
  161.  *
  162.  *  Pass some manner of RSA or DSA digital signature
  163.  *  on, after checking to see if it comes at an appropriate state.
  164.  *
  165.  */
  166.  
  167. int jar_parse_sig
  168.     (JAR *jar, const char *path, char ZHUGEP *raw_manifest, long length)
  169.   {
  170.   JAR_Signer *signer;
  171.   int status = JAR_ERR_ORDER;
  172.   if (length <= 128) 
  173.     {
  174.     /* signature is way too small */
  175.     return JAR_ERR_SIG;
  176.     }
  177.   /* make sure that MF and SF have already been processed */
  178.   if (jar->globalmeta == NULL)
  179.     return JAR_ERR_ORDER;
  180. #if 0
  181.   /* XXX Turn this on to disable multiple signers */
  182.   if (jar->digest == NULL)
  183.     return JAR_ERR_ORDER;
  184. #endif
  185.   /* Determine whether or not this RSA file has
  186.      has an associated SF file */
  187.   if (path)
  188.     {
  189.     char *owner;
  190.     owner = jar_basename (path);
  191.     if (owner == NULL)
  192.       return JAR_ERR_MEMORY;
  193.     signer = jar_get_signer (jar, owner);
  194.     PORT_Free (owner);
  195.     }
  196.   else
  197.     signer = jar_get_signer (jar, "*");
  198.   if (signer == NULL)
  199.     return JAR_ERR_ORDER;
  200.   /* Do not pass a huge pointer to this function,
  201.      since the underlying security code is unaware. We will
  202.      never pass >64k through here. */
  203.   if (length > 64000)
  204.     {
  205.     /* this digital signature is way too big */
  206.     return JAR_ERR_SIG;
  207.     }
  208. #ifdef XP_WIN16
  209.   /*
  210.    * For Win16, copy the portion of the raw_buffer containing the digital 
  211.    * signature into another buffer...  This insures that the data will
  212.    * NOT cross a segment boundary.  Therefore, 
  213.    * jar_parse_digital_signature(...) does NOT need to deal with HUGE 
  214.    * pointers...
  215.    */
  216.     {
  217.     unsigned char *manifest_copy;
  218.     manifest_copy = (unsigned char *) PORT_ZAlloc (length);
  219.     if (manifest_copy)
  220.       {
  221.       xp_HUGE_MEMCPY (manifest_copy, raw_manifest, length);
  222.       status = jar_parse_digital_signature 
  223.                   (manifest_copy, signer, length, jar);
  224.       PORT_Free (manifest_copy);
  225.       }
  226.     else
  227.       {
  228.       /* out of memory */
  229.       return JAR_ERR_MEMORY;
  230.       }
  231.     }
  232. #else
  233.   /* don't expense unneeded calloc overhead on non-win16 */
  234.   status = jar_parse_digital_signature 
  235.                 (raw_manifest, signer, length, jar);
  236. #endif
  237.   return status;
  238.   }
  239. /*
  240.  *  j a r _ p a r s e _ m f
  241.  *
  242.  *  Parse the META-INF/manifest.mf file, whose
  243.  *  information applies to all signers.
  244.  *
  245.  */
  246. int jar_parse_mf
  247.     (JAR *jar, char ZHUGEP *raw_manifest, 
  248.         long length, const char *path, const char *url)
  249.   {
  250.   if (jar->globalmeta)
  251.     {
  252.     /* refuse a second manifest file, if passed for some reason */
  253.     return JAR_ERR_ORDER;
  254.     }
  255.   /* remember a digest for the global section */
  256.   jar->globalmeta = jar_digest_section (raw_manifest, length);
  257.   if (jar->globalmeta == NULL)
  258.     return JAR_ERR_MEMORY;
  259.   return jar_parse_any 
  260.     (jar, jarTypeMF, NULL, raw_manifest, length, path, url);
  261.   }
  262. /*
  263.  *  j a r _ p a r s e _ s f
  264.  *
  265.  *  Parse META-INF/xxx.sf, a digitally signed file
  266.  *  pointing to a subset of MF sections. 
  267.  *
  268.  */
  269. int jar_parse_sf
  270.     (JAR *jar, char ZHUGEP *raw_manifest, 
  271.         long length, const char *path, const char *url)
  272.   {
  273.   JAR_Signer *signer = NULL;
  274.   int status = JAR_ERR_MEMORY;
  275.   if (jar->globalmeta == NULL)
  276.     {
  277.     /* It is a requirement that the MF file be passed before the SF file */
  278.     return JAR_ERR_ORDER;
  279.     }
  280.   signer = JAR_new_signer();
  281.   if (signer == NULL)
  282.     goto loser;
  283.   if (path)
  284.     {
  285.     signer->owner = jar_basename (path);
  286.     if (signer->owner == NULL)
  287.       goto loser;
  288.     }
  289.   /* check for priors. When someone doctors a jar file
  290.      to contain identical path entries, prevent the second
  291.      one from affecting JAR functions */
  292.   if (jar_get_signer (jar, signer->owner))
  293.     {
  294.     /* someone is trying to spoof us */
  295.     status = JAR_ERR_ORDER;
  296.     goto loser;
  297.     }
  298.   /* remember its digest */
  299.   signer->digest = JAR_calculate_digest (raw_manifest, length);
  300.   if (signer->digest == NULL)
  301.     goto loser;
  302.   /* Add this signer to the jar */
  303.   ADDITEM (jar->signers, jarTypeOwner, 
  304.      signer->owner, signer, sizeof (JAR_Signer));
  305.   return jar_parse_any 
  306.     (jar, jarTypeSF, signer, raw_manifest, length, path, url);
  307. loser:
  308.   if (signer)
  309.     JAR_destroy_signer (signer);
  310.   return status;
  311.   }
  312. /* 
  313.  *  j a r _ p a r s e _ a n y
  314.  *
  315.  *  Parse a MF or SF manifest file. 
  316.  *
  317.  */
  318.  
  319. int jar_parse_any
  320.     (JAR *jar, int type, JAR_Signer *signer, char ZHUGEP *raw_manifest, 
  321.         long length, const char *path, const char *url)
  322.   {
  323.   int status;
  324.   long raw_len;
  325.   JAR_Digest *dig, *mfdig = NULL;
  326.   char line [SZ];
  327.   char x_name [SZ], x_md5 [SZ], x_sha [SZ];
  328.   char *x_info;
  329.   char *sf_md5 = NULL, *sf_sha1 = NULL;
  330.   *x_name = 0;
  331.   *x_md5 = 0;
  332.   *x_sha = 0;
  333.   PORT_Assert( length > 0 );
  334.   raw_len = length;
  335. #ifdef DEBUG
  336.   if ((status = jar_insanity_check (raw_manifest, raw_len)) < 0)
  337.     return status;
  338. #endif
  339.   /* null terminate the first line */
  340.   raw_manifest = jar_eat_line (0, PR_TRUE, raw_manifest, &raw_len);
  341.   /* skip over the preliminary section */
  342.   /* This is one section at the top of the file with global metainfo */
  343.   while (raw_len)
  344.     {
  345.     JAR_Metainfo *met;
  346.     raw_manifest = jar_eat_line (1, PR_TRUE, raw_manifest, &raw_len);
  347.     if (!*raw_manifest) break;
  348.     met = (JAR_Metainfo*)PORT_ZAlloc (sizeof (JAR_Metainfo));
  349.     if (met == NULL)
  350.       return JAR_ERR_MEMORY;
  351.     /* Parse out the header & info */
  352.     if (xp_HUGE_STRLEN (raw_manifest) >= SZ)
  353.       {
  354.       /* almost certainly nonsense */
  355.       continue;
  356.       }
  357.     xp_HUGE_STRCPY (line, raw_manifest);
  358.     x_info = line;
  359.     while (*x_info && *x_info != ' ' && *x_info != 't' && *x_info != ':')
  360.       x_info++;
  361.     if (*x_info) *x_info++ = 0;
  362.     while (*x_info == ' ' || *x_info == 't')
  363.       x_info++;
  364.     /* metainfo (name, value) pair is now (line, x_info) */
  365.     met->header = PORT_Strdup (line);
  366.     met->info = PORT_Strdup (x_info);
  367.     if (type == jarTypeMF)
  368.       {
  369.       ADDITEM (jar->metainfo, jarTypeMeta, 
  370.          /* pathname */ NULL, met, sizeof (JAR_Metainfo));
  371.       }
  372.     /* For SF files, this metadata may be the digests
  373.        of the MF file, still in the "met" structure. */
  374.     if (type == jarTypeSF)
  375.       {
  376.       if (!PORT_Strcasecmp (line, "MD5-Digest"))
  377.         sf_md5 = (char *) met->info;
  378.       if (!PORT_Strcasecmp (line, "SHA1-Digest") || !PORT_Strcasecmp (line, "SHA-Digest"))
  379.         sf_sha1 = (char *) met->info;
  380.       }
  381.     }
  382.   if (type == jarTypeSF && jar->globalmeta)
  383.     {
  384.     /* this is a SF file which may contain a digest of the manifest.mf's 
  385.        global metainfo. */
  386.     int match = 0;
  387.     JAR_Digest *glob = jar->globalmeta;
  388.     if (sf_md5)
  389.       {
  390.       unsigned int md5_length;
  391.       unsigned char *md5_digest;
  392.       md5_digest = ATOB_AsciiToData (sf_md5, &md5_length);
  393.       PORT_Assert( md5_length == MD5_LENGTH );
  394.       if (md5_length != MD5_LENGTH)
  395.         return JAR_ERR_CORRUPT;
  396.       match = PORT_Memcmp (md5_digest, glob->md5, MD5_LENGTH);
  397.       }
  398.     if (sf_sha1 && match == 0)
  399.       {
  400.       unsigned int sha1_length;
  401.       unsigned char *sha1_digest;
  402.       sha1_digest = ATOB_AsciiToData (sf_sha1, &sha1_length);
  403.       PORT_Assert( sha1_length == SHA1_LENGTH );
  404.       if (sha1_length != SHA1_LENGTH)
  405.         return JAR_ERR_CORRUPT;
  406.       match = PORT_Memcmp (sha1_digest, glob->sha1, SHA1_LENGTH);
  407.       }
  408.     if (match != 0)
  409.       {
  410.       /* global digest doesn't match, SF file therefore invalid */
  411.       jar->valid = JAR_ERR_METADATA;
  412.       return JAR_ERR_METADATA;
  413.       }
  414.     }
  415.   /* done with top section of global data */
  416.   while (raw_len)
  417.     {
  418.     *x_md5 = 0;
  419.     *x_sha = 0;
  420.     *x_name = 0;
  421.     /* If this is a manifest file, attempt to get a digest of the following section, 
  422.        without damaging it. This digest will be saved later. */
  423.     if (type == jarTypeMF)
  424.       {
  425.       char ZHUGEP *sec;
  426.       long sec_len = raw_len;
  427.       if (!*raw_manifest || *raw_manifest == 'n')
  428.         {     
  429.         /* skip the blank line */ 
  430.         sec = jar_eat_line (1, PR_FALSE, raw_manifest, &sec_len);
  431.         }
  432.       else
  433.         sec = raw_manifest;
  434.       if (!xp_HUGE_STRNCASECMP (sec, "Name:", 5))
  435.         {
  436.         if (type == jarTypeMF)
  437.           mfdig = jar_digest_section (sec, sec_len);
  438.         else
  439.           mfdig = NULL;
  440.         }
  441.       }
  442.     while (raw_len)
  443.       {
  444.       raw_manifest = jar_eat_line (1, PR_TRUE, raw_manifest, &raw_len);
  445.       if (!*raw_manifest) break; /* blank line, done with this entry */
  446.       if (xp_HUGE_STRLEN (raw_manifest) >= SZ)
  447.         {
  448.         /* almost certainly nonsense */
  449.         continue;
  450.         }
  451.       /* Parse out the name/value pair */
  452.       xp_HUGE_STRCPY (line, raw_manifest);
  453.       x_info = line;
  454.       while (*x_info && *x_info != ' ' && *x_info != 't' && *x_info != ':')
  455.         x_info++;
  456.       if (*x_info) *x_info++ = 0;
  457.       while (*x_info == ' ' || *x_info == 't') 
  458.         x_info++;
  459.       if (!PORT_Strcasecmp (line, "Name"))
  460.         PORT_Strcpy (x_name, x_info);
  461.       else if (!PORT_Strcasecmp (line, "MD5-Digest"))
  462.         PORT_Strcpy (x_md5, x_info);
  463.       else if (!PORT_Strcasecmp (line, "SHA1-Digest") 
  464.                   || !PORT_Strcasecmp (line, "SHA-Digest"))
  465.         {
  466.         PORT_Strcpy (x_sha, x_info);
  467.         }
  468.       /* Algorithm list is meta info we don't care about; keeping it out
  469.          of metadata saves significant space for large jar files */
  470.       else if (!PORT_Strcasecmp (line, "Digest-Algorithms")
  471.                     || !PORT_Strcasecmp (line, "Hash-Algorithms"))
  472.         {
  473.         continue;
  474.         }
  475.       /* Meta info is only collected for the manifest.mf file,
  476.          since the JAR_get_metainfo call does not support identity */
  477.       else if (type == jarTypeMF)
  478.         {
  479.         JAR_Metainfo *met;
  480.         /* this is meta-data */
  481.         met = (JAR_Metainfo*)PORT_ZAlloc (sizeof (JAR_Metainfo));
  482.         if (met == NULL)
  483.           return JAR_ERR_MEMORY;
  484.         /* metainfo (name, value) pair is now (line, x_info) */
  485.         if ((met->header = PORT_Strdup (line)) == NULL)
  486.           return JAR_ERR_MEMORY;
  487.         if ((met->info = PORT_Strdup (x_info)) == NULL)
  488.           return JAR_ERR_MEMORY;
  489.         ADDITEM (jar->metainfo, jarTypeMeta, 
  490.            x_name, met, sizeof (JAR_Metainfo));
  491.         }
  492.       }
  493. if(!x_name || !*x_name) {
  494. /* Whatever that was, it wasn't an entry, because we didn't get a name.
  495.  * We don't really have anything, so don't record this. */
  496. continue;
  497. }
  498.     dig = (JAR_Digest*)PORT_ZAlloc (sizeof (JAR_Digest));
  499.     if (dig == NULL)
  500.       return JAR_ERR_MEMORY;
  501.     if (*x_md5 ) 
  502.       {
  503.       unsigned int binary_length;
  504.       unsigned char *binary_digest;
  505.       binary_digest = ATOB_AsciiToData (x_md5, &binary_length);
  506.       PORT_Assert( binary_length == MD5_LENGTH );
  507.       if (binary_length != MD5_LENGTH)
  508.         return JAR_ERR_CORRUPT;
  509.       memcpy (dig->md5, binary_digest, MD5_LENGTH);
  510.       dig->md5_status = jarHashPresent;
  511.       }
  512.     if (*x_sha ) 
  513.       {
  514.       unsigned int binary_length;
  515.       unsigned char *binary_digest;
  516.       binary_digest = ATOB_AsciiToData (x_sha, &binary_length);
  517.       PORT_Assert( binary_length == SHA1_LENGTH );
  518.       if (binary_length != SHA1_LENGTH)
  519.         return JAR_ERR_CORRUPT;
  520.       memcpy (dig->sha1, binary_digest, SHA1_LENGTH);
  521.       dig->sha1_status = jarHashPresent;
  522.       }
  523.     PORT_Assert( type == jarTypeMF || type == jarTypeSF );
  524.     if (type == jarTypeMF)
  525.       {
  526.       ADDITEM (jar->hashes, jarTypeMF, x_name, dig, sizeof (JAR_Digest));
  527.       }
  528.     else if (type == jarTypeSF)
  529.       {
  530.       ADDITEM (signer->sf, jarTypeSF, x_name, dig, sizeof (JAR_Digest));
  531.       }
  532.     else
  533.       return JAR_ERR_ORDER;
  534.     /* we're placing these calculated digests of manifest.mf 
  535.        sections in a list where they can subsequently be forgotten */
  536.     if (type == jarTypeMF && mfdig)
  537.       {
  538.       ADDITEM (jar->manifest, jarTypeSect, 
  539.          x_name, mfdig, sizeof (JAR_Digest));
  540.       mfdig = NULL;
  541.       }
  542.     /* Retrieve our saved SHA1 digest from saved copy and check digests.
  543.        This is just comparing the digest of the MF section as indicated in
  544.        the SF file with the one we remembered from parsing the MF file */
  545.     if (type == jarTypeSF)
  546.       {
  547.       if ((status = jar_internal_digest (jar, path, x_name, dig)) < 0)
  548.         return status;
  549.       }
  550.     }
  551.   return 0;
  552.   }
  553. static int jar_internal_digest 
  554.      (JAR *jar, const char *path, char *x_name, JAR_Digest *dig)
  555.   {
  556.   int cv;
  557.   int status;
  558.   JAR_Digest *savdig;
  559.   savdig = jar_get_mf_digest (jar, x_name);
  560.   if (savdig == NULL)
  561.     {
  562.     /* no .mf digest for this pathname */
  563.     status = jar_signal (JAR_ERR_ENTRY, jar, path, x_name);
  564.     if (status < 0) 
  565.       return 0; /* was continue; */
  566.     else 
  567.       return status;
  568.     }
  569.   /* check for md5 consistency */
  570.   if (dig->md5_status)
  571.     {
  572.     cv = PORT_Memcmp (savdig->md5, dig->md5, MD5_LENGTH);
  573.     /* md5 hash of .mf file is not what expected */
  574.     if (cv) 
  575.       {
  576.       status = jar_signal (JAR_ERR_HASH, jar, path, x_name);
  577.       /* bad hash, man */
  578.       dig->md5_status = jarHashBad;
  579.       savdig->md5_status = jarHashBad;
  580.       if (status < 0) 
  581.         return 0; /* was continue; */
  582.       else 
  583.         return status;
  584.       }
  585.     }
  586.   /* check for sha1 consistency */
  587.   if (dig->sha1_status)
  588.     {
  589.     cv = PORT_Memcmp (savdig->sha1, dig->sha1, SHA1_LENGTH);
  590.     /* sha1 hash of .mf file is not what expected */
  591.     if (cv) 
  592.       {
  593.       status = jar_signal (JAR_ERR_HASH, jar, path, x_name);
  594.       /* bad hash, man */
  595.       dig->sha1_status = jarHashBad;
  596.       savdig->sha1_status = jarHashBad;
  597.       if (status < 0)
  598.         return 0; /* was continue; */
  599.       else
  600.         return status;
  601.       }
  602.     }
  603. return 0;
  604.   }
  605. #ifdef DEBUG
  606. /*
  607.  *  j a r _ i n s a n i t y _ c h e c k
  608.  *
  609.  *  Check for illegal characters (or possibly so)
  610.  *  in the manifest files, to detect potential memory
  611.  *  corruption by our neighbors. Debug only, since
  612.  *  not I18N safe.
  613.  * 
  614.  */
  615. static int jar_insanity_check (char ZHUGEP *data, long length)
  616.   {
  617.   int c;
  618.   long off;
  619.   for (off = 0; off < length; off++)
  620.     {
  621.     c = data [off];
  622.     if (c == 'n' || c == 'r' || (c >= ' ' && c <= 128))
  623.       continue;
  624.     return JAR_ERR_CORRUPT;
  625.     }
  626.   return 0;
  627.   }
  628. #endif
  629. /*
  630.  *  j a r _ p a r s e _ d i g i t a l _ s i g n a t u r e
  631.  *
  632.  *  Parse an RSA or DSA (or perhaps other) digital signature.
  633.  *  Right now everything is PKCS7.
  634.  *
  635.  */
  636. static int jar_parse_digital_signature 
  637.      (char *raw_manifest, JAR_Signer *signer, long length, JAR *jar)
  638.   {
  639. #if defined(XP_WIN16)
  640.   PORT_Assert( LOWORD(raw_manifest) + length < 0xFFFF );
  641. #endif
  642.   return jar_validate_pkcs7 (jar, signer, raw_manifest, length);
  643.   }
  644. /*
  645.  *  j a r _ a d d _ c e r t
  646.  * 
  647.  *  Add information for the given certificate
  648.  *  (or whatever) to the JAR linked list. A pointer
  649.  *  is passed for some relevant reference, say
  650.  *  for example the original certificate.
  651.  *
  652.  */
  653. static int jar_add_cert
  654.      (JAR *jar, JAR_Signer *signer, int type, CERTCertificate *cert)
  655.   {
  656.   JAR_Cert *fing;
  657.   if (cert == NULL)
  658.     return JAR_ERR_ORDER;
  659.   fing = (JAR_Cert*)PORT_ZAlloc (sizeof (JAR_Cert));
  660.   if (fing == NULL)
  661.     goto loser;
  662. #ifdef USE_MOZ_THREAD
  663.   fing->cert = jar_moz_dup (cert);
  664. #else
  665.   fing->cert = CERT_DupCertificate (cert);
  666. #endif
  667.   /* get the certkey */
  668.   fing->length = cert->certKey.len;
  669.   fing->key = (char *) PORT_ZAlloc (fing->length);
  670.   if (fing->key == NULL)
  671.     goto loser;
  672.   PORT_Memcpy (fing->key, cert->certKey.data, fing->length);
  673.   ADDITEM (signer->certs, type, 
  674.     /* pathname */ NULL, fing, sizeof (JAR_Cert));
  675.   return 0;
  676. loser:
  677.   if (fing)
  678.     {
  679.     if (fing->cert) 
  680.       CERT_DestroyCertificate (fing->cert);
  681.     PORT_Free (fing);
  682.     }
  683.   return JAR_ERR_MEMORY;
  684.   }
  685. /*
  686.  *  e a t _ l i n e 
  687.  *
  688.  *  Consume an ascii line from the top of a file kept
  689.  *  in memory. This destroys the file in place. This function
  690.  *  handles PC, Mac, and Unix style text files.
  691.  *
  692.  */
  693. static char ZHUGEP *jar_eat_line 
  694.     (int lines, int eating, char ZHUGEP *data, long *len)
  695.   {
  696.   char ZHUGEP *ret;
  697.   ret = data;
  698.   if (!*len) return ret;
  699.   /* Eat the requisite number of lines, if any; 
  700.      prior to terminating the current line with a 0. */
  701.   for (/* yip */ ; lines; lines--)
  702.     {
  703.     while (*data && *data != 'n')
  704.       data++;
  705.     /* After the CR, ok to eat one LF */
  706.     if (*data == 'n')
  707.       data++;
  708.     /* If there are zeros, we put them there */
  709.     while (*data == 0 && data - ret < *len)
  710.       data++;
  711.     }
  712.   *len -= data - ret;
  713.   ret = data;
  714.   if (eating)
  715.     {
  716.     /* Terminate this line with a 0 */ 
  717.     while (*data && *data != 'n' && *data != 'r')
  718.       data++;
  719.     /* In any case we are allowed to eat CR */
  720.     if (*data == 'r')
  721.       *data++ = 0;
  722.     /* After the CR, ok to eat one LF */
  723.     if (*data == 'n')
  724.       *data++ = 0;
  725.     }
  726.   return ret;
  727.   }
  728. /*
  729.  *  j a r _ d i g e s t _ s e c t i o n
  730.  *
  731.  *  Return the digests of the next section of the manifest file.
  732.  *  Does not damage the manifest file, unlike parse_manifest.
  733.  * 
  734.  */
  735. static JAR_Digest *jar_digest_section 
  736.     (char ZHUGEP *manifest, long length)
  737.   {
  738.   long global_len;
  739.   char ZHUGEP *global_end;
  740.   global_end = manifest;
  741.   global_len = length;
  742.   while (global_len)
  743.     {
  744.     global_end = jar_eat_line (1, PR_FALSE, global_end, &global_len);
  745.     if (*global_end == 0 || *global_end == 'n')
  746.       break;
  747.     }
  748.   return JAR_calculate_digest (manifest, global_end - manifest);
  749.   }
  750. /*
  751.  *  J A R _ v e r i f y _ d i g e s t
  752.  *
  753.  *  Verifies that a precalculated digest matches the
  754.  *  expected value in the manifest.
  755.  *
  756.  */
  757. int PR_CALLBACK JAR_verify_digest
  758.     (JAR *jar, const char *name, JAR_Digest *dig)
  759.   {
  760.   JAR_Item *it;
  761.   JAR_Digest *shindig;
  762.   ZZLink *link;
  763.   ZZList *list;
  764.   int result1, result2;
  765.   list = jar->hashes;
  766.   result1 = result2 = 0;
  767.   if (jar->valid < 0)
  768.     {
  769.     /* signature not valid */
  770.     return JAR_ERR_SIG;
  771.     }
  772.   if (ZZ_ListEmpty (list))
  773.     {
  774.     /* empty list */
  775.     return JAR_ERR_PNF;
  776.     }
  777.   for (link = ZZ_ListHead (list); 
  778.        !ZZ_ListIterDone (list, link); 
  779.        link = link->next)
  780.     {
  781.     it = link->thing;
  782.     if (it->type == jarTypeMF 
  783.            && it->pathname && !PORT_Strcmp (it->pathname, name))
  784.       {
  785.       shindig = (JAR_Digest *) it->data;
  786.       if (shindig->md5_status)
  787.         {
  788.         if (shindig->md5_status == jarHashBad)
  789.           return JAR_ERR_HASH;
  790.         else
  791.           result1 = memcmp (dig->md5, shindig->md5, MD5_LENGTH);
  792.         }
  793.       if (shindig->sha1_status)
  794.         {
  795.         if (shindig->sha1_status == jarHashBad)
  796.           return JAR_ERR_HASH;
  797.         else
  798.           result2 = memcmp (dig->sha1, shindig->sha1, SHA1_LENGTH);
  799.         }
  800.       return (result1 == 0 && result2 == 0) ? 0 : JAR_ERR_HASH;
  801.       }
  802.     }
  803.   return JAR_ERR_PNF;
  804.   }
  805. /* 
  806.  *  J A R _ c e r t _ a t t r i b u t e
  807.  *
  808.  *  Return the named certificate attribute from the
  809.  *  certificate specified by the given key.
  810.  *
  811.  */
  812. int PR_CALLBACK JAR_cert_attribute
  813.     (JAR *jar, jarCert attrib, long keylen, void *key, 
  814.         void **result, unsigned long *length)
  815.   {
  816.   int status = 0;
  817.   char *ret = NULL;
  818.   CERTCertificate *cert;
  819.   CERTCertDBHandle *certdb;
  820.   JAR_Digest *dig;
  821.   SECItem hexme;
  822.   *length = 0;
  823.   if (attrib == 0 || key == 0)
  824.     return JAR_ERR_GENERAL;
  825.   if (attrib == jarCertJavaHack)
  826.     {
  827.     cert = (CERTCertificate *) NULL;
  828.     certdb = JAR_open_database();
  829.     if (certdb)
  830.       {
  831. #ifdef USE_MOZ_THREAD
  832.       cert = jar_moz_nickname (certdb, (char*)key);
  833. #else
  834.       cert = CERT_FindCertByNickname (certdb, key);
  835. #endif
  836.       if (cert)
  837.         {
  838.         *length = cert->certKey.len;
  839.         *result = (void *) PORT_ZAlloc (*length);
  840.         if (*result)
  841.           PORT_Memcpy (*result, cert->certKey.data, *length);
  842.         else
  843.           return JAR_ERR_MEMORY;
  844.         }
  845.       JAR_close_database (certdb);
  846.       }
  847.     return cert ? 0 : JAR_ERR_GENERAL;
  848.     }
  849.   if (jar && jar->pkcs7 == 0)
  850.     return JAR_ERR_GENERAL;
  851.   cert = jar_get_certificate (jar, keylen, key, &status);
  852.   if (cert == NULL || status < 0)
  853.     return JAR_ERR_GENERAL;
  854. #define SEP " <br> "
  855. #define SEPLEN (PORT_Strlen(SEP))
  856.   switch (attrib)
  857.     {
  858.     case jarCertCompany:
  859.       ret = cert->subjectName;
  860.       /* This is pretty ugly looking but only used
  861.          here for this one purpose. */
  862.       if (ret)
  863.         {
  864.         int retlen = 0;
  865.         char *cer_ou1, *cer_ou2, *cer_ou3;
  866. char *cer_cn, *cer_e, *cer_o, *cer_l;
  867. cer_cn  = CERT_GetCommonName (&cert->subject);
  868.         cer_e   = CERT_GetCertEmailAddress (&cert->subject);
  869.         cer_ou3 = jar_cert_element (ret, "OU=", 3);
  870.         cer_ou2 = jar_cert_element (ret, "OU=", 2);
  871.         cer_ou1 = jar_cert_element (ret, "OU=", 1);
  872.         cer_o   = CERT_GetOrgName (&cert->subject);
  873.         cer_l   = CERT_GetCountryName (&cert->subject);
  874.         if (cer_cn)  retlen += SEPLEN + PORT_Strlen (cer_cn);
  875.         if (cer_e)   retlen += SEPLEN + PORT_Strlen (cer_e);
  876.         if (cer_ou1) retlen += SEPLEN + PORT_Strlen (cer_ou1);
  877.         if (cer_ou2) retlen += SEPLEN + PORT_Strlen (cer_ou2);
  878.         if (cer_ou3) retlen += SEPLEN + PORT_Strlen (cer_ou3);
  879.         if (cer_o)   retlen += SEPLEN + PORT_Strlen (cer_o);
  880.         if (cer_l)   retlen += SEPLEN + PORT_Strlen (cer_l);
  881.         ret = (char *) PORT_ZAlloc (1 + retlen);
  882.         if (cer_cn)  { PORT_Strcpy (ret, cer_cn);  PORT_Strcat (ret, SEP); }
  883.         if (cer_e)   { PORT_Strcat (ret, cer_e);   PORT_Strcat (ret, SEP); }
  884.         if (cer_ou1) { PORT_Strcat (ret, cer_ou1); PORT_Strcat (ret, SEP); }
  885.         if (cer_ou2) { PORT_Strcat (ret, cer_ou2); PORT_Strcat (ret, SEP); }
  886.         if (cer_ou3) { PORT_Strcat (ret, cer_ou3); PORT_Strcat (ret, SEP); }
  887.         if (cer_o)   { PORT_Strcat (ret, cer_o);   PORT_Strcat (ret, SEP); }
  888.         if (cer_l)     PORT_Strcat (ret, cer_l);
  889. /* return here to avoid unsightly memory leak */
  890.         *result = ret;
  891.         *length = PORT_Strlen (ret);
  892.         return 0;
  893.         }
  894.       break;
  895.     case jarCertCA:
  896.       ret = cert->issuerName;
  897.       if (ret)
  898.         {
  899.         int retlen = 0;
  900.         char *cer_ou1, *cer_ou2, *cer_ou3;
  901. char *cer_cn, *cer_e, *cer_o, *cer_l;
  902.         /* This is pretty ugly looking but only used
  903.            here for this one purpose. */
  904. cer_cn  = CERT_GetCommonName (&cert->issuer);
  905.         cer_e   = CERT_GetCertEmailAddress (&cert->issuer);
  906.         cer_ou3 = jar_cert_element (ret, "OU=", 3);
  907.         cer_ou2 = jar_cert_element (ret, "OU=", 2);
  908.         cer_ou1 = jar_cert_element (ret, "OU=", 1);
  909.         cer_o   = CERT_GetOrgName (&cert->issuer);
  910.         cer_l   = CERT_GetCountryName (&cert->issuer);
  911.         if (cer_cn)  retlen += SEPLEN + PORT_Strlen (cer_cn);
  912.         if (cer_e)   retlen += SEPLEN + PORT_Strlen (cer_e);
  913.         if (cer_ou1) retlen += SEPLEN + PORT_Strlen (cer_ou1);
  914.         if (cer_ou2) retlen += SEPLEN + PORT_Strlen (cer_ou2);
  915.         if (cer_ou3) retlen += SEPLEN + PORT_Strlen (cer_ou3);
  916.         if (cer_o)   retlen += SEPLEN + PORT_Strlen (cer_o);
  917.         if (cer_l)   retlen += SEPLEN + PORT_Strlen (cer_l);
  918.         ret = (char *) PORT_ZAlloc (1 + retlen);
  919.         if (cer_cn)  { PORT_Strcpy (ret, cer_cn);  PORT_Strcat (ret, SEP); }
  920.         if (cer_e)   { PORT_Strcat (ret, cer_e);   PORT_Strcat (ret, SEP); }
  921.         if (cer_ou1) { PORT_Strcat (ret, cer_ou1); PORT_Strcat (ret, SEP); }
  922.         if (cer_ou2) { PORT_Strcat (ret, cer_ou2); PORT_Strcat (ret, SEP); }
  923.         if (cer_ou3) { PORT_Strcat (ret, cer_ou3); PORT_Strcat (ret, SEP); }
  924.         if (cer_o)   { PORT_Strcat (ret, cer_o);   PORT_Strcat (ret, SEP); }
  925.         if (cer_l)     PORT_Strcat (ret, cer_l);
  926. /* return here to avoid unsightly memory leak */
  927.         *result = ret;
  928.         *length = PORT_Strlen (ret);
  929.         return 0;
  930.         }
  931.       break;
  932.     case jarCertSerial:
  933.       ret = CERT_Hexify (&cert->serialNumber, 1);
  934.       break;
  935.     case jarCertExpires:
  936.       ret = DER_UTCDayToAscii (&cert->validity.notAfter);
  937.       break;
  938.     case jarCertNickname:
  939.       ret = jar_choose_nickname (cert);
  940.       break;
  941.     case jarCertFinger:
  942.       dig = JAR_calculate_digest 
  943.          ((char *) cert->derCert.data, cert->derCert.len);
  944.       if (dig)
  945.         {
  946.         hexme.len = sizeof (dig->md5);
  947.         hexme.data = dig->md5;
  948.         ret = CERT_Hexify (&hexme, 1);
  949.         }
  950.       break;
  951.     default:
  952.       return JAR_ERR_GENERAL;
  953.     }
  954.   *result = ret ? PORT_Strdup (ret) : NULL;
  955.   *length = ret ? PORT_Strlen (ret) : 0;
  956.   return 0;
  957.   }
  958. /* 
  959.  *  j a r  _ c e r t _ e l e m e n t
  960.  *
  961.  *  Retrieve an element from an x400ish ascii
  962.  *  designator, in a hackish sort of way. The right
  963.  *  thing would probably be to sort AVATags.
  964.  *
  965.  */
  966. static char *jar_cert_element (char *name, char *tag, int occ)
  967.   {
  968.   if (name && tag)
  969.     {
  970.     char *s;
  971.     int found = 0;
  972.     while (occ--)
  973.       {
  974.       if (PORT_Strstr (name, tag))
  975.         {
  976.         name = PORT_Strstr (name, tag) + PORT_Strlen (tag);
  977.         found = 1;
  978.         }
  979.       else
  980.         {
  981.         name = PORT_Strstr (name, "=");
  982.         if (name == NULL) return NULL;
  983.         found = 0;
  984.         }
  985.       }
  986.     if (!found) return NULL;
  987.     /* must mangle only the copy */
  988.     name = PORT_Strdup (name);
  989.     /* advance to next equal */
  990.     for (s = name; *s && *s != '='; s++)
  991.       /* yip */ ;
  992.     /* back up to previous comma */
  993.     while (s > name && *s != ',') s--;
  994.     /* zap the whitespace and return */
  995.     *s = 0;
  996.     }
  997.   return name;
  998.   }
  999. /* 
  1000.  *  j a r _ c h o o s e _ n i c k n a m e
  1001.  *
  1002.  *  Attempt to determine a suitable nickname for
  1003.  *  a certificate with a computer-generated "tmpcertxxx" 
  1004.  *  nickname. It needs to be something a user can
  1005.  *  understand, so try a few things.
  1006.  *
  1007.  */
  1008. static char *jar_choose_nickname (CERTCertificate *cert)
  1009.   {
  1010.   char *cert_cn;
  1011.   char *cert_o;
  1012.   char *cert_cn_o;
  1013.   int cn_o_length;
  1014.   /* is the existing name ok */
  1015.   if (cert->nickname && PORT_Strncmp (cert->nickname, "tmpcert", 7))
  1016.     return PORT_Strdup (cert->nickname);
  1017.   /* we have an ugly name here people */
  1018.   /* Try the CN */
  1019.   cert_cn = CERT_GetCommonName (&cert->subject);
  1020.   if (cert_cn)
  1021.     {
  1022.     /* check for duplicate nickname */
  1023. #ifdef USE_MOZ_THREAD
  1024.     if (jar_moz_nickname (CERT_GetDefaultCertDB(), cert_cn) == NULL)
  1025. #else
  1026.     if (CERT_FindCertByNickname (CERT_GetDefaultCertDB(), cert_cn) == NULL)
  1027. #endif
  1028.       return cert_cn;
  1029.     /* Try the CN plus O */
  1030.     cert_o = CERT_GetOrgName (&cert->subject);
  1031.     cn_o_length = PORT_Strlen (cert_cn) + 3 + PORT_Strlen (cert_o) + 20;
  1032.     cert_cn_o = (char*)PORT_ZAlloc (cn_o_length);
  1033.     PR_snprintf (cert_cn_o, cn_o_length, 
  1034.            "%s's %s Certificate", cert_cn, cert_o);
  1035. #ifdef USE_MOZ_THREAD
  1036.     if (jar_moz_nickname (CERT_GetDefaultCertDB(), cert_cn_o) == NULL)
  1037. #else
  1038.     if (CERT_FindCertByNickname (CERT_GetDefaultCertDB(), cert_cn_o) == NULL)
  1039. #endif
  1040.       return cert_cn;
  1041.     }
  1042.   /* If all that failed, use the ugly nickname */
  1043.   return cert->nickname ? PORT_Strdup (cert->nickname) : NULL;
  1044.   }
  1045. /*
  1046.  *  J A R _ c e r t _ h t m l 
  1047.  *
  1048.  *  Return an HTML representation of the certificate
  1049.  *  designated by the given fingerprint, in specified style.
  1050.  *
  1051.  *  JAR is optional, but supply it if you can in order
  1052.  *  to optimize.
  1053.  *
  1054.  */
  1055. char *JAR_cert_html
  1056.     (JAR *jar, int style, long keylen, void *key, int *result)
  1057.   {
  1058.   char *html;
  1059.   CERTCertificate *cert;
  1060.   *result = -1;
  1061.   if (style != 0)
  1062.     return NULL;
  1063.   cert = jar_get_certificate (jar, keylen, key, result);
  1064.   if (cert == NULL || *result < 0)
  1065.     return NULL;
  1066.   *result = 0;
  1067.   html = CERT_HTMLCertInfo (cert, /* show images */ PR_TRUE,
  1068. /*show issuer*/PR_TRUE);
  1069.   if (html == NULL)
  1070.     *result = -1;
  1071.   return html;
  1072.   }
  1073. /*
  1074.  *  J A R _ s t a s h _ c e r t
  1075.  *
  1076.  *  Stash the certificate pointed to by this
  1077.  *  fingerprint, in persistent storage somewhere.
  1078.  *
  1079.  */
  1080. extern int PR_CALLBACK JAR_stash_cert
  1081.     (JAR *jar, long keylen, void *key)
  1082.   {
  1083.   int result = 0;
  1084.   char *nickname;
  1085.   CERTCertTrust trust;
  1086.   CERTCertDBHandle *certdb;
  1087.   CERTCertificate *cert, *newcert;
  1088.   cert = jar_get_certificate (jar, keylen, key, &result);
  1089.   if (result < 0)
  1090.     return result;
  1091.   if (cert == NULL)
  1092.     return JAR_ERR_GENERAL;
  1093.   if ((certdb = JAR_open_database()) == NULL)
  1094.     return JAR_ERR_GENERAL;
  1095.   /* Attempt to give a name to the newish certificate */
  1096.   nickname = jar_choose_nickname (cert);
  1097. #ifdef USE_MOZ_THREAD
  1098.   newcert = jar_moz_nickname (certdb, nickname);
  1099. #else
  1100.   newcert = CERT_FindCertByNickname (certdb, nickname);
  1101. #endif
  1102.   if (newcert && newcert->isperm) 
  1103.     {
  1104.     /* already in permanant database */
  1105.     return 0;
  1106.     }
  1107.   if (newcert) cert = newcert;
  1108.   /* FIX, since FindCert returns a bogus dbhandle
  1109.      set it ourselves */
  1110.   cert->dbhandle = certdb;
  1111. #if 0
  1112.   nickname = cert->subjectName;
  1113.   if (nickname)
  1114.     {
  1115.     /* Not checking for a conflict here. But this should
  1116.        be a new cert or it would have been found earlier. */
  1117.     nickname = jar_cert_element (nickname, "CN=", 1);
  1118.     if (SEC_CertNicknameConflict (nickname, cert->dbhandle))
  1119.       {
  1120.       /* conflict */
  1121.       nickname = PORT_Realloc (&nickname, PORT_Strlen (nickname) + 3);
  1122.       /* Beyond one copy, there are probably serious problems 
  1123.          so we will stop at two rather than counting.. */
  1124.       PORT_Strcat (nickname, " #2");
  1125.       }
  1126.     }
  1127. #endif
  1128.   if (nickname != NULL)
  1129.     {
  1130.     PORT_Memset ((void *) &trust, 0, sizeof(trust));
  1131. #ifdef USE_MOZ_THREAD
  1132.     if (jar_moz_perm (cert, nickname, &trust) != SECSuccess) 
  1133. #else
  1134.     if (CERT_AddTempCertToPerm (cert, nickname, &trust) != SECSuccess) 
  1135. #endif
  1136.       {
  1137.       /* XXX might want to call PORT_GetError here */
  1138.       result = JAR_ERR_GENERAL;
  1139.       }
  1140.     }
  1141.   JAR_close_database (certdb);
  1142.   return result;
  1143.   }
  1144. /*
  1145.  *  J A R _ f e t c h _ c e r t
  1146.  *
  1147.  *  Given an opaque identifier of a certificate, 
  1148.  *  return the full certificate.
  1149.  *
  1150.  * The new function, which retrieves by key.
  1151.  *
  1152.  */
  1153. void *JAR_fetch_cert (long length, void *key)
  1154.   {
  1155.   SECItem seckey;
  1156.   CERTCertificate *cert = NULL;
  1157.   CERTCertDBHandle *certdb;
  1158.   certdb = JAR_open_database();
  1159.   if (certdb)
  1160.     {
  1161.     seckey.len = length;
  1162.     seckey.data = (unsigned char*)key;
  1163. #ifdef USE_MOZ_THREAD
  1164.     cert = jar_moz_certkey (certdb, &seckey);
  1165. #else
  1166.     cert = CERT_FindCertByKey (certdb, &seckey);
  1167. #endif
  1168.     JAR_close_database (certdb);
  1169.     }
  1170.   return (void *) cert;
  1171.   }
  1172. /*
  1173.  *  j a r _ g e t _ m f _ d i g e s t
  1174.  *
  1175.  *  Retrieve a corresponding saved digest over a section
  1176.  *  of the main manifest file. 
  1177.  *
  1178.  */
  1179. static JAR_Digest *jar_get_mf_digest (JAR *jar, char *pathname)
  1180.   {
  1181.   JAR_Item *it;
  1182.   JAR_Digest *dig;
  1183.   ZZLink *link;
  1184.   ZZList *list;
  1185.   list = jar->manifest;
  1186.   if (ZZ_ListEmpty (list))
  1187.     return NULL;
  1188.   for (link = ZZ_ListHead (list);
  1189.        !ZZ_ListIterDone (list, link);
  1190.        link = link->next)
  1191.     {
  1192.     it = link->thing;
  1193.     if (it->type == jarTypeSect 
  1194.           && it->pathname && !PORT_Strcmp (it->pathname, pathname))
  1195.       {
  1196.       dig = (JAR_Digest *) it->data;
  1197.       return dig;
  1198.       }
  1199.     }
  1200.   return NULL;
  1201.   }
  1202. /*
  1203.  *  j a r _ b a s e n a m e
  1204.  *
  1205.  *  Return the basename -- leading components of path stripped off,
  1206.  *  extension ripped off -- of a path.
  1207.  *
  1208.  */
  1209. static char *jar_basename (const char *path)
  1210.   {
  1211.   char *pith, *e, *basename, *ext;
  1212.   if (path == NULL)
  1213.     return PORT_Strdup ("");
  1214.   pith = PORT_Strdup (path);
  1215.   basename = pith;
  1216.   while (1)
  1217.     {
  1218.     for (e = basename; *e && *e != '/' && *e != '\'; e++)
  1219.       /* yip */ ;
  1220.     if (*e) 
  1221.       basename = ++e; 
  1222.     else
  1223.       break;
  1224.     }
  1225.   if ((ext = PORT_Strrchr (basename, '.')) != NULL)
  1226.     *ext = 0;
  1227.   /* We already have the space allocated */
  1228.   PORT_Strcpy (pith, basename);
  1229.   return pith;
  1230.   }
  1231. /*
  1232.  *  + + + + + + + + + + + + + + +
  1233.  *
  1234.  *  CRYPTO ROUTINES FOR JAR
  1235.  *
  1236.  *  The following functions are the cryptographic 
  1237.  *  interface to PKCS7 for Jarnatures.
  1238.  *
  1239.  *  + + + + + + + + + + + + + + +
  1240.  *
  1241.  */
  1242. /*
  1243.  *  j a r _ c a t c h _ b y t e s
  1244.  *
  1245.  *  In the event signatures contain enveloped data, it will show up here.
  1246.  *  But note that the lib/pkcs7 routines aren't ready for it.
  1247.  *
  1248.  */
  1249. static void jar_catch_bytes
  1250.      (void *arg, const char *buf, unsigned long len)
  1251.   {
  1252.   /* Actually this should never be called, since there is
  1253.      presumably no data in the signature itself. */
  1254.   }
  1255. /*
  1256.  *  j a r _ v a l i d a t e _ p k c s 7
  1257.  *
  1258.  *  Validate (and decode, if necessary) a binary pkcs7
  1259.  *  signature in DER format.
  1260.  *
  1261.  */
  1262. static int jar_validate_pkcs7 
  1263.      (JAR *jar, JAR_Signer *signer, char *data, long length)
  1264.   {
  1265.   SECItem detdig;
  1266.   SEC_PKCS7ContentInfo *cinfo;
  1267.   SEC_PKCS7DecoderContext *dcx;
  1268.   int status = 0;
  1269.   char *errstring = NULL;
  1270.   PORT_Assert( jar != NULL && signer != NULL );
  1271.   if (jar == NULL || signer == NULL)
  1272.     return JAR_ERR_ORDER;
  1273.   signer->valid = JAR_ERR_SIG;
  1274.   /* We need a context if we can get one */
  1275. #ifdef MOZILLA_CLIENT_OLD
  1276.   if (jar->mw == NULL) {
  1277.     JAR_set_context (jar, NULL);
  1278.   }
  1279. #endif
  1280.   dcx = SEC_PKCS7DecoderStart
  1281.            (jar_catch_bytes, NULL /*cb_arg*/, NULL /*getpassword*/, jar->mw,
  1282.             NULL, NULL, NULL);
  1283.   if (dcx != NULL) 
  1284.     {
  1285.     SEC_PKCS7DecoderUpdate (dcx, data, length);
  1286.     cinfo = SEC_PKCS7DecoderFinish (dcx);
  1287.     }
  1288.   if (cinfo == NULL)
  1289.     {
  1290.     /* strange pkcs7 failure */
  1291.     return JAR_ERR_PK7;
  1292.     }
  1293.   if (SEC_PKCS7ContentIsEncrypted (cinfo))
  1294.     {
  1295.     /* content was encrypted, fail */
  1296.     return JAR_ERR_PK7;
  1297.     }
  1298.   if (SEC_PKCS7ContentIsSigned (cinfo) == PR_FALSE)
  1299.     {
  1300.     /* content was not signed, fail */
  1301.     return JAR_ERR_PK7;
  1302.     }
  1303.   PORT_SetError (0);
  1304.   /* use SHA1 only */
  1305.   detdig.len = SHA1_LENGTH;
  1306.   detdig.data = signer->digest->sha1;
  1307. #ifdef USE_MOZ_THREAD
  1308.   if (jar_moz_verify
  1309.         (cinfo, certUsageObjectSigner, &detdig, HASH_AlgSHA1, PR_FALSE)==
  1310. SECSuccess)
  1311. #else
  1312.   if (SEC_PKCS7VerifyDetachedSignature 
  1313.         (cinfo, certUsageObjectSigner, &detdig, HASH_AlgSHA1, PR_FALSE)==
  1314. PR_TRUE)
  1315. #endif
  1316.     {
  1317.     /* signature is valid */
  1318.     signer->valid = 0;
  1319.     jar_gather_signers (jar, signer, cinfo);
  1320.     }
  1321.   else
  1322.     {
  1323.     status = PORT_GetError();
  1324.     PORT_Assert( status < 0 );
  1325.     if (status >= 0) status = JAR_ERR_SIG;
  1326.     jar->valid = status;
  1327.     signer->valid = status;
  1328.     errstring = JAR_get_error (status);
  1329.     /*XP_TRACE(("JAR signature invalid (reason %d = %s)", status, errstring));*/
  1330.     }
  1331.   jar->pkcs7 = PR_TRUE;
  1332.   signer->pkcs7 = PR_TRUE;
  1333.   SEC_PKCS7DestroyContentInfo (cinfo);
  1334.   return status;
  1335.   }
  1336. /*
  1337.  *  j a r _ g a t h e r _ s i g n e r s
  1338.  *
  1339.  *  Add the single signer of this signature to the
  1340.  *  certificate linked list.
  1341.  *
  1342.  */
  1343. static int jar_gather_signers
  1344.      (JAR *jar, JAR_Signer *signer, SEC_PKCS7ContentInfo *cinfo)
  1345.   {
  1346.   int result;
  1347.   CERTCertificate *cert;
  1348.   CERTCertDBHandle *certdb;
  1349.   SEC_PKCS7SignedData *sdp;
  1350.   SEC_PKCS7SignerInfo **pksigners, *pksigner;
  1351.   sdp = cinfo->content.signedData;
  1352.   if (sdp == NULL)
  1353.     return JAR_ERR_PK7;
  1354.   pksigners = sdp->signerInfos;
  1355.   /* permit exactly one signer */
  1356.   if (pksigners == NULL || pksigners [0] == NULL || pksigners [1] != NULL)
  1357.     return JAR_ERR_PK7;
  1358.   pksigner = *pksigners;
  1359.   cert = pksigner->cert;
  1360.   if (cert == NULL)
  1361.     return JAR_ERR_PK7;
  1362.   certdb = JAR_open_database();
  1363.   if (certdb == NULL)
  1364.     return JAR_ERR_GENERAL;
  1365.   result = jar_add_cert (jar, signer, jarTypeSign, cert);
  1366.   JAR_close_database (certdb);
  1367.   return result;
  1368.   }
  1369. /*
  1370.  *  j a r _ o p e n _ d a t a b a s e
  1371.  *
  1372.  *  Open the certificate database,
  1373.  *  for use by JAR functions.
  1374.  *
  1375.  */
  1376. CERTCertDBHandle *JAR_open_database (void)
  1377.   {
  1378.   int keepcerts = 0;
  1379.   CERTCertDBHandle *certdb;
  1380.   /* local_certdb will only be used if calling from a command line tool */
  1381.   static CERTCertDBHandle local_certdb;
  1382.   certdb = CERT_GetDefaultCertDB();
  1383.   if (certdb == NULL) 
  1384.     {
  1385.     if (CERT_OpenCertDBFilename (&local_certdb, NULL, (PRBool)!keepcerts) != 
  1386.                                                            SECSuccess)
  1387.       {
  1388.       return NULL;
  1389.       }
  1390.     certdb = &local_certdb;
  1391.     }
  1392.   return certdb;
  1393.   }
  1394. /*
  1395.  *  j a r _ c l o s e _ d a t a b a s e
  1396.  *
  1397.  *  Close the certificate database.
  1398.  *  For use by JAR functions.
  1399.  *
  1400.  */
  1401. int JAR_close_database (CERTCertDBHandle *certdb)
  1402.   {
  1403.   CERTCertDBHandle *defaultdb;
  1404.   /* This really just retrieves the handle, nothing more */
  1405.   defaultdb = CERT_GetDefaultCertDB();
  1406.   /* If there is no default db, it means we opened 
  1407.      the permanent database for some reason */
  1408.   if (defaultdb == NULL && certdb != NULL)
  1409.     CERT_ClosePermCertDB (certdb);
  1410.   return 0;
  1411.   }
  1412. /*
  1413.  *  j a r _ g e t _ c e r t i f i c a t e
  1414.  *
  1415.  *  Return the certificate referenced
  1416.  *  by a given fingerprint, or NULL if not found.
  1417.  *  Error code is returned in result.
  1418.  *
  1419.  */
  1420. static CERTCertificate *jar_get_certificate
  1421.       (JAR *jar, long keylen, void *key, int *result)
  1422.   {
  1423.   int found = 0;
  1424.   JAR_Item *it;
  1425.   JAR_Cert *fing;
  1426.   JAR_Context *ctx;
  1427.   if (jar == NULL) 
  1428.     {
  1429.     void *cert;
  1430.     cert = JAR_fetch_cert (keylen, key);
  1431.     *result = (cert == NULL) ? JAR_ERR_GENERAL : 0;
  1432.     return (CERTCertificate *) cert;
  1433.     }
  1434.   ctx = JAR_find (jar, NULL, jarTypeSign);
  1435.   while (JAR_find_next (ctx, &it) >= 0)
  1436.     {
  1437.     fing = (JAR_Cert *) it->data;
  1438.     if (keylen != fing->length)
  1439.       continue;
  1440.     PORT_Assert( keylen < 0xFFFF );
  1441.     if (!PORT_Memcmp (fing->key, key, keylen))
  1442.       {
  1443.       found = 1;
  1444.       break;
  1445.       }
  1446.     }
  1447.   JAR_find_end (ctx);
  1448.   if (found == 0)
  1449.     {
  1450.     *result = JAR_ERR_GENERAL;
  1451.     return NULL;
  1452.     }
  1453.   *result = 0;
  1454.   return fing->cert;
  1455.   }
  1456. /*
  1457.  *  j a r _ s i g n a l
  1458.  *
  1459.  *  Nonfatal errors come here to callback Java.
  1460.  *  
  1461.  */
  1462. static int jar_signal 
  1463.      (int status, JAR *jar, const char *metafile, char *pathname)
  1464.   {
  1465.   char *errstring;
  1466.   errstring = JAR_get_error (status);
  1467.   if (jar->signal)
  1468.     {
  1469.     (*jar->signal) (status, jar, metafile, pathname, errstring);
  1470.     return 0;
  1471.     }
  1472.   return status;
  1473.   }
  1474. /*
  1475.  *  j a r _ a p p e n d
  1476.  *
  1477.  *  Tack on an element to one of a JAR's linked
  1478.  *  lists, with rudimentary error handling.
  1479.  *
  1480.  */
  1481. int jar_append (ZZList *list, int type, 
  1482.         char *pathname, void *data, size_t size)
  1483.   {
  1484.   JAR_Item *it;
  1485.   ZZLink *entity;
  1486.   it = (JAR_Item*)PORT_ZAlloc (sizeof (JAR_Item));
  1487.   if (it == NULL)
  1488.     goto loser;
  1489.   if (pathname)
  1490.     {
  1491.     it->pathname = PORT_Strdup (pathname);
  1492.     if (it->pathname == NULL)
  1493.       goto loser;
  1494.     }
  1495.   it->type = (jarType)type;
  1496.   it->data = (unsigned char *) data;
  1497.   it->size = size;
  1498.   entity = ZZ_NewLink (it);
  1499.   if (entity)
  1500.     {
  1501.     ZZ_AppendLink (list, entity);
  1502.     return 0;
  1503.     }
  1504. loser:
  1505.   if (it)
  1506.     {
  1507.     if (it->pathname) PORT_Free (it->pathname);
  1508.     PORT_Free (it);
  1509.     }
  1510.   return JAR_ERR_MEMORY;
  1511.   }
  1512. /* 
  1513.  *  W I N 1 6   s t u f f
  1514.  *
  1515.  *  These functions possibly belong in xp_mem.c, they operate 
  1516.  *  on huge string pointers for win16.
  1517.  *
  1518.  */
  1519. #if defined(XP_WIN16)
  1520. int xp_HUGE_STRNCASECMP (char ZHUGEP *buf, char *key, int len)
  1521.   {
  1522.   while (len--) 
  1523.     {
  1524.     char c1, c2;
  1525.     c1 = *buf++;
  1526.     c2 = *key++;
  1527.     if (c1 >= 'a' && c1 <= 'z') c1 -= ('a' - 'A');
  1528.     if (c2 >= 'a' && c2 <= 'z') c2 -= ('a' - 'A');
  1529.     if (c1 != c2) 
  1530.       return (c1 < c2) ? -1 : 1;
  1531.     }
  1532.   return 0;
  1533.   }
  1534. size_t xp_HUGE_STRLEN (char ZHUGEP *s)
  1535.   {
  1536.   size_t len = 0L;
  1537.   while (*s++) len++;
  1538.   return len;
  1539.   }
  1540. char *xp_HUGE_STRCPY (char *to, char ZHUGEP *from)
  1541.   {
  1542.   char *ret = to;
  1543.   while (*from)
  1544.     *to++ = *from++;
  1545.   *to = 0;
  1546.   return ret;
  1547.   }
  1548. #endif