Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #ifndef __JAR_h_ |
michael@0 | 6 | #define __JAR_h_ |
michael@0 | 7 | |
michael@0 | 8 | /* |
michael@0 | 9 | * In general, any functions that return pointers |
michael@0 | 10 | * have memory owned by the caller. |
michael@0 | 11 | * |
michael@0 | 12 | */ |
michael@0 | 13 | |
michael@0 | 14 | /* security includes */ |
michael@0 | 15 | #include "cert.h" |
michael@0 | 16 | #include "hasht.h" |
michael@0 | 17 | |
michael@0 | 18 | /* nspr 2.0 includes */ |
michael@0 | 19 | #include "prio.h" |
michael@0 | 20 | |
michael@0 | 21 | #define ZHUGEP |
michael@0 | 22 | |
michael@0 | 23 | #include <stdio.h> |
michael@0 | 24 | |
michael@0 | 25 | /* various types */ |
michael@0 | 26 | |
michael@0 | 27 | typedef enum { |
michael@0 | 28 | jarTypeMF = 2, |
michael@0 | 29 | jarTypeSF = 3, |
michael@0 | 30 | jarTypeMeta = 6, |
michael@0 | 31 | jarTypePhy = 7, |
michael@0 | 32 | jarTypeSign = 10, |
michael@0 | 33 | jarTypeSect = 11, |
michael@0 | 34 | jarTypeOwner = 13 |
michael@0 | 35 | } jarType; |
michael@0 | 36 | |
michael@0 | 37 | /* void data in ZZList's contain JAR_Item type */ |
michael@0 | 38 | typedef struct JAR_Item_ { |
michael@0 | 39 | char *pathname; /* relative. inside zip file */ |
michael@0 | 40 | jarType type; /* various types */ |
michael@0 | 41 | size_t size; /* size of data below */ |
michael@0 | 42 | void *data; /* totally opaque */ |
michael@0 | 43 | } JAR_Item; |
michael@0 | 44 | |
michael@0 | 45 | /* hashes */ |
michael@0 | 46 | typedef enum { |
michael@0 | 47 | jarHashNone = 0, |
michael@0 | 48 | jarHashBad = 1, |
michael@0 | 49 | jarHashPresent = 2 |
michael@0 | 50 | } jarHash; |
michael@0 | 51 | |
michael@0 | 52 | typedef struct JAR_Digest_ { |
michael@0 | 53 | jarHash md5_status; |
michael@0 | 54 | unsigned char md5 [MD5_LENGTH]; |
michael@0 | 55 | jarHash sha1_status; |
michael@0 | 56 | unsigned char sha1 [SHA1_LENGTH]; |
michael@0 | 57 | } JAR_Digest; |
michael@0 | 58 | |
michael@0 | 59 | /* physical archive formats */ |
michael@0 | 60 | typedef enum { |
michael@0 | 61 | jarArchGuess = 0, |
michael@0 | 62 | jarArchNone = 1, |
michael@0 | 63 | jarArchZip = 2, |
michael@0 | 64 | jarArchTar = 3 |
michael@0 | 65 | } jarArch; |
michael@0 | 66 | |
michael@0 | 67 | #include "jar-ds.h" |
michael@0 | 68 | |
michael@0 | 69 | struct JAR_; |
michael@0 | 70 | |
michael@0 | 71 | typedef int jar_settable_callback_fn(int status, struct JAR_ *jar, |
michael@0 | 72 | const char *metafile, char *pathname, |
michael@0 | 73 | char *errortext); |
michael@0 | 74 | |
michael@0 | 75 | /* jar object */ |
michael@0 | 76 | typedef struct JAR_ { |
michael@0 | 77 | jarArch format; /* physical archive format */ |
michael@0 | 78 | |
michael@0 | 79 | char *url; /* Where it came from */ |
michael@0 | 80 | char *filename; /* Disk location */ |
michael@0 | 81 | FILE *fp; /* For multiple extractions */ |
michael@0 | 82 | /* JAR_FILE */ |
michael@0 | 83 | |
michael@0 | 84 | /* various linked lists */ |
michael@0 | 85 | ZZList *manifest; /* Digests of MF sections */ |
michael@0 | 86 | ZZList *hashes; /* Digests of actual signed files */ |
michael@0 | 87 | ZZList *phy; /* Physical layout of JAR file */ |
michael@0 | 88 | ZZList *metainfo; /* Global metainfo */ |
michael@0 | 89 | |
michael@0 | 90 | JAR_Digest *globalmeta; /* digest of .MF global portion */ |
michael@0 | 91 | |
michael@0 | 92 | /* Below will change to a linked list to support multiple sigs */ |
michael@0 | 93 | int pkcs7; /* Enforced opaqueness */ |
michael@0 | 94 | int valid; /* PKCS7 signature validated */ |
michael@0 | 95 | |
michael@0 | 96 | ZZList *signers; /* the above, per signer */ |
michael@0 | 97 | |
michael@0 | 98 | /* Window context, very necessary for PKCS11 now */ |
michael@0 | 99 | void *mw; /* MWContext window context */ |
michael@0 | 100 | |
michael@0 | 101 | /* Signal callback function */ |
michael@0 | 102 | jar_settable_callback_fn *signal; |
michael@0 | 103 | } JAR; |
michael@0 | 104 | |
michael@0 | 105 | /* |
michael@0 | 106 | * Iterator |
michael@0 | 107 | * |
michael@0 | 108 | * Context for iterative operations. Certain operations |
michael@0 | 109 | * require iterating multiple linked lists because of |
michael@0 | 110 | * multiple signers. "nextsign" is used for this purpose. |
michael@0 | 111 | * |
michael@0 | 112 | */ |
michael@0 | 113 | typedef struct JAR_Context_ { |
michael@0 | 114 | JAR *jar; /* Jar we are searching */ |
michael@0 | 115 | char *pattern; /* Regular expression */ |
michael@0 | 116 | jarType finding; /* Type of item to find */ |
michael@0 | 117 | ZZLink *next; /* Next item in find */ |
michael@0 | 118 | ZZLink *nextsign; /* Next signer, sometimes */ |
michael@0 | 119 | } JAR_Context; |
michael@0 | 120 | |
michael@0 | 121 | typedef struct JAR_Signer_ { |
michael@0 | 122 | int pkcs7; /* Enforced opaqueness */ |
michael@0 | 123 | int valid; /* PKCS7 signature validated */ |
michael@0 | 124 | char *owner; /* name of .RSA file */ |
michael@0 | 125 | JAR_Digest *digest; /* of .SF file */ |
michael@0 | 126 | ZZList *sf; /* Linked list of .SF file contents */ |
michael@0 | 127 | ZZList *certs; /* Signing information */ |
michael@0 | 128 | } JAR_Signer; |
michael@0 | 129 | |
michael@0 | 130 | /* Meta informaton, or "policy", from the manifest file. |
michael@0 | 131 | Right now just one tuple per JAR_Item. */ |
michael@0 | 132 | typedef struct JAR_Metainfo_ { |
michael@0 | 133 | char *header; |
michael@0 | 134 | char *info; |
michael@0 | 135 | } JAR_Metainfo; |
michael@0 | 136 | |
michael@0 | 137 | /* This should not be global */ |
michael@0 | 138 | typedef struct JAR_Physical_ { |
michael@0 | 139 | unsigned char compression; |
michael@0 | 140 | unsigned long offset; |
michael@0 | 141 | unsigned long length; |
michael@0 | 142 | unsigned long uncompressed_length; |
michael@0 | 143 | #if defined(XP_UNIX) || defined(XP_BEOS) |
michael@0 | 144 | PRUint16 mode; |
michael@0 | 145 | #endif |
michael@0 | 146 | } JAR_Physical; |
michael@0 | 147 | |
michael@0 | 148 | typedef struct JAR_Cert_ { |
michael@0 | 149 | size_t length; |
michael@0 | 150 | void *key; |
michael@0 | 151 | CERTCertificate *cert; |
michael@0 | 152 | } JAR_Cert; |
michael@0 | 153 | |
michael@0 | 154 | |
michael@0 | 155 | /* certificate stuff */ |
michael@0 | 156 | typedef enum { |
michael@0 | 157 | jarCertCompany = 1, |
michael@0 | 158 | jarCertCA = 2, |
michael@0 | 159 | jarCertSerial = 3, |
michael@0 | 160 | jarCertExpires = 4, |
michael@0 | 161 | jarCertNickname = 5, |
michael@0 | 162 | jarCertFinger = 6, |
michael@0 | 163 | jarCertJavaHack = 100 |
michael@0 | 164 | } jarCert; |
michael@0 | 165 | |
michael@0 | 166 | /* callback types */ |
michael@0 | 167 | #define JAR_CB_SIGNAL 1 |
michael@0 | 168 | |
michael@0 | 169 | /* |
michael@0 | 170 | * This is the base for the JAR error codes. It will |
michael@0 | 171 | * change when these are incorporated into allxpstr.c, |
michael@0 | 172 | * but right now they won't let me put them there. |
michael@0 | 173 | * |
michael@0 | 174 | */ |
michael@0 | 175 | #ifndef SEC_ERR_BASE |
michael@0 | 176 | #define SEC_ERR_BASE (-0x2000) |
michael@0 | 177 | #endif |
michael@0 | 178 | |
michael@0 | 179 | #define JAR_BASE SEC_ERR_BASE + 300 |
michael@0 | 180 | |
michael@0 | 181 | /* Jar specific error definitions */ |
michael@0 | 182 | |
michael@0 | 183 | #define JAR_ERR_GENERAL (JAR_BASE + 1) |
michael@0 | 184 | #define JAR_ERR_FNF (JAR_BASE + 2) |
michael@0 | 185 | #define JAR_ERR_CORRUPT (JAR_BASE + 3) |
michael@0 | 186 | #define JAR_ERR_MEMORY (JAR_BASE + 4) |
michael@0 | 187 | #define JAR_ERR_DISK (JAR_BASE + 5) |
michael@0 | 188 | #define JAR_ERR_ORDER (JAR_BASE + 6) |
michael@0 | 189 | #define JAR_ERR_SIG (JAR_BASE + 7) |
michael@0 | 190 | #define JAR_ERR_METADATA (JAR_BASE + 8) |
michael@0 | 191 | #define JAR_ERR_ENTRY (JAR_BASE + 9) |
michael@0 | 192 | #define JAR_ERR_HASH (JAR_BASE + 10) |
michael@0 | 193 | #define JAR_ERR_PK7 (JAR_BASE + 11) |
michael@0 | 194 | #define JAR_ERR_PNF (JAR_BASE + 12) |
michael@0 | 195 | |
michael@0 | 196 | /* Function declarations */ |
michael@0 | 197 | |
michael@0 | 198 | extern JAR *JAR_new (void); |
michael@0 | 199 | |
michael@0 | 200 | extern void PR_CALLBACK JAR_destroy (JAR *jar); |
michael@0 | 201 | |
michael@0 | 202 | extern char *JAR_get_error (int status); |
michael@0 | 203 | |
michael@0 | 204 | extern int JAR_set_callback(int type, JAR *jar, jar_settable_callback_fn *fn); |
michael@0 | 205 | |
michael@0 | 206 | extern void |
michael@0 | 207 | JAR_init_callbacks(char *(*string_cb)(int), |
michael@0 | 208 | void *(*find_cx)(void), |
michael@0 | 209 | void *(*init_cx)(void) ); |
michael@0 | 210 | |
michael@0 | 211 | /* |
michael@0 | 212 | * JAR_set_context |
michael@0 | 213 | * |
michael@0 | 214 | * PKCS11 may require a password to be entered by the user |
michael@0 | 215 | * before any crypto routines may be called. This will require |
michael@0 | 216 | * a window context if used from inside Mozilla. |
michael@0 | 217 | * |
michael@0 | 218 | * Call this routine with your context before calling |
michael@0 | 219 | * verifying or signing. If you have no context, call with NULL |
michael@0 | 220 | * and one will be chosen for you. |
michael@0 | 221 | * |
michael@0 | 222 | */ |
michael@0 | 223 | int JAR_set_context (JAR *jar, void /*MWContext*/ *mw); |
michael@0 | 224 | |
michael@0 | 225 | /* |
michael@0 | 226 | * Iterative operations |
michael@0 | 227 | * |
michael@0 | 228 | * JAR_find sets up for repeated calls with JAR_find_next. |
michael@0 | 229 | * I never liked findfirst and findnext, this is nicer. |
michael@0 | 230 | * |
michael@0 | 231 | * Pattern contains a relative pathname to match inside the |
michael@0 | 232 | * archive. It is currently assumed to be "*". |
michael@0 | 233 | * |
michael@0 | 234 | * To use: |
michael@0 | 235 | * |
michael@0 | 236 | * JAR_Item *item; |
michael@0 | 237 | * JAR_find (jar, "*.class", jarTypeMF); |
michael@0 | 238 | * while (JAR_find_next (jar, &item) >= 0) |
michael@0 | 239 | * { do stuff } |
michael@0 | 240 | * |
michael@0 | 241 | */ |
michael@0 | 242 | |
michael@0 | 243 | /* Replacement functions with an external context */ |
michael@0 | 244 | |
michael@0 | 245 | extern JAR_Context *JAR_find (JAR *jar, char *pattern, jarType type); |
michael@0 | 246 | |
michael@0 | 247 | extern int JAR_find_next (JAR_Context *ctx, JAR_Item **it); |
michael@0 | 248 | |
michael@0 | 249 | extern void JAR_find_end (JAR_Context *ctx); |
michael@0 | 250 | |
michael@0 | 251 | /* |
michael@0 | 252 | * Function to parse manifest file: |
michael@0 | 253 | * |
michael@0 | 254 | * Many signatures may be attached to a single filename located |
michael@0 | 255 | * inside the zip file. We only support one. |
michael@0 | 256 | * |
michael@0 | 257 | * Several manifests may be included in the zip file. |
michael@0 | 258 | * |
michael@0 | 259 | * You must pass the MANIFEST.MF file before any .SF files. |
michael@0 | 260 | * |
michael@0 | 261 | * Right now this returns a big ole list, privately in the jar structure. |
michael@0 | 262 | * If you need to traverse it, use JAR_find if possible. |
michael@0 | 263 | * |
michael@0 | 264 | * The path is needed to determine what type of binary signature is |
michael@0 | 265 | * being passed, though it is technically not needed for manifest files. |
michael@0 | 266 | * |
michael@0 | 267 | * When parsing an ASCII file, null terminate the ASCII raw_manifest |
michael@0 | 268 | * prior to sending it, and indicate a length of 0. For binary digital |
michael@0 | 269 | * signatures only, indicate the true length of the signature. |
michael@0 | 270 | * (This is legacy behavior.) |
michael@0 | 271 | * |
michael@0 | 272 | * You may free the manifest after parsing it. |
michael@0 | 273 | * |
michael@0 | 274 | */ |
michael@0 | 275 | |
michael@0 | 276 | extern int |
michael@0 | 277 | JAR_parse_manifest(JAR *jar, char *raw_manifest, long length, const char *path, |
michael@0 | 278 | const char *url); |
michael@0 | 279 | |
michael@0 | 280 | /* |
michael@0 | 281 | * Verify data (nonstreaming). The signature is actually |
michael@0 | 282 | * checked by JAR_parse_manifest or JAR_pass_archive. |
michael@0 | 283 | * |
michael@0 | 284 | */ |
michael@0 | 285 | |
michael@0 | 286 | extern JAR_Digest * PR_CALLBACK |
michael@0 | 287 | JAR_calculate_digest(void *data, long length); |
michael@0 | 288 | |
michael@0 | 289 | extern int PR_CALLBACK |
michael@0 | 290 | JAR_verify_digest(JAR *jar, const char *name, JAR_Digest *dig); |
michael@0 | 291 | |
michael@0 | 292 | extern int |
michael@0 | 293 | JAR_digest_file(char *filename, JAR_Digest *dig); |
michael@0 | 294 | |
michael@0 | 295 | /* |
michael@0 | 296 | * Meta information |
michael@0 | 297 | * |
michael@0 | 298 | * Currently, since this call does not support passing of an owner |
michael@0 | 299 | * (certificate, or physical name of the .sf file), it is restricted to |
michael@0 | 300 | * returning information located in the manifest.mf file. |
michael@0 | 301 | * |
michael@0 | 302 | * Meta information is a name/value pair inside the archive file. Here, |
michael@0 | 303 | * the name is passed in *header and value returned in **info. |
michael@0 | 304 | * |
michael@0 | 305 | * Pass a NULL as the name to retrieve metainfo from the global section. |
michael@0 | 306 | * |
michael@0 | 307 | * Data is returned in **info, of size *length. The return value |
michael@0 | 308 | * will indicate if no data was found. |
michael@0 | 309 | * |
michael@0 | 310 | */ |
michael@0 | 311 | |
michael@0 | 312 | extern int |
michael@0 | 313 | JAR_get_metainfo(JAR *jar, char *name, char *header, void **info, |
michael@0 | 314 | unsigned long *length); |
michael@0 | 315 | |
michael@0 | 316 | extern char *JAR_get_filename (JAR *jar); |
michael@0 | 317 | |
michael@0 | 318 | extern char *JAR_get_url (JAR *jar); |
michael@0 | 319 | |
michael@0 | 320 | /* save the certificate with this fingerprint in persistent |
michael@0 | 321 | storage, somewhere, for retrieval in a future session when there |
michael@0 | 322 | is no corresponding JAR structure. */ |
michael@0 | 323 | extern int PR_CALLBACK |
michael@0 | 324 | JAR_stash_cert(JAR *jar, long keylen, void *key); |
michael@0 | 325 | |
michael@0 | 326 | /* retrieve a certificate presumably stashed with the above |
michael@0 | 327 | function, but may be any certificate. Type is &CERTCertificate */ |
michael@0 | 328 | CERTCertificate * |
michael@0 | 329 | JAR_fetch_cert(long length, void *key); |
michael@0 | 330 | |
michael@0 | 331 | /* |
michael@0 | 332 | * New functions to handle archives alone |
michael@0 | 333 | * (call JAR_new beforehand) |
michael@0 | 334 | * |
michael@0 | 335 | * JAR_pass_archive acts much like parse_manifest. Certificates |
michael@0 | 336 | * are returned in the JAR structure but as opaque data. When calling |
michael@0 | 337 | * JAR_verified_extract you still need to decide which of these |
michael@0 | 338 | * certificates to honor. |
michael@0 | 339 | * |
michael@0 | 340 | * Code to examine a JAR structure is in jarbert.c. You can obtain both |
michael@0 | 341 | * a list of filenames and certificates from traversing the linked list. |
michael@0 | 342 | * |
michael@0 | 343 | */ |
michael@0 | 344 | extern int |
michael@0 | 345 | JAR_pass_archive(JAR *jar, jarArch format, char *filename, const char *url); |
michael@0 | 346 | |
michael@0 | 347 | /* |
michael@0 | 348 | * Same thing, but don't check signatures |
michael@0 | 349 | */ |
michael@0 | 350 | extern int |
michael@0 | 351 | JAR_pass_archive_unverified(JAR *jar, jarArch format, char *filename, |
michael@0 | 352 | const char *url); |
michael@0 | 353 | |
michael@0 | 354 | /* |
michael@0 | 355 | * Extracts a relative pathname from the archive and places it |
michael@0 | 356 | * in the filename specified. |
michael@0 | 357 | * |
michael@0 | 358 | * Call JAR_set_nailed if you want to keep the file descriptors |
michael@0 | 359 | * open between multiple calls to JAR_verify_extract. |
michael@0 | 360 | * |
michael@0 | 361 | */ |
michael@0 | 362 | extern int |
michael@0 | 363 | JAR_verified_extract(JAR *jar, char *path, char *outpath); |
michael@0 | 364 | |
michael@0 | 365 | /* |
michael@0 | 366 | * JAR_extract does no crypto checking. This can be used if you |
michael@0 | 367 | * need to extract a manifest file or signature, etc. |
michael@0 | 368 | * |
michael@0 | 369 | */ |
michael@0 | 370 | extern int |
michael@0 | 371 | JAR_extract(JAR *jar, char *path, char *outpath); |
michael@0 | 372 | |
michael@0 | 373 | #endif /* __JAR_h_ */ |