summaryrefslogtreecommitdiff
path: root/security/nss/lib/jar/jarver.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/jar/jarver.c')
-rw-r--r--security/nss/lib/jar/jarver.c1175
1 files changed, 0 insertions, 1175 deletions
diff --git a/security/nss/lib/jar/jarver.c b/security/nss/lib/jar/jarver.c
deleted file mode 100644
index d06b4e00c..000000000
--- a/security/nss/lib/jar/jarver.c
+++ /dev/null
@@ -1,1175 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * JARVER
- *
- * Jarnature Parsing & Verification
- */
-
-#include "nssrenam.h"
-#include "jar.h"
-#include "jarint.h"
-#include "certdb.h"
-#include "certt.h"
-#include "secpkcs7.h"
-
-/*#include "cdbhdl.h" */
-#include "secder.h"
-
-/* from certdb.h */
-#define CERTDB_USER (1<<6)
-
-#define SZ 512
-
-static int
-jar_validate_pkcs7(JAR *jar, JAR_Signer *signer, 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 *
-jar_eat_line(int lines, int eating, char *data, long *len);
-
-static JAR_Digest *
-jar_digest_section(char *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 char *jar_basename(const char *path);
-
-static int
-jar_signal(int status, JAR *jar, const char *metafile, char *pathname);
-
-#ifdef DEBUG
-static int jar_insanity_check(char *data, long length);
-#endif
-
-int
-jar_parse_mf(JAR *jar, char *raw_manifest, long length,
- const char *path, const char *url);
-
-int
-jar_parse_sf(JAR *jar, char *raw_manifest, long length,
- const char *path, const char *url);
-
-int
-jar_parse_sig(JAR *jar, const char *path, char *raw_manifest,
- long length);
-
-int
-jar_parse_any(JAR *jar, int type, JAR_Signer *signer,
- char *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 *raw_manifest, long length,
- const char *path, const char *url)
-{
- int filename_free = 0;
-
- /* fill in the path, if supplied. This is 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;
- filename_free = 1;
- }
-
- /* 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) {
- if (filename_free) {
- PORT_Free(jar->filename);
- }
- 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 (!PORT_Strncasecmp (raw_manifest, "Manifest-Version:", 17)) {
- return jar_parse_mf(jar, raw_manifest, length, path, url);
- }
- else if (!PORT_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 *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;
-
- /* 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;
- }
-
- /* don't expense unneeded calloc overhead on non-win16 */
- status = jar_parse_digital_signature(raw_manifest, signer, length, jar);
-
- 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 *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 *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 *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 > 0) {
- JAR_Metainfo *met;
-
- raw_manifest = jar_eat_line(1, PR_TRUE, raw_manifest, &raw_len);
- if (raw_len <= 0 || !*raw_manifest)
- break;
-
- met = PORT_ZNew(JAR_Metainfo);
- if (met == NULL)
- return JAR_ERR_MEMORY;
-
- /* Parse out the header & info */
- if (PORT_Strlen (raw_manifest) >= SZ) {
- /* almost certainly nonsense */
- PORT_Free(met);
- continue;
- }
-
- PORT_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 != jarTypeMF) {
- PORT_Free(met->header);
- if (type != jarTypeSF) {
- PORT_Free(met->info);
- }
- PORT_Free(met);
- }
- }
-
- 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 > 0) {
- *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 *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 (sec_len > 0 && !PORT_Strncasecmp(sec, "Name:", 5)) {
- if (type == jarTypeMF)
- mfdig = jar_digest_section(sec, sec_len);
- else
- mfdig = NULL;
- }
- }
-
-
- while (raw_len > 0) {
- raw_manifest = jar_eat_line(1, PR_TRUE, raw_manifest, &raw_len);
- if (raw_len <= 0 || !*raw_manifest)
- break; /* blank line, done with this entry */
-
- if (PORT_Strlen(raw_manifest) >= SZ) {
- /* almost certainly nonsense */
- continue;
- }
-
- /* Parse out the name/value pair */
- PORT_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 = PORT_ZNew(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) {
- PORT_Free(met);
- return JAR_ERR_MEMORY;
- }
-
- if ((met->info = PORT_Strdup(x_info)) == NULL) {
- PORT_Free(met->header);
- PORT_Free(met);
- return JAR_ERR_MEMORY;
- }
-
- ADDITEM (jar->metainfo, jarTypeMeta,
- x_name, met, sizeof (JAR_Metainfo));
- }
- }
-
- if (!*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 = PORT_ZNew(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) {
- PORT_Free(dig);
- return JAR_ERR_CORRUPT;
- }
- memcpy (dig->md5, binary_digest, MD5_LENGTH);
- dig->md5_status = jarHashPresent;
- }
-
- if (*x_sha ) {
- unsigned int binary_length;
- unsigned char *binary_digest;
-
- binary_digest = ATOB_AsciiToData (x_sha, &binary_length);
- PORT_Assert( binary_length == SHA1_LENGTH );
- if (binary_length != SHA1_LENGTH) {
- PORT_Free(dig);
- return JAR_ERR_CORRUPT;
- }
- memcpy (dig->sha1, binary_digest, SHA1_LENGTH);
- dig->sha1_status = jarHashPresent;
- }
-
- PORT_Assert( type == jarTypeMF || type == jarTypeSF );
- if (type == jarTypeMF) {
- ADDITEM (jar->hashes, jarTypeMF, x_name, dig, sizeof (JAR_Digest));
- } else if (type == jarTypeSF) {
- ADDITEM (signer->sf, jarTypeSF, x_name, dig, sizeof (JAR_Digest));
- } else {
- PORT_Free(dig);
- return JAR_ERR_ORDER;
- }
-
- /* we're placing these calculated digests of manifest.mf
- sections in a list where they can subsequently be forgotten */
- if (type == jarTypeMF && mfdig) {
- ADDITEM (jar->manifest, jarTypeSect,
- x_name, mfdig, sizeof (JAR_Digest));
- mfdig = NULL;
- }
-
- /* Retrieve our saved SHA1 digest from saved copy and check digests.
- This is just comparing the digest of the MF section as indicated in
- the SF file with the one we remembered from parsing the MF file */
-
- if (type == jarTypeSF) {
- if ((status = jar_internal_digest(jar, path, x_name, dig)) < 0)
- return status;
- }
- }
-
- return 0;
-}
-
-static int
-jar_internal_digest(JAR *jar, const char *path, char *x_name, JAR_Digest *dig)
-{
- int cv;
- int status;
-
- JAR_Digest *savdig;
-
- savdig = jar_get_mf_digest(jar, x_name);
- if (savdig == NULL) {
- /* no .mf digest for this pathname */
- status = jar_signal(JAR_ERR_ENTRY, jar, path, x_name);
- if (status < 0)
- return 0; /* was continue; */
- return status;
- }
-
- /* check for md5 consistency */
- if (dig->md5_status) {
- cv = PORT_Memcmp(savdig->md5, dig->md5, MD5_LENGTH);
- /* md5 hash of .mf file is not what expected */
- if (cv) {
- status = jar_signal(JAR_ERR_HASH, jar, path, x_name);
-
- /* bad hash, man */
- dig->md5_status = jarHashBad;
- savdig->md5_status = jarHashBad;
-
- if (status < 0)
- return 0; /* was continue; */
- return status;
- }
- }
-
- /* check for sha1 consistency */
- if (dig->sha1_status) {
- cv = PORT_Memcmp(savdig->sha1, dig->sha1, SHA1_LENGTH);
- /* sha1 hash of .mf file is not what expected */
- if (cv) {
- status = jar_signal(JAR_ERR_HASH, jar, path, x_name);
-
- /* bad hash, man */
- dig->sha1_status = jarHashBad;
- savdig->sha1_status = jarHashBad;
-
- if (status < 0)
- return 0; /* was continue; */
- return status;
- }
- }
- return 0;
-}
-
-#ifdef DEBUG
-/*
- * j a r _ i n s a n i t y _ c h e c k
- *
- * Check for illegal characters (or possibly so)
- * in the manifest files, to detect potential memory
- * corruption by our neighbors. Debug only, since
- * not I18N safe.
- *
- */
-static int
-jar_insanity_check(char *data, long length)
-{
- int c;
- long off;
-
- for (off = 0; off < length; off++) {
- c = data [off];
- if (c == '\n' || c == '\r' || (c >= ' ' && c <= 128))
- continue;
- return JAR_ERR_CORRUPT;
- }
- return 0;
-}
-#endif
-
-/*
- * j a r _ p a r s e _ d i g i t a l _ s i g n a t u r e
- *
- * Parse an RSA or DSA (or perhaps other) digital signature.
- * Right now everything is PKCS7.
- *
- */
-static int
-jar_parse_digital_signature(char *raw_manifest, JAR_Signer *signer,
- long length, JAR *jar)
-{
- return jar_validate_pkcs7 (jar, signer, raw_manifest, length);
-}
-
-/*
- * j a r _ a d d _ c e r t
- *
- * Add information for the given certificate
- * (or whatever) to the JAR linked list. A pointer
- * is passed for some relevant reference, say
- * for example the original certificate.
- *
- */
-static int
-jar_add_cert(JAR *jar, JAR_Signer *signer, int type, CERTCertificate *cert)
-{
- JAR_Cert *fing;
- unsigned char *keyData;
-
- if (cert == NULL)
- return JAR_ERR_ORDER;
-
- fing = PORT_ZNew(JAR_Cert);
- if (fing == NULL)
- goto loser;
-
- fing->cert = CERT_DupCertificate (cert);
-
- /* get the certkey */
- fing->length = cert->derIssuer.len + 2 + cert->serialNumber.len;
- fing->key = keyData = (unsigned char *) PORT_ZAlloc(fing->length);
- if (fing->key == NULL)
- goto loser;
- keyData[0] = ((cert->derIssuer.len) >> 8) & 0xff;
- keyData[1] = ((cert->derIssuer.len) & 0xff);
- PORT_Memcpy(&keyData[2], cert->derIssuer.data, cert->derIssuer.len);
- PORT_Memcpy(&keyData[2+cert->derIssuer.len], cert->serialNumber.data,
- cert->serialNumber.len);
-
- ADDITEM (signer->certs, type, NULL, fing, sizeof (JAR_Cert));
- return 0;
-
-loser:
- if (fing) {
- if (fing->cert)
- CERT_DestroyCertificate (fing->cert);
- PORT_Free(fing);
- }
- return JAR_ERR_MEMORY;
-}
-
-/*
- * e a t _ l i n e
- *
- * Reads and/or modifies input buffer "data" of length "*len".
- * This function does zero, one or two of the following tasks:
- * 1) if "lines" is non-zero, it reads and discards that many lines from
- * the input. NUL characters are treated as end-of-line characters,
- * not as end-of-input characters. The input is NOT NUL terminated.
- * Note: presently, all callers pass either 0 or 1 for lines.
- * 2) After skipping the specified number of input lines, if "eating" is
- * non-zero, it finds the end of the next line of input and replaces
- * the end of line character(s) with a NUL character.
- * This function modifies the input buffer, containing the file, in place.
- * This function handles PC, Mac, and Unix style text files.
- * On entry, *len contains the maximum number of characters that this
- * function should ever examine, starting with the character in *data.
- * On return, *len is reduced by the number of characters skipped by the
- * first task, if any;
- * If lines is zero and eating is false, this function returns
- * the value in the data argument, but otherwise does nothing.
- */
-static char *
-jar_eat_line(int lines, int eating, char *data, long *len)
-{
- char *start = data;
- long maxLen = *len;
-
- if (maxLen <= 0)
- return start;
-
-#define GO_ON ((data - start) < maxLen)
-
- /* Eat the requisite number of lines, if any;
- prior to terminating the current line with a 0. */
- for (/* yip */ ; lines > 0; lines--) {
- while (GO_ON && *data && *data != '\r' && *data != '\n')
- data++;
-
- /* Eat any leading CR */
- if (GO_ON && *data == '\r')
- data++;
-
- /* After the CR, ok to eat one LF */
- if (GO_ON && *data == '\n')
- data++;
-
- /* If there are NULs, this function probably put them there */
- while (GO_ON && !*data)
- data++;
- }
- maxLen -= data - start; /* we have this many characters left. */
- *len = maxLen;
- start = data; /* now start again here. */
- if (maxLen > 0 && eating) {
- /* Terminate this line with a 0 */
- while (GO_ON && *data && *data != '\n' && *data != '\r')
- data++;
-
- /* If not past the end, we are allowed to eat one CR */
- if (GO_ON && *data == '\r')
- *data++ = 0;
-
- /* After the CR (if any), if not past the end, ok to eat one LF */
- if (GO_ON && *data == '\n')
- *data++ = 0;
- }
- return start;
-}
-#undef GO_ON
-
-/*
- * j a r _ d i g e s t _ s e c t i o n
- *
- * Return the digests of the next section of the manifest file.
- * Does not damage the manifest file, unlike parse_manifest.
- *
- */
-static JAR_Digest *
-jar_digest_section(char *manifest, long length)
-{
- long global_len;
- char *global_end;
-
- global_end = manifest;
- global_len = length;
-
- while (global_len > 0) {
- global_end = jar_eat_line(1, PR_FALSE, global_end, &global_len);
- if (global_len > 0 && (*global_end == 0 || *global_end == '\n'))
- break;
- }
- return JAR_calculate_digest (manifest, global_end - manifest);
-}
-
-/*
- * J A R _ v e r i f y _ d i g e s t
- *
- * Verifies that a precalculated digest matches the
- * expected value in the manifest.
- *
- */
-int PR_CALLBACK
-JAR_verify_digest(JAR *jar, const char *name, JAR_Digest *dig)
-{
- JAR_Item *it;
- JAR_Digest *shindig;
- ZZLink *link;
- ZZList *list = jar->hashes;
- int result1 = 0;
- int result2 = 0;
-
-
- if (jar->valid < 0) {
- /* signature not valid */
- return JAR_ERR_SIG;
- }
- if (ZZ_ListEmpty (list)) {
- /* empty list */
- return JAR_ERR_PNF;
- }
-
- for (link = ZZ_ListHead (list);
- !ZZ_ListIterDone (list, link);
- link = link->next) {
- it = link->thing;
- if (it->type == jarTypeMF
- && it->pathname && !PORT_Strcmp(it->pathname, name)) {
- shindig = (JAR_Digest *) it->data;
- if (shindig->md5_status) {
- if (shindig->md5_status == jarHashBad)
- return JAR_ERR_HASH;
- result1 = memcmp (dig->md5, shindig->md5, MD5_LENGTH);
- }
- if (shindig->sha1_status) {
- if (shindig->sha1_status == jarHashBad)
- return JAR_ERR_HASH;
- result2 = memcmp (dig->sha1, shindig->sha1, SHA1_LENGTH);
- }
- return (result1 == 0 && result2 == 0) ? 0 : JAR_ERR_HASH;
- }
- }
- return JAR_ERR_PNF;
-}
-
-
-
-
-
-
-
-/*
- * J A R _ f e t c h _ c e r t
- *
- * Given an opaque identifier of a certificate,
- * return the full certificate.
- *
- * The new function, which retrieves by key.
- *
- */
-CERTCertificate *
-JAR_fetch_cert(long length, void *key)
-{
- CERTIssuerAndSN issuerSN;
- CERTCertificate *cert = NULL;
- CERTCertDBHandle *certdb;
-
- certdb = JAR_open_database();
- if (certdb) {
- unsigned char *keyData = (unsigned char *)key;
- issuerSN.derIssuer.len = (keyData[0] << 8) + keyData[0];
- issuerSN.derIssuer.data = &keyData[2];
- issuerSN.serialNumber.len = length - (2 + issuerSN.derIssuer.len);
- issuerSN.serialNumber.data = &keyData[2+issuerSN.derIssuer.len];
- cert = CERT_FindCertByIssuerAndSN (certdb, &issuerSN);
- JAR_close_database (certdb);
- }
- return cert;
-}
-
-/*
- * j a r _ g e t _ m f _ d i g e s t
- *
- * Retrieve a corresponding saved digest over a section
- * of the main manifest file.
- *
- */
-static JAR_Digest *
-jar_get_mf_digest(JAR *jar, char *pathname)
-{
- JAR_Item *it;
- JAR_Digest *dig;
- ZZLink *link;
- ZZList *list = jar->manifest;
-
- if (ZZ_ListEmpty (list))
- return NULL;
-
- for (link = ZZ_ListHead (list);
- !ZZ_ListIterDone (list, link);
- link = link->next) {
- it = link->thing;
- if (it->type == jarTypeSect
- && it->pathname && !PORT_Strcmp(it->pathname, pathname)) {
- dig = (JAR_Digest *) it->data;
- return dig;
- }
- }
- return NULL;
-}
-
-/*
- * j a r _ b a s e n a m e
- *
- * Return the basename -- leading components of path stripped off,
- * extension ripped off -- of a path.
- *
- */
-static char *
-jar_basename(const char *path)
-{
- char *pith, *e, *basename, *ext;
-
- if (path == NULL)
- return PORT_Strdup("");
-
- pith = PORT_Strdup(path);
- basename = pith;
- while (1) {
- for (e = basename; *e && *e != '/' && *e != '\\'; e++)
- /* yip */ ;
- if (*e)
- basename = ++e;
- else
- break;
- }
-
- if ((ext = PORT_Strrchr(basename, '.')) != NULL)
- *ext = 0;
-
- /* We already have the space allocated */
- PORT_Strcpy(pith, basename);
- return pith;
-}
-
-/*
- * + + + + + + + + + + + + + + +
- *
- * CRYPTO ROUTINES FOR JAR
- *
- * The following functions are the cryptographic
- * interface to PKCS7 for Jarnatures.
- *
- * + + + + + + + + + + + + + + +
- *
- */
-
-/*
- * j a r _ c a t c h _ b y t e s
- *
- * In the event signatures contain enveloped data, it will show up here.
- * But note that the lib/pkcs7 routines aren't ready for it.
- *
- */
-static void
-jar_catch_bytes(void *arg, const char *buf, unsigned long len)
-{
- /* Actually this should never be called, since there is
- presumably no data in the signature itself. */
-}
-
-/*
- * j a r _ v a l i d a t e _ p k c s 7
- *
- * Validate (and decode, if necessary) a binary pkcs7
- * signature in DER format.
- *
- */
-static int
-jar_validate_pkcs7(JAR *jar, JAR_Signer *signer, char *data, long length)
-{
-
- SEC_PKCS7ContentInfo *cinfo = NULL;
- SEC_PKCS7DecoderContext *dcx;
- PRBool goodSig;
- int status = 0;
- SECItem detdig;
-
- PORT_Assert( jar != NULL && signer != NULL );
-
- if (jar == NULL || signer == NULL)
- return JAR_ERR_ORDER;
-
- signer->valid = JAR_ERR_SIG;
-
- /* We need a context if we can get one */
- dcx = SEC_PKCS7DecoderStart(jar_catch_bytes, NULL /*cb_arg*/,
- NULL /*getpassword*/, jar->mw,
- NULL, NULL, NULL);
- if (dcx == NULL) {
- /* strange pkcs7 failure */
- return JAR_ERR_PK7;
- }
-
- SEC_PKCS7DecoderUpdate (dcx, data, length);
- cinfo = SEC_PKCS7DecoderFinish (dcx);
- if (cinfo == NULL) {
- /* strange pkcs7 failure */
- return JAR_ERR_PK7;
- }
- if (SEC_PKCS7ContentIsEncrypted (cinfo)) {
- /* content was encrypted, fail */
- return JAR_ERR_PK7;
- }
- if (SEC_PKCS7ContentIsSigned (cinfo) == PR_FALSE) {
- /* content was not signed, fail */
- return JAR_ERR_PK7;
- }
-
- PORT_SetError(0);
-
- /* use SHA1 only */
- detdig.len = SHA1_LENGTH;
- detdig.data = signer->digest->sha1;
- goodSig = SEC_PKCS7VerifyDetachedSignature(cinfo,
- certUsageObjectSigner,
- &detdig, HASH_AlgSHA1,
- PR_FALSE);
- jar_gather_signers(jar, signer, cinfo);
- if (goodSig == PR_TRUE) {
- /* signature is valid */
- signer->valid = 0;
- } else {
- status = PORT_GetError();
- PORT_Assert( status < 0 );
- if (status >= 0)
- status = JAR_ERR_SIG;
- jar->valid = status;
- signer->valid = status;
- }
- jar->pkcs7 = PR_TRUE;
- signer->pkcs7 = PR_TRUE;
- SEC_PKCS7DestroyContentInfo(cinfo);
- return status;
-}
-
-/*
- * j a r _ g a t h e r _ s i g n e r s
- *
- * Add the single signer of this signature to the
- * certificate linked list.
- *
- */
-static int
-jar_gather_signers(JAR *jar, JAR_Signer *signer, SEC_PKCS7ContentInfo *cinfo)
-{
- int result;
- CERTCertificate *cert;
- CERTCertDBHandle *certdb;
- SEC_PKCS7SignedData *sdp = cinfo->content.signedData;
- SEC_PKCS7SignerInfo **pksigners, *pksigner;
-
- if (sdp == NULL)
- return JAR_ERR_PK7;
-
- pksigners = sdp->signerInfos;
- /* permit exactly one signer */
- if (pksigners == NULL || pksigners [0] == NULL || pksigners [1] != NULL)
- return JAR_ERR_PK7;
-
- pksigner = *pksigners;
- cert = pksigner->cert;
-
- if (cert == NULL)
- return JAR_ERR_PK7;
-
- certdb = JAR_open_database();
- if (certdb == NULL)
- return JAR_ERR_GENERAL;
-
- result = jar_add_cert(jar, signer, jarTypeSign, cert);
- JAR_close_database (certdb);
- return result;
-}
-
-/*
- * j a r _ o p e n _ d a t a b a s e
- *
- * Open the certificate database,
- * for use by JAR functions.
- *
- */
-CERTCertDBHandle *
-JAR_open_database(void)
-{
- return CERT_GetDefaultCertDB();
-}
-
-/*
- * j a r _ c l o s e _ d a t a b a s e
- *
- * Close the certificate database.
- * For use by JAR functions.
- *
- */
-int
-JAR_close_database(CERTCertDBHandle *certdb)
-{
- return 0;
-}
-
-
-/*
- * j a r _ s i g n a l
- *
- * Nonfatal errors come here to callback Java.
- *
- */
-static int
-jar_signal(int status, JAR *jar, const char *metafile, char *pathname)
-{
- char *errstring = JAR_get_error (status);
- if (jar->signal) {
- (*jar->signal) (status, jar, metafile, pathname, errstring);
- return 0;
- }
- return status;
-}
-
-/*
- * j a r _ a p p e n d
- *
- * Tack on an element to one of a JAR's linked
- * lists, with rudimentary error handling.
- *
- */
-int
-jar_append(ZZList *list, int type, char *pathname, void *data, size_t size)
-{
- JAR_Item *it = PORT_ZNew(JAR_Item);
- ZZLink *entity;
-
- if (it == NULL)
- goto loser;
-
- if (pathname) {
- it->pathname = PORT_Strdup(pathname);
- if (it->pathname == NULL)
- goto loser;
- }
-
- it->type = (jarType)type;
- it->data = (unsigned char *) data;
- it->size = size;
- entity = ZZ_NewLink (it);
- if (entity) {
- ZZ_AppendLink (list, entity);
- return 0;
- }
-
-loser:
- if (it) {
- if (it->pathname)
- PORT_Free(it->pathname);
- PORT_Free(it);
- }
- return JAR_ERR_MEMORY;
-}