jarver.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,030 行 · 第 1/3 页

C
2,030
字号
/* * 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. *//* *  JARVER * *  Jarnature Parsing & Verification */#define USE_MOZ_THREAD#include "jar.h"#include "jarint.h"#ifdef USE_MOZ_THREAD#include "jarevil.h"#endif#include "cdbhdl.h"/* to use huge pointers in win16 */#if !defined(XP_WIN16)#define xp_HUGE_MEMCPY PORT_Memcpy#define xp_HUGE_STRCPY PORT_Strcpy#define xp_HUGE_STRLEN PORT_Strlen#define xp_HUGE_STRNCASECMP PORT_Strncasecmp#else#define xp_HUGE_MEMCPY hmemcpyint xp_HUGE_STRNCASECMP (char ZHUGEP *buf, char *key, int len);size_t xp_HUGE_STRLEN (char ZHUGEP *s);char *xp_HUGE_STRCPY (char *to, char ZHUGEP *from);#endif/* from certdb.h */#define CERTDB_USER (1<<6)#if 0/* from certdb.h */extern PRBool SEC_CertNicknameConflict   (char *nickname, CERTCertDBHandle *handle);/* from certdb.h */extern SECStatus SEC_AddTempNickname   (CERTCertDBHandle *handle, char *nickname, SECItem *certKey);/* from certdb.h */typedef SECStatus (* PermCertCallback)(CERTCertificate *cert, SECItem *k, void *pdata);#endif/* from certdb.h */SECStatus SEC_TraversePermCerts   (CERTCertDBHandle *handle, PermCertCallback certfunc, void *udata);#define SZ 512static int jar_validate_pkcs7      (JAR *jar, JAR_Signer *signer, char *data, long length);static int jar_decode (JAR *jar, char *data, long length);static void jar_catch_bytes     (void *arg, const char *buf, unsigned long len);static int jar_gather_signers     (JAR *jar, JAR_Signer *signer, SEC_PKCS7ContentInfo *cinfo);static char ZHUGEP *jar_eat_line      (int lines, int eating, char ZHUGEP *data, long *len);static JAR_Digest *jar_digest_section      (char ZHUGEP *manifest, long length);static JAR_Digest *jar_get_mf_digest (JAR *jar, char *path);static int jar_parse_digital_signature      (char *raw_manifest, JAR_Signer *signer, long length, JAR *jar);static int jar_add_cert     (JAR *jar, JAR_Signer *signer, int type, CERTCertificate *cert);static CERTCertificate *jar_get_certificate            (JAR *jar, long keylen, void *key, int *result);static char *jar_cert_element (char *name, char *tag, int occ);static char *jar_choose_nickname (CERTCertificate *cert);static char *jar_basename (const char *path);static int jar_signal      (int status, JAR *jar, const char *metafile, char *pathname);static int jar_insanity_check (char ZHUGEP *data, long length);int jar_parse_mf    (JAR *jar, char ZHUGEP *raw_manifest,         long length, const char *path, const char *url);int jar_parse_sf    (JAR *jar, char ZHUGEP *raw_manifest,         long length, const char *path, const char *url);int jar_parse_sig    (JAR *jar, const char *path, char ZHUGEP *raw_manifest, long length);int jar_parse_any    (JAR *jar, int type, JAR_Signer *signer, char ZHUGEP *raw_manifest,         long length, const char *path, const char *url);static int jar_internal_digest      (JAR *jar, const char *path, char *x_name, JAR_Digest *dig);/* *  J A R _ p a r s e _ m a n i f e s t *  *  Pass manifest files to this function. They are *  decoded and placed into internal representations. *  *  Accepts both signature and manifest files. Use *  the same "jar" for both.  * */int JAR_parse_manifest     (JAR *jar, char ZHUGEP *raw_manifest,         long length, const char *path, const char *url)  {#if defined(XP_WIN16)    PORT_Assert( !IsBadHugeReadPtr(raw_manifest, length) );#endif  /* fill in the path, if supplied. This is a the location     of the jar file on disk, if known */  if (jar->filename == NULL && path)    {    jar->filename = PORT_Strdup (path);    if (jar->filename == NULL)      return JAR_ERR_MEMORY;    }  /* fill in the URL, if supplied. This is the place     from which the jar file was retrieved. */  if (jar->url == NULL && url)    {    jar->url = PORT_Strdup (url);    if (jar->url == NULL)      return JAR_ERR_MEMORY;    }  /* Determine what kind of file this is from the META-INF      directory. It could be MF, SF, or a binary RSA/DSA file */  if (!xp_HUGE_STRNCASECMP (raw_manifest, "Manifest-Version:", 17))    {    return jar_parse_mf (jar, raw_manifest, length, path, url);    }  else if (!xp_HUGE_STRNCASECMP (raw_manifest, "Signature-Version:", 18))    {    return jar_parse_sf (jar, raw_manifest, length, path, url);    }  else    {    /* This is probably a binary signature */    return jar_parse_sig (jar, path, raw_manifest, length);    }  }/* *  j a r _ p a r s e _ s i g * *  Pass some manner of RSA or DSA digital signature *  on, after checking to see if it comes at an appropriate state. * */ int jar_parse_sig    (JAR *jar, const char *path, char ZHUGEP *raw_manifest, long length)  {  JAR_Signer *signer;  int status = JAR_ERR_ORDER;  if (length <= 128)     {    /* signature is way too small */    return JAR_ERR_SIG;    }  /* make sure that MF and SF have already been processed */  if (jar->globalmeta == NULL)    return JAR_ERR_ORDER;#if 0  /* XXX Turn this on to disable multiple signers */  if (jar->digest == NULL)    return JAR_ERR_ORDER;#endif  /* Determine whether or not this RSA file has     has an associated SF file */  if (path)    {    char *owner;    owner = jar_basename (path);    if (owner == NULL)      return JAR_ERR_MEMORY;    signer = jar_get_signer (jar, owner);    PORT_Free (owner);    }  else    signer = jar_get_signer (jar, "*");  if (signer == NULL)    return JAR_ERR_ORDER;  /* Do not pass a huge pointer to this function,     since the underlying security code is unaware. We will     never pass >64k through here. */  if (length > 64000)    {    /* this digital signature is way too big */    return JAR_ERR_SIG;    }#ifdef XP_WIN16  /*   * For Win16, copy the portion of the raw_buffer containing the digital    * signature into another buffer...  This insures that the data will   * NOT cross a segment boundary.  Therefore,    * jar_parse_digital_signature(...) does NOT need to deal with HUGE    * pointers...   */    {    unsigned char *manifest_copy;    manifest_copy = (unsigned char *) PORT_ZAlloc (length);    if (manifest_copy)      {      xp_HUGE_MEMCPY (manifest_copy, raw_manifest, length);      status = jar_parse_digital_signature                   (manifest_copy, signer, length, jar);      PORT_Free (manifest_copy);      }    else      {      /* out of memory */      return JAR_ERR_MEMORY;      }    }#else  /* don't expense unneeded calloc overhead on non-win16 */  status = jar_parse_digital_signature                 (raw_manifest, signer, length, jar);#endif  return status;  }/* *  j a r _ p a r s e _ m f * *  Parse the META-INF/manifest.mf file, whose *  information applies to all signers. * */int jar_parse_mf    (JAR *jar, char ZHUGEP *raw_manifest,         long length, const char *path, const char *url)  {  if (jar->globalmeta)    {    /* refuse a second manifest file, if passed for some reason */    return JAR_ERR_ORDER;    }  /* remember a digest for the global section */  jar->globalmeta = jar_digest_section (raw_manifest, length);  if (jar->globalmeta == NULL)    return JAR_ERR_MEMORY;  return jar_parse_any     (jar, jarTypeMF, NULL, raw_manifest, length, path, url);  }/* *  j a r _ p a r s e _ s f * *  Parse META-INF/xxx.sf, a digitally signed file *  pointing to a subset of MF sections.  * */int jar_parse_sf    (JAR *jar, char ZHUGEP *raw_manifest,         long length, const char *path, const char *url)  {  JAR_Signer *signer = NULL;  int status = JAR_ERR_MEMORY;  if (jar->globalmeta == NULL)    {    /* It is a requirement that the MF file be passed before the SF file */    return JAR_ERR_ORDER;    }  signer = JAR_new_signer();  if (signer == NULL)    goto loser;  if (path)    {    signer->owner = jar_basename (path);    if (signer->owner == NULL)      goto loser;    }  /* check for priors. When someone doctors a jar file     to contain identical path entries, prevent the second     one from affecting JAR functions */  if (jar_get_signer (jar, signer->owner))    {    /* someone is trying to spoof us */    status = JAR_ERR_ORDER;    goto loser;    }  /* remember its digest */  signer->digest = JAR_calculate_digest (raw_manifest, length);  if (signer->digest == NULL)    goto loser;  /* Add this signer to the jar */  ADDITEM (jar->signers, jarTypeOwner,      signer->owner, signer, sizeof (JAR_Signer));  return jar_parse_any     (jar, jarTypeSF, signer, raw_manifest, length, path, url);loser:  if (signer)    JAR_destroy_signer (signer);  return status;  }/*  *  j a r _ p a r s e _ a n y * *  Parse a MF or SF manifest file.  * */ int jar_parse_any    (JAR *jar, int type, JAR_Signer *signer, char ZHUGEP *raw_manifest,         long length, const char *path, const char *url)  {  int status;  long raw_len;  JAR_Digest *dig, *mfdig = NULL;  char line [SZ];  char x_name [SZ], x_md5 [SZ], x_sha [SZ];  char *x_info;  char *sf_md5 = NULL, *sf_sha1 = NULL;  *x_name = 0;  *x_md5 = 0;  *x_sha = 0;  PORT_Assert( length > 0 );  raw_len = length;#ifdef DEBUG  if ((status = jar_insanity_check (raw_manifest, raw_len)) < 0)    return status;#endif  /* null terminate the first line */  raw_manifest = jar_eat_line (0, PR_TRUE, raw_manifest, &raw_len);  /* skip over the preliminary section */  /* This is one section at the top of the file with global metainfo */  while (raw_len)    {    JAR_Metainfo *met;    raw_manifest = jar_eat_line (1, PR_TRUE, raw_manifest, &raw_len);    if (!*raw_manifest) break;    met = (JAR_Metainfo*)PORT_ZAlloc (sizeof (JAR_Metainfo));    if (met == NULL)      return JAR_ERR_MEMORY;    /* Parse out the header & info */    if (xp_HUGE_STRLEN (raw_manifest) >= SZ)      {      /* almost certainly nonsense */      continue;      }    xp_HUGE_STRCPY (line, raw_manifest);    x_info = line;    while (*x_info && *x_info != ' ' && *x_info != '\t' && *x_info != ':')      x_info++;    if (*x_info) *x_info++ = 0;    while (*x_info == ' ' || *x_info == '\t')      x_info++;    /* metainfo (name, value) pair is now (line, x_info) */    met->header = PORT_Strdup (line);    met->info = PORT_Strdup (x_info);    if (type == jarTypeMF)      {      ADDITEM (jar->metainfo, jarTypeMeta,          /* pathname */ NULL, met, sizeof (JAR_Metainfo));      }    /* For SF files, this metadata may be the digests       of the MF file, still in the "met" structure. */    if (type == jarTypeSF)      {      if (!PORT_Strcasecmp (line, "MD5-Digest"))        sf_md5 = (char *) met->info;      if (!PORT_Strcasecmp (line, "SHA1-Digest") || !PORT_Strcasecmp (line, "SHA-Digest"))        sf_sha1 = (char *) met->info;      }    }  if (type == jarTypeSF && jar->globalmeta)    {    /* this is a SF file which may contain a digest of the manifest.mf's        global metainfo. */    int match = 0;    JAR_Digest *glob = jar->globalmeta;    if (sf_md5)      {      unsigned int md5_length;      unsigned char *md5_digest;      md5_digest = ATOB_AsciiToData (sf_md5, &md5_length);      PORT_Assert( md5_length == MD5_LENGTH );      if (md5_length != MD5_LENGTH)        return JAR_ERR_CORRUPT;      match = PORT_Memcmp (md5_digest, glob->md5, MD5_LENGTH);      }    if (sf_sha1 && match == 0)      {      unsigned int sha1_length;      unsigned char *sha1_digest;      sha1_digest = ATOB_AsciiToData (sf_sha1, &sha1_length);      PORT_Assert( sha1_length == SHA1_LENGTH );      if (sha1_length != SHA1_LENGTH)        return JAR_ERR_CORRUPT;      match = PORT_Memcmp (sha1_digest, glob->sha1, SHA1_LENGTH);      }    if (match != 0)      {      /* global digest doesn't match, SF file therefore invalid */      jar->valid = JAR_ERR_METADATA;      return JAR_ERR_METADATA;      }    }  /* done with top section of global data */  while (raw_len)    {    *x_md5 = 0;    *x_sha = 0;    *x_name = 0;    /* If this is a manifest file, attempt to get a digest of the following section,        without damaging it. This digest will be saved later. */    if (type == jarTypeMF)      {      char ZHUGEP *sec;      long sec_len = raw_len;      if (!*raw_manifest || *raw_manifest == '\n')        {             /* skip the blank line */         sec = jar_eat_line (1, PR_FALSE, raw_manifest, &sec_len);        }      else        sec = raw_manifest;      if (!xp_HUGE_STRNCASECMP (sec, "Name:", 5))        {        if (type == jarTypeMF)          mfdig = jar_digest_section (sec, sec_len);        else          mfdig = NULL;        }      }    while (raw_len)      {      raw_manifest = jar_eat_line (1, PR_TRUE, raw_manifest, &raw_len);      if (!*raw_manifest) break; /* blank line, done with this entry */      if (xp_HUGE_STRLEN (raw_manifest) >= SZ)        {        /* almost certainly nonsense */        continue;        }      /* Parse out the name/value pair */      xp_HUGE_STRCPY (line, raw_manifest);      x_info = line;      while (*x_info && *x_info != ' ' && *x_info != '\t' && *x_info != ':')        x_info++;      if (*x_info) *x_info++ = 0;      while (*x_info == ' ' || *x_info == '\t')         x_info++;      if (!PORT_Strcasecmp (line, "Name"))        PORT_Strcpy (x_name, x_info);      else if (!PORT_Strcasecmp (line, "MD5-Digest"))        PORT_Strcpy (x_md5, x_info);      else if (!PORT_Strcasecmp (line, "SHA1-Digest")                   || !PORT_Strcasecmp (line, "SHA-Digest"))        {        PORT_Strcpy (x_sha, x_info);        }      /* Algorithm list is meta info we don't care about; keeping it out         of metadata saves significant space for large jar files */      else if (!PORT_Strcasecmp (line, "Digest-Algorithms")                    || !PORT_Strcasecmp (line, "Hash-Algorithms"))        {        continue;        }      /* Meta info is only collected for the manifest.mf file,         since the JAR_get_metainfo call does not support identity */      else if (type == jarTypeMF)        {        JAR_Metainfo *met;        /* this is meta-data */        met = (JAR_Metainfo*)PORT_ZAlloc (sizeof (JAR_Metainfo));        if (met == NULL)          return JAR_ERR_MEMORY;        /* metainfo (name, value) pair is now (line, x_info) */        if ((met->header = PORT_Strdup (line)) == NULL)          return JAR_ERR_MEMORY;        if ((met->info = PORT_Strdup (x_info)) == NULL)          return JAR_ERR_MEMORY;        ADDITEM (jar->metainfo, jarTypeMeta,            x_name, met, sizeof (JAR_Metainfo));        }      }	if(!x_name || !*x_name) {		/* Whatever that was, it wasn't an entry, because we didn't get a name.		 * We don't really have anything, so don't record this. */		continue;	}    dig = (JAR_Digest*)PORT_ZAlloc (sizeof (JAR_Digest));    if (dig == NULL)      return JAR_ERR_MEMORY;    if (*x_md5 )       {      unsigned int binary_length;      unsigned char *binary_digest;      binary_digest = ATOB_AsciiToData (x_md5, &binary_length);      PORT_Assert( binary_length == MD5_LENGTH );      if (binary_length != MD5_LENGTH)        return JAR_ERR_CORRUPT;      memcpy (dig->md5, binary_digest, MD5_LENGTH);      dig->md5_status = jarHashPresent;      }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?