michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef __JAR_h_ michael@0: #define __JAR_h_ michael@0: michael@0: /* michael@0: * In general, any functions that return pointers michael@0: * have memory owned by the caller. michael@0: * michael@0: */ michael@0: michael@0: /* security includes */ michael@0: #include "cert.h" michael@0: #include "hasht.h" michael@0: michael@0: /* nspr 2.0 includes */ michael@0: #include "prio.h" michael@0: michael@0: #define ZHUGEP michael@0: michael@0: #include michael@0: michael@0: /* various types */ michael@0: michael@0: typedef enum { michael@0: jarTypeMF = 2, michael@0: jarTypeSF = 3, michael@0: jarTypeMeta = 6, michael@0: jarTypePhy = 7, michael@0: jarTypeSign = 10, michael@0: jarTypeSect = 11, michael@0: jarTypeOwner = 13 michael@0: } jarType; michael@0: michael@0: /* void data in ZZList's contain JAR_Item type */ michael@0: typedef struct JAR_Item_ { michael@0: char *pathname; /* relative. inside zip file */ michael@0: jarType type; /* various types */ michael@0: size_t size; /* size of data below */ michael@0: void *data; /* totally opaque */ michael@0: } JAR_Item; michael@0: michael@0: /* hashes */ michael@0: typedef enum { michael@0: jarHashNone = 0, michael@0: jarHashBad = 1, michael@0: jarHashPresent = 2 michael@0: } jarHash; michael@0: michael@0: typedef struct JAR_Digest_ { michael@0: jarHash md5_status; michael@0: unsigned char md5 [MD5_LENGTH]; michael@0: jarHash sha1_status; michael@0: unsigned char sha1 [SHA1_LENGTH]; michael@0: } JAR_Digest; michael@0: michael@0: /* physical archive formats */ michael@0: typedef enum { michael@0: jarArchGuess = 0, michael@0: jarArchNone = 1, michael@0: jarArchZip = 2, michael@0: jarArchTar = 3 michael@0: } jarArch; michael@0: michael@0: #include "jar-ds.h" michael@0: michael@0: struct JAR_; michael@0: michael@0: typedef int jar_settable_callback_fn(int status, struct JAR_ *jar, michael@0: const char *metafile, char *pathname, michael@0: char *errortext); michael@0: michael@0: /* jar object */ michael@0: typedef struct JAR_ { michael@0: jarArch format; /* physical archive format */ michael@0: michael@0: char *url; /* Where it came from */ michael@0: char *filename; /* Disk location */ michael@0: FILE *fp; /* For multiple extractions */ michael@0: /* JAR_FILE */ michael@0: michael@0: /* various linked lists */ michael@0: ZZList *manifest; /* Digests of MF sections */ michael@0: ZZList *hashes; /* Digests of actual signed files */ michael@0: ZZList *phy; /* Physical layout of JAR file */ michael@0: ZZList *metainfo; /* Global metainfo */ michael@0: michael@0: JAR_Digest *globalmeta; /* digest of .MF global portion */ michael@0: michael@0: /* Below will change to a linked list to support multiple sigs */ michael@0: int pkcs7; /* Enforced opaqueness */ michael@0: int valid; /* PKCS7 signature validated */ michael@0: michael@0: ZZList *signers; /* the above, per signer */ michael@0: michael@0: /* Window context, very necessary for PKCS11 now */ michael@0: void *mw; /* MWContext window context */ michael@0: michael@0: /* Signal callback function */ michael@0: jar_settable_callback_fn *signal; michael@0: } JAR; michael@0: michael@0: /* michael@0: * Iterator michael@0: * michael@0: * Context for iterative operations. Certain operations michael@0: * require iterating multiple linked lists because of michael@0: * multiple signers. "nextsign" is used for this purpose. michael@0: * michael@0: */ michael@0: typedef struct JAR_Context_ { michael@0: JAR *jar; /* Jar we are searching */ michael@0: char *pattern; /* Regular expression */ michael@0: jarType finding; /* Type of item to find */ michael@0: ZZLink *next; /* Next item in find */ michael@0: ZZLink *nextsign; /* Next signer, sometimes */ michael@0: } JAR_Context; michael@0: michael@0: typedef struct JAR_Signer_ { michael@0: int pkcs7; /* Enforced opaqueness */ michael@0: int valid; /* PKCS7 signature validated */ michael@0: char *owner; /* name of .RSA file */ michael@0: JAR_Digest *digest; /* of .SF file */ michael@0: ZZList *sf; /* Linked list of .SF file contents */ michael@0: ZZList *certs; /* Signing information */ michael@0: } JAR_Signer; michael@0: michael@0: /* Meta informaton, or "policy", from the manifest file. michael@0: Right now just one tuple per JAR_Item. */ michael@0: typedef struct JAR_Metainfo_ { michael@0: char *header; michael@0: char *info; michael@0: } JAR_Metainfo; michael@0: michael@0: /* This should not be global */ michael@0: typedef struct JAR_Physical_ { michael@0: unsigned char compression; michael@0: unsigned long offset; michael@0: unsigned long length; michael@0: unsigned long uncompressed_length; michael@0: #if defined(XP_UNIX) || defined(XP_BEOS) michael@0: PRUint16 mode; michael@0: #endif michael@0: } JAR_Physical; michael@0: michael@0: typedef struct JAR_Cert_ { michael@0: size_t length; michael@0: void *key; michael@0: CERTCertificate *cert; michael@0: } JAR_Cert; michael@0: michael@0: michael@0: /* certificate stuff */ michael@0: typedef enum { michael@0: jarCertCompany = 1, michael@0: jarCertCA = 2, michael@0: jarCertSerial = 3, michael@0: jarCertExpires = 4, michael@0: jarCertNickname = 5, michael@0: jarCertFinger = 6, michael@0: jarCertJavaHack = 100 michael@0: } jarCert; michael@0: michael@0: /* callback types */ michael@0: #define JAR_CB_SIGNAL 1 michael@0: michael@0: /* michael@0: * This is the base for the JAR error codes. It will michael@0: * change when these are incorporated into allxpstr.c, michael@0: * but right now they won't let me put them there. michael@0: * michael@0: */ michael@0: #ifndef SEC_ERR_BASE michael@0: #define SEC_ERR_BASE (-0x2000) michael@0: #endif michael@0: michael@0: #define JAR_BASE SEC_ERR_BASE + 300 michael@0: michael@0: /* Jar specific error definitions */ michael@0: michael@0: #define JAR_ERR_GENERAL (JAR_BASE + 1) michael@0: #define JAR_ERR_FNF (JAR_BASE + 2) michael@0: #define JAR_ERR_CORRUPT (JAR_BASE + 3) michael@0: #define JAR_ERR_MEMORY (JAR_BASE + 4) michael@0: #define JAR_ERR_DISK (JAR_BASE + 5) michael@0: #define JAR_ERR_ORDER (JAR_BASE + 6) michael@0: #define JAR_ERR_SIG (JAR_BASE + 7) michael@0: #define JAR_ERR_METADATA (JAR_BASE + 8) michael@0: #define JAR_ERR_ENTRY (JAR_BASE + 9) michael@0: #define JAR_ERR_HASH (JAR_BASE + 10) michael@0: #define JAR_ERR_PK7 (JAR_BASE + 11) michael@0: #define JAR_ERR_PNF (JAR_BASE + 12) michael@0: michael@0: /* Function declarations */ michael@0: michael@0: extern JAR *JAR_new (void); michael@0: michael@0: extern void PR_CALLBACK JAR_destroy (JAR *jar); michael@0: michael@0: extern char *JAR_get_error (int status); michael@0: michael@0: extern int JAR_set_callback(int type, JAR *jar, jar_settable_callback_fn *fn); michael@0: michael@0: extern void michael@0: JAR_init_callbacks(char *(*string_cb)(int), michael@0: void *(*find_cx)(void), michael@0: void *(*init_cx)(void) ); michael@0: michael@0: /* michael@0: * JAR_set_context michael@0: * michael@0: * PKCS11 may require a password to be entered by the user michael@0: * before any crypto routines may be called. This will require michael@0: * a window context if used from inside Mozilla. michael@0: * michael@0: * Call this routine with your context before calling michael@0: * verifying or signing. If you have no context, call with NULL michael@0: * and one will be chosen for you. michael@0: * michael@0: */ michael@0: int JAR_set_context (JAR *jar, void /*MWContext*/ *mw); michael@0: michael@0: /* michael@0: * Iterative operations michael@0: * michael@0: * JAR_find sets up for repeated calls with JAR_find_next. michael@0: * I never liked findfirst and findnext, this is nicer. michael@0: * michael@0: * Pattern contains a relative pathname to match inside the michael@0: * archive. It is currently assumed to be "*". michael@0: * michael@0: * To use: michael@0: * michael@0: * JAR_Item *item; michael@0: * JAR_find (jar, "*.class", jarTypeMF); michael@0: * while (JAR_find_next (jar, &item) >= 0) michael@0: * { do stuff } michael@0: * michael@0: */ michael@0: michael@0: /* Replacement functions with an external context */ michael@0: michael@0: extern JAR_Context *JAR_find (JAR *jar, char *pattern, jarType type); michael@0: michael@0: extern int JAR_find_next (JAR_Context *ctx, JAR_Item **it); michael@0: michael@0: extern void JAR_find_end (JAR_Context *ctx); michael@0: michael@0: /* michael@0: * Function to parse manifest file: michael@0: * michael@0: * Many signatures may be attached to a single filename located michael@0: * inside the zip file. We only support one. michael@0: * michael@0: * Several manifests may be included in the zip file. michael@0: * michael@0: * You must pass the MANIFEST.MF file before any .SF files. michael@0: * michael@0: * Right now this returns a big ole list, privately in the jar structure. michael@0: * If you need to traverse it, use JAR_find if possible. michael@0: * michael@0: * The path is needed to determine what type of binary signature is michael@0: * being passed, though it is technically not needed for manifest files. michael@0: * michael@0: * When parsing an ASCII file, null terminate the ASCII raw_manifest michael@0: * prior to sending it, and indicate a length of 0. For binary digital michael@0: * signatures only, indicate the true length of the signature. michael@0: * (This is legacy behavior.) michael@0: * michael@0: * You may free the manifest after parsing it. michael@0: * michael@0: */ michael@0: michael@0: extern int michael@0: JAR_parse_manifest(JAR *jar, char *raw_manifest, long length, const char *path, michael@0: const char *url); michael@0: michael@0: /* michael@0: * Verify data (nonstreaming). The signature is actually michael@0: * checked by JAR_parse_manifest or JAR_pass_archive. michael@0: * michael@0: */ michael@0: michael@0: extern JAR_Digest * PR_CALLBACK michael@0: JAR_calculate_digest(void *data, long length); michael@0: michael@0: extern int PR_CALLBACK michael@0: JAR_verify_digest(JAR *jar, const char *name, JAR_Digest *dig); michael@0: michael@0: extern int michael@0: JAR_digest_file(char *filename, JAR_Digest *dig); michael@0: michael@0: /* michael@0: * Meta information michael@0: * michael@0: * Currently, since this call does not support passing of an owner michael@0: * (certificate, or physical name of the .sf file), it is restricted to michael@0: * returning information located in the manifest.mf file. michael@0: * michael@0: * Meta information is a name/value pair inside the archive file. Here, michael@0: * the name is passed in *header and value returned in **info. michael@0: * michael@0: * Pass a NULL as the name to retrieve metainfo from the global section. michael@0: * michael@0: * Data is returned in **info, of size *length. The return value michael@0: * will indicate if no data was found. michael@0: * michael@0: */ michael@0: michael@0: extern int michael@0: JAR_get_metainfo(JAR *jar, char *name, char *header, void **info, michael@0: unsigned long *length); michael@0: michael@0: extern char *JAR_get_filename (JAR *jar); michael@0: michael@0: extern char *JAR_get_url (JAR *jar); michael@0: michael@0: /* save the certificate with this fingerprint in persistent michael@0: storage, somewhere, for retrieval in a future session when there michael@0: is no corresponding JAR structure. */ michael@0: extern int PR_CALLBACK michael@0: JAR_stash_cert(JAR *jar, long keylen, void *key); michael@0: michael@0: /* retrieve a certificate presumably stashed with the above michael@0: function, but may be any certificate. Type is &CERTCertificate */ michael@0: CERTCertificate * michael@0: JAR_fetch_cert(long length, void *key); michael@0: michael@0: /* michael@0: * New functions to handle archives alone michael@0: * (call JAR_new beforehand) michael@0: * michael@0: * JAR_pass_archive acts much like parse_manifest. Certificates michael@0: * are returned in the JAR structure but as opaque data. When calling michael@0: * JAR_verified_extract you still need to decide which of these michael@0: * certificates to honor. michael@0: * michael@0: * Code to examine a JAR structure is in jarbert.c. You can obtain both michael@0: * a list of filenames and certificates from traversing the linked list. michael@0: * michael@0: */ michael@0: extern int michael@0: JAR_pass_archive(JAR *jar, jarArch format, char *filename, const char *url); michael@0: michael@0: /* michael@0: * Same thing, but don't check signatures michael@0: */ michael@0: extern int michael@0: JAR_pass_archive_unverified(JAR *jar, jarArch format, char *filename, michael@0: const char *url); michael@0: michael@0: /* michael@0: * Extracts a relative pathname from the archive and places it michael@0: * in the filename specified. michael@0: * michael@0: * Call JAR_set_nailed if you want to keep the file descriptors michael@0: * open between multiple calls to JAR_verify_extract. michael@0: * michael@0: */ michael@0: extern int michael@0: JAR_verified_extract(JAR *jar, char *path, char *outpath); michael@0: michael@0: /* michael@0: * JAR_extract does no crypto checking. This can be used if you michael@0: * need to extract a manifest file or signature, etc. michael@0: * michael@0: */ michael@0: extern int michael@0: JAR_extract(JAR *jar, char *path, char *outpath); michael@0: michael@0: #endif /* __JAR_h_ */