1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/jar/jar.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,684 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * JAR.C 1.10 + * 1.11 + * Jarnature. 1.12 + * Routines common to signing and validating. 1.13 + * 1.14 + */ 1.15 + 1.16 +#include "jar.h" 1.17 +#include "jarint.h" 1.18 +#include "portreg.h" 1.19 + 1.20 +static void 1.21 +jar_destroy_list (ZZList *list); 1.22 + 1.23 +static int 1.24 +jar_find_first_cert(JAR_Signer *signer, int type, JAR_Item **it); 1.25 + 1.26 +/* 1.27 + * J A R _ n e w 1.28 + * 1.29 + * Create a new instantiation of a manifest representation. 1.30 + * Use this as a token to any calls to this API. 1.31 + * 1.32 + */ 1.33 +JAR * 1.34 +JAR_new(void) 1.35 +{ 1.36 + JAR *jar; 1.37 + 1.38 + if ((jar = (JAR*)PORT_ZAlloc (sizeof (JAR))) == NULL) 1.39 + goto loser; 1.40 + if ((jar->manifest = ZZ_NewList()) == NULL) 1.41 + goto loser; 1.42 + if ((jar->hashes = ZZ_NewList()) == NULL) 1.43 + goto loser; 1.44 + if ((jar->phy = ZZ_NewList()) == NULL) 1.45 + goto loser; 1.46 + if ((jar->metainfo = ZZ_NewList()) == NULL) 1.47 + goto loser; 1.48 + if ((jar->signers = ZZ_NewList()) == NULL) 1.49 + goto loser; 1.50 + return jar; 1.51 + 1.52 +loser: 1.53 + if (jar) { 1.54 + if (jar->manifest) 1.55 + ZZ_DestroyList (jar->manifest); 1.56 + if (jar->hashes) 1.57 + ZZ_DestroyList (jar->hashes); 1.58 + if (jar->phy) 1.59 + ZZ_DestroyList (jar->phy); 1.60 + if (jar->metainfo) 1.61 + ZZ_DestroyList (jar->metainfo); 1.62 + if (jar->signers) 1.63 + ZZ_DestroyList (jar->signers); 1.64 + PORT_Free (jar); 1.65 + } 1.66 + return NULL; 1.67 +} 1.68 + 1.69 +/* 1.70 + * J A R _ d e s t r o y 1.71 + */ 1.72 +void PR_CALLBACK 1.73 +JAR_destroy(JAR *jar) 1.74 +{ 1.75 + PORT_Assert( jar != NULL ); 1.76 + 1.77 + if (jar == NULL) 1.78 + return; 1.79 + 1.80 + if (jar->fp) 1.81 + JAR_FCLOSE ((PRFileDesc*)jar->fp); 1.82 + if (jar->url) 1.83 + PORT_Free (jar->url); 1.84 + if (jar->filename) 1.85 + PORT_Free (jar->filename); 1.86 + 1.87 + /* Free the linked list elements */ 1.88 + jar_destroy_list (jar->manifest); 1.89 + ZZ_DestroyList (jar->manifest); 1.90 + jar_destroy_list (jar->hashes); 1.91 + ZZ_DestroyList (jar->hashes); 1.92 + jar_destroy_list (jar->phy); 1.93 + ZZ_DestroyList (jar->phy); 1.94 + jar_destroy_list (jar->metainfo); 1.95 + ZZ_DestroyList (jar->metainfo); 1.96 + jar_destroy_list (jar->signers); 1.97 + ZZ_DestroyList (jar->signers); 1.98 + PORT_Free (jar); 1.99 +} 1.100 + 1.101 +static void 1.102 +jar_destroy_list(ZZList *list) 1.103 +{ 1.104 + ZZLink *link, *oldlink; 1.105 + JAR_Item *it; 1.106 + JAR_Physical *phy; 1.107 + JAR_Digest *dig; 1.108 + JAR_Cert *fing; 1.109 + JAR_Metainfo *met; 1.110 + JAR_Signer *signer; 1.111 + 1.112 + if (list && !ZZ_ListEmpty (list)) { 1.113 + link = ZZ_ListHead (list); 1.114 + while (!ZZ_ListIterDone (list, link)) { 1.115 + it = link->thing; 1.116 + if (!it) 1.117 + goto next; 1.118 + if (it->pathname) 1.119 + PORT_Free (it->pathname); 1.120 + 1.121 + switch (it->type) { 1.122 + case jarTypeMeta: 1.123 + met = (JAR_Metainfo *) it->data; 1.124 + if (met) { 1.125 + if (met->header) 1.126 + PORT_Free (met->header); 1.127 + if (met->info) 1.128 + PORT_Free (met->info); 1.129 + PORT_Free (met); 1.130 + } 1.131 + break; 1.132 + 1.133 + case jarTypePhy: 1.134 + phy = (JAR_Physical *) it->data; 1.135 + if (phy) 1.136 + PORT_Free (phy); 1.137 + break; 1.138 + 1.139 + case jarTypeSign: 1.140 + fing = (JAR_Cert *) it->data; 1.141 + if (fing) { 1.142 + if (fing->cert) 1.143 + CERT_DestroyCertificate (fing->cert); 1.144 + if (fing->key) 1.145 + PORT_Free (fing->key); 1.146 + PORT_Free (fing); 1.147 + } 1.148 + break; 1.149 + 1.150 + case jarTypeSect: 1.151 + case jarTypeMF: 1.152 + case jarTypeSF: 1.153 + dig = (JAR_Digest *) it->data; 1.154 + if (dig) { 1.155 + PORT_Free (dig); 1.156 + } 1.157 + break; 1.158 + 1.159 + case jarTypeOwner: 1.160 + signer = (JAR_Signer *) it->data; 1.161 + if (signer) 1.162 + JAR_destroy_signer (signer); 1.163 + break; 1.164 + 1.165 + default: 1.166 + /* PORT_Assert( 1 != 2 ); */ 1.167 + break; 1.168 + } 1.169 + PORT_Free (it); 1.170 + 1.171 +next: 1.172 + oldlink = link; 1.173 + link = link->next; 1.174 + ZZ_DestroyLink (oldlink); 1.175 + } 1.176 + } 1.177 +} 1.178 + 1.179 +/* 1.180 + * J A R _ g e t _ m e t a i n f o 1.181 + * 1.182 + * Retrieve meta information from the manifest file. 1.183 + * It doesn't matter whether it's from .MF or .SF, does it? 1.184 + * 1.185 + */ 1.186 + 1.187 +int 1.188 +JAR_get_metainfo(JAR *jar, char *name, char *header, void **info, 1.189 + unsigned long *length) 1.190 +{ 1.191 + JAR_Item *it; 1.192 + ZZLink *link; 1.193 + ZZList *list; 1.194 + 1.195 + PORT_Assert( jar != NULL && header != NULL ); 1.196 + 1.197 + if (jar == NULL || header == NULL) 1.198 + return JAR_ERR_PNF; 1.199 + 1.200 + list = jar->metainfo; 1.201 + 1.202 + if (ZZ_ListEmpty (list)) 1.203 + return JAR_ERR_PNF; 1.204 + 1.205 + for (link = ZZ_ListHead (list); 1.206 + !ZZ_ListIterDone (list, link); 1.207 + link = link->next) { 1.208 + it = link->thing; 1.209 + if (it->type == jarTypeMeta) { 1.210 + JAR_Metainfo *met; 1.211 + 1.212 + if ((name && !it->pathname) || (!name && it->pathname)) 1.213 + continue; 1.214 + if (name && it->pathname && strcmp (it->pathname, name)) 1.215 + continue; 1.216 + met = (JAR_Metainfo *) it->data; 1.217 + if (!PORT_Strcasecmp (met->header, header)) { 1.218 + *info = PORT_Strdup (met->info); 1.219 + *length = PORT_Strlen (met->info); 1.220 + return 0; 1.221 + } 1.222 + } 1.223 + } 1.224 + return JAR_ERR_PNF; 1.225 +} 1.226 + 1.227 +/* 1.228 + * J A R _ f i n d 1.229 + * 1.230 + * Establish the search pattern for use 1.231 + * by JAR_find_next, to traverse the filenames 1.232 + * or certificates in the JAR structure. 1.233 + * 1.234 + * See jar.h for a description on how to use. 1.235 + * 1.236 + */ 1.237 +JAR_Context * 1.238 +JAR_find (JAR *jar, char *pattern, jarType type) 1.239 +{ 1.240 + JAR_Context *ctx; 1.241 + 1.242 + PORT_Assert( jar != NULL ); 1.243 + 1.244 + if (!jar) 1.245 + return NULL; 1.246 + 1.247 + ctx = (JAR_Context *) PORT_ZAlloc (sizeof (JAR_Context)); 1.248 + if (ctx == NULL) 1.249 + return NULL; 1.250 + 1.251 + ctx->jar = jar; 1.252 + if (pattern) { 1.253 + if ((ctx->pattern = PORT_Strdup (pattern)) == NULL) { 1.254 + PORT_Free (ctx); 1.255 + return NULL; 1.256 + } 1.257 + } 1.258 + ctx->finding = type; 1.259 + 1.260 + switch (type) { 1.261 + case jarTypeMF: 1.262 + ctx->next = ZZ_ListHead (jar->hashes); 1.263 + break; 1.264 + 1.265 + case jarTypeSF: 1.266 + case jarTypeSign: 1.267 + ctx->next = NULL; 1.268 + ctx->nextsign = ZZ_ListHead (jar->signers); 1.269 + break; 1.270 + 1.271 + case jarTypeSect: 1.272 + ctx->next = ZZ_ListHead (jar->manifest); 1.273 + break; 1.274 + 1.275 + case jarTypePhy: 1.276 + ctx->next = ZZ_ListHead (jar->phy); 1.277 + break; 1.278 + 1.279 + case jarTypeOwner: 1.280 + if (jar->signers) 1.281 + ctx->next = ZZ_ListHead (jar->signers); 1.282 + else 1.283 + ctx->next = NULL; 1.284 + break; 1.285 + 1.286 + case jarTypeMeta: 1.287 + ctx->next = ZZ_ListHead (jar->metainfo); 1.288 + break; 1.289 + 1.290 + default: 1.291 + PORT_Assert( 1 != 2); 1.292 + break; 1.293 + } 1.294 + return ctx; 1.295 +} 1.296 + 1.297 +/* 1.298 + * J A R _ f i n d _ e n d 1.299 + * 1.300 + * Destroy the find iterator context. 1.301 + * 1.302 + */ 1.303 +void 1.304 +JAR_find_end (JAR_Context *ctx) 1.305 +{ 1.306 + PORT_Assert( ctx != NULL ); 1.307 + if (ctx) { 1.308 + if (ctx->pattern) 1.309 + PORT_Free (ctx->pattern); 1.310 + PORT_Free (ctx); 1.311 + } 1.312 +} 1.313 + 1.314 +/* 1.315 + * J A R _ f i n d _ n e x t 1.316 + * 1.317 + * Return the next item of the given type 1.318 + * from one of the JAR linked lists. 1.319 + * 1.320 + */ 1.321 + 1.322 +int JAR_find_next (JAR_Context *ctx, JAR_Item **it) 1.323 +{ 1.324 + JAR *jar; 1.325 + ZZList *list = NULL; 1.326 + int finding; 1.327 + JAR_Signer *signer = NULL; 1.328 + 1.329 + PORT_Assert( ctx != NULL ); 1.330 + PORT_Assert( ctx->jar != NULL ); 1.331 + 1.332 + jar = ctx->jar; 1.333 + 1.334 + /* Internally, convert jarTypeSign to jarTypeSF, and return 1.335 + the actual attached certificate later */ 1.336 + finding = (ctx->finding == jarTypeSign) ? jarTypeSF : ctx->finding; 1.337 + if (ctx->nextsign) { 1.338 + if (ZZ_ListIterDone (jar->signers, ctx->nextsign)) { 1.339 + *it = NULL; 1.340 + return -1; 1.341 + } 1.342 + PORT_Assert (ctx->nextsign->thing != NULL); 1.343 + signer = (JAR_Signer*)ctx->nextsign->thing->data; 1.344 + } 1.345 + 1.346 + /* Find out which linked list to traverse. Then if 1.347 + necessary, advance to the next linked list. */ 1.348 + while (1) { 1.349 + switch (finding) { 1.350 + case jarTypeSign: /* not any more */ 1.351 + PORT_Assert( finding != jarTypeSign ); 1.352 + list = signer->certs; 1.353 + break; 1.354 + 1.355 + case jarTypeSect: 1.356 + list = jar->manifest; 1.357 + break; 1.358 + 1.359 + case jarTypePhy: 1.360 + list = jar->phy; 1.361 + break; 1.362 + 1.363 + case jarTypeSF: /* signer, not jar */ 1.364 + PORT_Assert( signer != NULL ); 1.365 + list = signer ? signer->sf : NULL; 1.366 + break; 1.367 + 1.368 + case jarTypeMF: 1.369 + list = jar->hashes; 1.370 + break; 1.371 + 1.372 + case jarTypeOwner: 1.373 + list = jar->signers; 1.374 + break; 1.375 + 1.376 + case jarTypeMeta: 1.377 + list = jar->metainfo; 1.378 + break; 1.379 + 1.380 + default: 1.381 + PORT_Assert( 1 != 2 ); 1.382 + list = NULL; 1.383 + break; 1.384 + } 1.385 + if (list == NULL) { 1.386 + *it = NULL; 1.387 + return -1; 1.388 + } 1.389 + /* When looping over lists of lists, advance to the next signer. 1.390 + This is done when multiple signers are possible. */ 1.391 + if (ZZ_ListIterDone (list, ctx->next)) { 1.392 + if (ctx->nextsign && jar->signers) { 1.393 + ctx->nextsign = ctx->nextsign->next; 1.394 + if (!ZZ_ListIterDone (jar->signers, ctx->nextsign)) { 1.395 + PORT_Assert (ctx->nextsign->thing != NULL); 1.396 + signer = (JAR_Signer*)ctx->nextsign->thing->data; 1.397 + PORT_Assert( signer != NULL ); 1.398 + ctx->next = NULL; 1.399 + continue; 1.400 + } 1.401 + } 1.402 + *it = NULL; 1.403 + return -1; 1.404 + } 1.405 + 1.406 + /* if the signer changed, still need to fill in the "next" link */ 1.407 + if (ctx->nextsign && ctx->next == NULL) { 1.408 + switch (finding) { 1.409 + case jarTypeSF: 1.410 + ctx->next = ZZ_ListHead (signer->sf); 1.411 + break; 1.412 + 1.413 + case jarTypeSign: 1.414 + ctx->next = ZZ_ListHead (signer->certs); 1.415 + break; 1.416 + } 1.417 + } 1.418 + PORT_Assert( ctx->next != NULL ); 1.419 + if (ctx->next == NULL) { 1.420 + *it = NULL; 1.421 + return -1; 1.422 + } 1.423 + while (!ZZ_ListIterDone (list, ctx->next)) { 1.424 + *it = ctx->next->thing; 1.425 + ctx->next = ctx->next->next; 1.426 + if (!*it || (*it)->type != finding) 1.427 + continue; 1.428 + if (ctx->pattern && *ctx->pattern) { 1.429 + if (PORT_RegExpSearch ((*it)->pathname, ctx->pattern)) 1.430 + continue; 1.431 + } 1.432 + /* We have a valid match. If this is a jarTypeSign 1.433 + return the certificate instead.. */ 1.434 + if (ctx->finding == jarTypeSign) { 1.435 + JAR_Item *itt; 1.436 + 1.437 + /* just the first one for now */ 1.438 + if (jar_find_first_cert (signer, jarTypeSign, &itt) >= 0) { 1.439 + *it = itt; 1.440 + return 0; 1.441 + } 1.442 + continue; 1.443 + } 1.444 + return 0; 1.445 + } 1.446 + } /* end while */ 1.447 +} 1.448 + 1.449 +static int 1.450 +jar_find_first_cert (JAR_Signer *signer, int type, JAR_Item **it) 1.451 +{ 1.452 + ZZLink *link; 1.453 + ZZList *list = signer->certs; 1.454 + int status = JAR_ERR_PNF; 1.455 + 1.456 + *it = NULL; 1.457 + if (ZZ_ListEmpty (list)) { 1.458 + /* empty list */ 1.459 + return JAR_ERR_PNF; 1.460 + } 1.461 + 1.462 + for (link = ZZ_ListHead (list); 1.463 + !ZZ_ListIterDone (list, link); 1.464 + link = link->next) { 1.465 + if (link->thing->type == type) { 1.466 + *it = link->thing; 1.467 + status = 0; 1.468 + break; 1.469 + } 1.470 + } 1.471 + return status; 1.472 +} 1.473 + 1.474 +JAR_Signer * 1.475 +JAR_new_signer (void) 1.476 +{ 1.477 + JAR_Signer *signer = (JAR_Signer *) PORT_ZAlloc (sizeof (JAR_Signer)); 1.478 + if (signer == NULL) 1.479 + goto loser; 1.480 + 1.481 + /* certs */ 1.482 + signer->certs = ZZ_NewList(); 1.483 + if (signer->certs == NULL) 1.484 + goto loser; 1.485 + 1.486 + /* sf */ 1.487 + signer->sf = ZZ_NewList(); 1.488 + if (signer->sf == NULL) 1.489 + goto loser; 1.490 + return signer; 1.491 + 1.492 +loser: 1.493 + if (signer) { 1.494 + if (signer->certs) 1.495 + ZZ_DestroyList (signer->certs); 1.496 + if (signer->sf) 1.497 + ZZ_DestroyList (signer->sf); 1.498 + PORT_Free (signer); 1.499 + } 1.500 + return NULL; 1.501 +} 1.502 + 1.503 +void 1.504 +JAR_destroy_signer(JAR_Signer *signer) 1.505 +{ 1.506 + if (signer) { 1.507 + if (signer->owner) 1.508 + PORT_Free (signer->owner); 1.509 + if (signer->digest) 1.510 + PORT_Free (signer->digest); 1.511 + jar_destroy_list (signer->sf); 1.512 + ZZ_DestroyList (signer->sf); 1.513 + jar_destroy_list (signer->certs); 1.514 + ZZ_DestroyList (signer->certs); 1.515 + PORT_Free (signer); 1.516 + } 1.517 +} 1.518 + 1.519 +JAR_Signer * 1.520 +jar_get_signer(JAR *jar, char *basename) 1.521 +{ 1.522 + JAR_Item *it; 1.523 + JAR_Context *ctx = JAR_find (jar, NULL, jarTypeOwner); 1.524 + JAR_Signer *candidate; 1.525 + JAR_Signer *signer = NULL; 1.526 + 1.527 + if (ctx == NULL) 1.528 + return NULL; 1.529 + 1.530 + while (JAR_find_next (ctx, &it) >= 0) { 1.531 + candidate = (JAR_Signer *) it->data; 1.532 + if (*basename == '*' || !PORT_Strcmp (candidate->owner, basename)) { 1.533 + signer = candidate; 1.534 + break; 1.535 + } 1.536 + } 1.537 + JAR_find_end (ctx); 1.538 + return signer; 1.539 +} 1.540 + 1.541 +/* 1.542 + * J A R _ g e t _ f i l e n a m e 1.543 + * 1.544 + * Returns the filename associated with 1.545 + * a JAR structure. 1.546 + * 1.547 + */ 1.548 +char * 1.549 +JAR_get_filename(JAR *jar) 1.550 +{ 1.551 + return jar->filename; 1.552 +} 1.553 + 1.554 +/* 1.555 + * J A R _ g e t _ u r l 1.556 + * 1.557 + * Returns the URL associated with 1.558 + * a JAR structure. Nobody really uses this now. 1.559 + * 1.560 + */ 1.561 +char * 1.562 +JAR_get_url(JAR *jar) 1.563 +{ 1.564 + return jar->url; 1.565 +} 1.566 + 1.567 +/* 1.568 + * J A R _ s e t _ c a l l b a c k 1.569 + * 1.570 + * Register some manner of callback function for this jar. 1.571 + * 1.572 + */ 1.573 +int 1.574 +JAR_set_callback(int type, JAR *jar, jar_settable_callback_fn *fn) 1.575 +{ 1.576 + if (type == JAR_CB_SIGNAL) { 1.577 + jar->signal = fn; 1.578 + return 0; 1.579 + } 1.580 + return -1; 1.581 +} 1.582 + 1.583 +/* 1.584 + * Callbacks 1.585 + * 1.586 + */ 1.587 + 1.588 +/* To return an error string */ 1.589 +char *(*jar_fn_GetString) (int) = NULL; 1.590 + 1.591 +/* To return an MWContext for Java */ 1.592 +void *(*jar_fn_FindSomeContext) (void) = NULL; 1.593 + 1.594 +/* To fabricate an MWContext for FE_GetPassword */ 1.595 +void *(*jar_fn_GetInitContext) (void) = NULL; 1.596 + 1.597 +void 1.598 +JAR_init_callbacks(char *(*string_cb)(int), 1.599 + void *(*find_cx)(void), 1.600 + void *(*init_cx)(void)) 1.601 +{ 1.602 + jar_fn_GetString = string_cb; 1.603 + jar_fn_FindSomeContext = find_cx; 1.604 + jar_fn_GetInitContext = init_cx; 1.605 +} 1.606 + 1.607 +/* 1.608 + * J A R _ g e t _ e r r o r 1.609 + * 1.610 + * This is provided to map internal JAR errors to strings for 1.611 + * the Java console. Also, a DLL may call this function if it does 1.612 + * not have access to the XP_GetString function. 1.613 + * 1.614 + * These strings aren't UI, since they are Java console only. 1.615 + * 1.616 + */ 1.617 +char * 1.618 +JAR_get_error(int status) 1.619 +{ 1.620 + char *errstring = NULL; 1.621 + 1.622 + switch (status) { 1.623 + case JAR_ERR_GENERAL: 1.624 + errstring = "General JAR file error"; 1.625 + break; 1.626 + 1.627 + case JAR_ERR_FNF: 1.628 + errstring = "JAR file not found"; 1.629 + break; 1.630 + 1.631 + case JAR_ERR_CORRUPT: 1.632 + errstring = "Corrupt JAR file"; 1.633 + break; 1.634 + 1.635 + case JAR_ERR_MEMORY: 1.636 + errstring = "Out of memory"; 1.637 + break; 1.638 + 1.639 + case JAR_ERR_DISK: 1.640 + errstring = "Disk error (perhaps out of space)"; 1.641 + break; 1.642 + 1.643 + case JAR_ERR_ORDER: 1.644 + errstring = "Inconsistent files in META-INF directory"; 1.645 + break; 1.646 + 1.647 + case JAR_ERR_SIG: 1.648 + errstring = "Invalid digital signature file"; 1.649 + break; 1.650 + 1.651 + case JAR_ERR_METADATA: 1.652 + errstring = "JAR metadata failed verification"; 1.653 + break; 1.654 + 1.655 + case JAR_ERR_ENTRY: 1.656 + errstring = "No Manifest entry for this JAR entry"; 1.657 + break; 1.658 + 1.659 + case JAR_ERR_HASH: 1.660 + errstring = "Invalid Hash of this JAR entry"; 1.661 + break; 1.662 + 1.663 + case JAR_ERR_PK7: 1.664 + errstring = "Strange PKCS7 or RSA failure"; 1.665 + break; 1.666 + 1.667 + case JAR_ERR_PNF: 1.668 + errstring = "Path not found inside JAR file"; 1.669 + break; 1.670 + 1.671 + default: 1.672 + if (jar_fn_GetString) { 1.673 + errstring = jar_fn_GetString (status); 1.674 + } else { 1.675 + /* this is not a normal situation, and would only be 1.676 + called in cases of improper initialization */ 1.677 + char *err = (char*)PORT_Alloc (40); 1.678 + if (err) 1.679 + PR_snprintf (err, 39, "Error %d\n", status); /* leak me! */ 1.680 + else 1.681 + err = "Error! Bad! Out of memory!"; 1.682 + return err; 1.683 + } 1.684 + break; 1.685 + } 1.686 + return errstring; 1.687 +}