security/nss/lib/jar/jar.c

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:a06d4739c695
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 * JAR.C
7 *
8 * Jarnature.
9 * Routines common to signing and validating.
10 *
11 */
12
13 #include "jar.h"
14 #include "jarint.h"
15 #include "portreg.h"
16
17 static void
18 jar_destroy_list (ZZList *list);
19
20 static int
21 jar_find_first_cert(JAR_Signer *signer, int type, JAR_Item **it);
22
23 /*
24 * J A R _ n e w
25 *
26 * Create a new instantiation of a manifest representation.
27 * Use this as a token to any calls to this API.
28 *
29 */
30 JAR *
31 JAR_new(void)
32 {
33 JAR *jar;
34
35 if ((jar = (JAR*)PORT_ZAlloc (sizeof (JAR))) == NULL)
36 goto loser;
37 if ((jar->manifest = ZZ_NewList()) == NULL)
38 goto loser;
39 if ((jar->hashes = ZZ_NewList()) == NULL)
40 goto loser;
41 if ((jar->phy = ZZ_NewList()) == NULL)
42 goto loser;
43 if ((jar->metainfo = ZZ_NewList()) == NULL)
44 goto loser;
45 if ((jar->signers = ZZ_NewList()) == NULL)
46 goto loser;
47 return jar;
48
49 loser:
50 if (jar) {
51 if (jar->manifest)
52 ZZ_DestroyList (jar->manifest);
53 if (jar->hashes)
54 ZZ_DestroyList (jar->hashes);
55 if (jar->phy)
56 ZZ_DestroyList (jar->phy);
57 if (jar->metainfo)
58 ZZ_DestroyList (jar->metainfo);
59 if (jar->signers)
60 ZZ_DestroyList (jar->signers);
61 PORT_Free (jar);
62 }
63 return NULL;
64 }
65
66 /*
67 * J A R _ d e s t r o y
68 */
69 void PR_CALLBACK
70 JAR_destroy(JAR *jar)
71 {
72 PORT_Assert( jar != NULL );
73
74 if (jar == NULL)
75 return;
76
77 if (jar->fp)
78 JAR_FCLOSE ((PRFileDesc*)jar->fp);
79 if (jar->url)
80 PORT_Free (jar->url);
81 if (jar->filename)
82 PORT_Free (jar->filename);
83
84 /* Free the linked list elements */
85 jar_destroy_list (jar->manifest);
86 ZZ_DestroyList (jar->manifest);
87 jar_destroy_list (jar->hashes);
88 ZZ_DestroyList (jar->hashes);
89 jar_destroy_list (jar->phy);
90 ZZ_DestroyList (jar->phy);
91 jar_destroy_list (jar->metainfo);
92 ZZ_DestroyList (jar->metainfo);
93 jar_destroy_list (jar->signers);
94 ZZ_DestroyList (jar->signers);
95 PORT_Free (jar);
96 }
97
98 static void
99 jar_destroy_list(ZZList *list)
100 {
101 ZZLink *link, *oldlink;
102 JAR_Item *it;
103 JAR_Physical *phy;
104 JAR_Digest *dig;
105 JAR_Cert *fing;
106 JAR_Metainfo *met;
107 JAR_Signer *signer;
108
109 if (list && !ZZ_ListEmpty (list)) {
110 link = ZZ_ListHead (list);
111 while (!ZZ_ListIterDone (list, link)) {
112 it = link->thing;
113 if (!it)
114 goto next;
115 if (it->pathname)
116 PORT_Free (it->pathname);
117
118 switch (it->type) {
119 case jarTypeMeta:
120 met = (JAR_Metainfo *) it->data;
121 if (met) {
122 if (met->header)
123 PORT_Free (met->header);
124 if (met->info)
125 PORT_Free (met->info);
126 PORT_Free (met);
127 }
128 break;
129
130 case jarTypePhy:
131 phy = (JAR_Physical *) it->data;
132 if (phy)
133 PORT_Free (phy);
134 break;
135
136 case jarTypeSign:
137 fing = (JAR_Cert *) it->data;
138 if (fing) {
139 if (fing->cert)
140 CERT_DestroyCertificate (fing->cert);
141 if (fing->key)
142 PORT_Free (fing->key);
143 PORT_Free (fing);
144 }
145 break;
146
147 case jarTypeSect:
148 case jarTypeMF:
149 case jarTypeSF:
150 dig = (JAR_Digest *) it->data;
151 if (dig) {
152 PORT_Free (dig);
153 }
154 break;
155
156 case jarTypeOwner:
157 signer = (JAR_Signer *) it->data;
158 if (signer)
159 JAR_destroy_signer (signer);
160 break;
161
162 default:
163 /* PORT_Assert( 1 != 2 ); */
164 break;
165 }
166 PORT_Free (it);
167
168 next:
169 oldlink = link;
170 link = link->next;
171 ZZ_DestroyLink (oldlink);
172 }
173 }
174 }
175
176 /*
177 * J A R _ g e t _ m e t a i n f o
178 *
179 * Retrieve meta information from the manifest file.
180 * It doesn't matter whether it's from .MF or .SF, does it?
181 *
182 */
183
184 int
185 JAR_get_metainfo(JAR *jar, char *name, char *header, void **info,
186 unsigned long *length)
187 {
188 JAR_Item *it;
189 ZZLink *link;
190 ZZList *list;
191
192 PORT_Assert( jar != NULL && header != NULL );
193
194 if (jar == NULL || header == NULL)
195 return JAR_ERR_PNF;
196
197 list = jar->metainfo;
198
199 if (ZZ_ListEmpty (list))
200 return JAR_ERR_PNF;
201
202 for (link = ZZ_ListHead (list);
203 !ZZ_ListIterDone (list, link);
204 link = link->next) {
205 it = link->thing;
206 if (it->type == jarTypeMeta) {
207 JAR_Metainfo *met;
208
209 if ((name && !it->pathname) || (!name && it->pathname))
210 continue;
211 if (name && it->pathname && strcmp (it->pathname, name))
212 continue;
213 met = (JAR_Metainfo *) it->data;
214 if (!PORT_Strcasecmp (met->header, header)) {
215 *info = PORT_Strdup (met->info);
216 *length = PORT_Strlen (met->info);
217 return 0;
218 }
219 }
220 }
221 return JAR_ERR_PNF;
222 }
223
224 /*
225 * J A R _ f i n d
226 *
227 * Establish the search pattern for use
228 * by JAR_find_next, to traverse the filenames
229 * or certificates in the JAR structure.
230 *
231 * See jar.h for a description on how to use.
232 *
233 */
234 JAR_Context *
235 JAR_find (JAR *jar, char *pattern, jarType type)
236 {
237 JAR_Context *ctx;
238
239 PORT_Assert( jar != NULL );
240
241 if (!jar)
242 return NULL;
243
244 ctx = (JAR_Context *) PORT_ZAlloc (sizeof (JAR_Context));
245 if (ctx == NULL)
246 return NULL;
247
248 ctx->jar = jar;
249 if (pattern) {
250 if ((ctx->pattern = PORT_Strdup (pattern)) == NULL) {
251 PORT_Free (ctx);
252 return NULL;
253 }
254 }
255 ctx->finding = type;
256
257 switch (type) {
258 case jarTypeMF:
259 ctx->next = ZZ_ListHead (jar->hashes);
260 break;
261
262 case jarTypeSF:
263 case jarTypeSign:
264 ctx->next = NULL;
265 ctx->nextsign = ZZ_ListHead (jar->signers);
266 break;
267
268 case jarTypeSect:
269 ctx->next = ZZ_ListHead (jar->manifest);
270 break;
271
272 case jarTypePhy:
273 ctx->next = ZZ_ListHead (jar->phy);
274 break;
275
276 case jarTypeOwner:
277 if (jar->signers)
278 ctx->next = ZZ_ListHead (jar->signers);
279 else
280 ctx->next = NULL;
281 break;
282
283 case jarTypeMeta:
284 ctx->next = ZZ_ListHead (jar->metainfo);
285 break;
286
287 default:
288 PORT_Assert( 1 != 2);
289 break;
290 }
291 return ctx;
292 }
293
294 /*
295 * J A R _ f i n d _ e n d
296 *
297 * Destroy the find iterator context.
298 *
299 */
300 void
301 JAR_find_end (JAR_Context *ctx)
302 {
303 PORT_Assert( ctx != NULL );
304 if (ctx) {
305 if (ctx->pattern)
306 PORT_Free (ctx->pattern);
307 PORT_Free (ctx);
308 }
309 }
310
311 /*
312 * J A R _ f i n d _ n e x t
313 *
314 * Return the next item of the given type
315 * from one of the JAR linked lists.
316 *
317 */
318
319 int JAR_find_next (JAR_Context *ctx, JAR_Item **it)
320 {
321 JAR *jar;
322 ZZList *list = NULL;
323 int finding;
324 JAR_Signer *signer = NULL;
325
326 PORT_Assert( ctx != NULL );
327 PORT_Assert( ctx->jar != NULL );
328
329 jar = ctx->jar;
330
331 /* Internally, convert jarTypeSign to jarTypeSF, and return
332 the actual attached certificate later */
333 finding = (ctx->finding == jarTypeSign) ? jarTypeSF : ctx->finding;
334 if (ctx->nextsign) {
335 if (ZZ_ListIterDone (jar->signers, ctx->nextsign)) {
336 *it = NULL;
337 return -1;
338 }
339 PORT_Assert (ctx->nextsign->thing != NULL);
340 signer = (JAR_Signer*)ctx->nextsign->thing->data;
341 }
342
343 /* Find out which linked list to traverse. Then if
344 necessary, advance to the next linked list. */
345 while (1) {
346 switch (finding) {
347 case jarTypeSign: /* not any more */
348 PORT_Assert( finding != jarTypeSign );
349 list = signer->certs;
350 break;
351
352 case jarTypeSect:
353 list = jar->manifest;
354 break;
355
356 case jarTypePhy:
357 list = jar->phy;
358 break;
359
360 case jarTypeSF: /* signer, not jar */
361 PORT_Assert( signer != NULL );
362 list = signer ? signer->sf : NULL;
363 break;
364
365 case jarTypeMF:
366 list = jar->hashes;
367 break;
368
369 case jarTypeOwner:
370 list = jar->signers;
371 break;
372
373 case jarTypeMeta:
374 list = jar->metainfo;
375 break;
376
377 default:
378 PORT_Assert( 1 != 2 );
379 list = NULL;
380 break;
381 }
382 if (list == NULL) {
383 *it = NULL;
384 return -1;
385 }
386 /* When looping over lists of lists, advance to the next signer.
387 This is done when multiple signers are possible. */
388 if (ZZ_ListIterDone (list, ctx->next)) {
389 if (ctx->nextsign && jar->signers) {
390 ctx->nextsign = ctx->nextsign->next;
391 if (!ZZ_ListIterDone (jar->signers, ctx->nextsign)) {
392 PORT_Assert (ctx->nextsign->thing != NULL);
393 signer = (JAR_Signer*)ctx->nextsign->thing->data;
394 PORT_Assert( signer != NULL );
395 ctx->next = NULL;
396 continue;
397 }
398 }
399 *it = NULL;
400 return -1;
401 }
402
403 /* if the signer changed, still need to fill in the "next" link */
404 if (ctx->nextsign && ctx->next == NULL) {
405 switch (finding) {
406 case jarTypeSF:
407 ctx->next = ZZ_ListHead (signer->sf);
408 break;
409
410 case jarTypeSign:
411 ctx->next = ZZ_ListHead (signer->certs);
412 break;
413 }
414 }
415 PORT_Assert( ctx->next != NULL );
416 if (ctx->next == NULL) {
417 *it = NULL;
418 return -1;
419 }
420 while (!ZZ_ListIterDone (list, ctx->next)) {
421 *it = ctx->next->thing;
422 ctx->next = ctx->next->next;
423 if (!*it || (*it)->type != finding)
424 continue;
425 if (ctx->pattern && *ctx->pattern) {
426 if (PORT_RegExpSearch ((*it)->pathname, ctx->pattern))
427 continue;
428 }
429 /* We have a valid match. If this is a jarTypeSign
430 return the certificate instead.. */
431 if (ctx->finding == jarTypeSign) {
432 JAR_Item *itt;
433
434 /* just the first one for now */
435 if (jar_find_first_cert (signer, jarTypeSign, &itt) >= 0) {
436 *it = itt;
437 return 0;
438 }
439 continue;
440 }
441 return 0;
442 }
443 } /* end while */
444 }
445
446 static int
447 jar_find_first_cert (JAR_Signer *signer, int type, JAR_Item **it)
448 {
449 ZZLink *link;
450 ZZList *list = signer->certs;
451 int status = JAR_ERR_PNF;
452
453 *it = NULL;
454 if (ZZ_ListEmpty (list)) {
455 /* empty list */
456 return JAR_ERR_PNF;
457 }
458
459 for (link = ZZ_ListHead (list);
460 !ZZ_ListIterDone (list, link);
461 link = link->next) {
462 if (link->thing->type == type) {
463 *it = link->thing;
464 status = 0;
465 break;
466 }
467 }
468 return status;
469 }
470
471 JAR_Signer *
472 JAR_new_signer (void)
473 {
474 JAR_Signer *signer = (JAR_Signer *) PORT_ZAlloc (sizeof (JAR_Signer));
475 if (signer == NULL)
476 goto loser;
477
478 /* certs */
479 signer->certs = ZZ_NewList();
480 if (signer->certs == NULL)
481 goto loser;
482
483 /* sf */
484 signer->sf = ZZ_NewList();
485 if (signer->sf == NULL)
486 goto loser;
487 return signer;
488
489 loser:
490 if (signer) {
491 if (signer->certs)
492 ZZ_DestroyList (signer->certs);
493 if (signer->sf)
494 ZZ_DestroyList (signer->sf);
495 PORT_Free (signer);
496 }
497 return NULL;
498 }
499
500 void
501 JAR_destroy_signer(JAR_Signer *signer)
502 {
503 if (signer) {
504 if (signer->owner)
505 PORT_Free (signer->owner);
506 if (signer->digest)
507 PORT_Free (signer->digest);
508 jar_destroy_list (signer->sf);
509 ZZ_DestroyList (signer->sf);
510 jar_destroy_list (signer->certs);
511 ZZ_DestroyList (signer->certs);
512 PORT_Free (signer);
513 }
514 }
515
516 JAR_Signer *
517 jar_get_signer(JAR *jar, char *basename)
518 {
519 JAR_Item *it;
520 JAR_Context *ctx = JAR_find (jar, NULL, jarTypeOwner);
521 JAR_Signer *candidate;
522 JAR_Signer *signer = NULL;
523
524 if (ctx == NULL)
525 return NULL;
526
527 while (JAR_find_next (ctx, &it) >= 0) {
528 candidate = (JAR_Signer *) it->data;
529 if (*basename == '*' || !PORT_Strcmp (candidate->owner, basename)) {
530 signer = candidate;
531 break;
532 }
533 }
534 JAR_find_end (ctx);
535 return signer;
536 }
537
538 /*
539 * J A R _ g e t _ f i l e n a m e
540 *
541 * Returns the filename associated with
542 * a JAR structure.
543 *
544 */
545 char *
546 JAR_get_filename(JAR *jar)
547 {
548 return jar->filename;
549 }
550
551 /*
552 * J A R _ g e t _ u r l
553 *
554 * Returns the URL associated with
555 * a JAR structure. Nobody really uses this now.
556 *
557 */
558 char *
559 JAR_get_url(JAR *jar)
560 {
561 return jar->url;
562 }
563
564 /*
565 * J A R _ s e t _ c a l l b a c k
566 *
567 * Register some manner of callback function for this jar.
568 *
569 */
570 int
571 JAR_set_callback(int type, JAR *jar, jar_settable_callback_fn *fn)
572 {
573 if (type == JAR_CB_SIGNAL) {
574 jar->signal = fn;
575 return 0;
576 }
577 return -1;
578 }
579
580 /*
581 * Callbacks
582 *
583 */
584
585 /* To return an error string */
586 char *(*jar_fn_GetString) (int) = NULL;
587
588 /* To return an MWContext for Java */
589 void *(*jar_fn_FindSomeContext) (void) = NULL;
590
591 /* To fabricate an MWContext for FE_GetPassword */
592 void *(*jar_fn_GetInitContext) (void) = NULL;
593
594 void
595 JAR_init_callbacks(char *(*string_cb)(int),
596 void *(*find_cx)(void),
597 void *(*init_cx)(void))
598 {
599 jar_fn_GetString = string_cb;
600 jar_fn_FindSomeContext = find_cx;
601 jar_fn_GetInitContext = init_cx;
602 }
603
604 /*
605 * J A R _ g e t _ e r r o r
606 *
607 * This is provided to map internal JAR errors to strings for
608 * the Java console. Also, a DLL may call this function if it does
609 * not have access to the XP_GetString function.
610 *
611 * These strings aren't UI, since they are Java console only.
612 *
613 */
614 char *
615 JAR_get_error(int status)
616 {
617 char *errstring = NULL;
618
619 switch (status) {
620 case JAR_ERR_GENERAL:
621 errstring = "General JAR file error";
622 break;
623
624 case JAR_ERR_FNF:
625 errstring = "JAR file not found";
626 break;
627
628 case JAR_ERR_CORRUPT:
629 errstring = "Corrupt JAR file";
630 break;
631
632 case JAR_ERR_MEMORY:
633 errstring = "Out of memory";
634 break;
635
636 case JAR_ERR_DISK:
637 errstring = "Disk error (perhaps out of space)";
638 break;
639
640 case JAR_ERR_ORDER:
641 errstring = "Inconsistent files in META-INF directory";
642 break;
643
644 case JAR_ERR_SIG:
645 errstring = "Invalid digital signature file";
646 break;
647
648 case JAR_ERR_METADATA:
649 errstring = "JAR metadata failed verification";
650 break;
651
652 case JAR_ERR_ENTRY:
653 errstring = "No Manifest entry for this JAR entry";
654 break;
655
656 case JAR_ERR_HASH:
657 errstring = "Invalid Hash of this JAR entry";
658 break;
659
660 case JAR_ERR_PK7:
661 errstring = "Strange PKCS7 or RSA failure";
662 break;
663
664 case JAR_ERR_PNF:
665 errstring = "Path not found inside JAR file";
666 break;
667
668 default:
669 if (jar_fn_GetString) {
670 errstring = jar_fn_GetString (status);
671 } else {
672 /* this is not a normal situation, and would only be
673 called in cases of improper initialization */
674 char *err = (char*)PORT_Alloc (40);
675 if (err)
676 PR_snprintf (err, 39, "Error %d\n", status); /* leak me! */
677 else
678 err = "Error! Bad! Out of memory!";
679 return err;
680 }
681 break;
682 }
683 return errstring;
684 }

mercurial