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 + -
显示快捷键?