tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

jar.c (17049B)


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