tor-browser

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

jarsign.c (6095B)


      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 *  JARSIGN
      7 *
      8 *  Routines used in signing archives.
      9 */
     10 
     11 #include "jar.h"
     12 #include "jarint.h"
     13 #include "secpkcs7.h"
     14 #include "pk11func.h"
     15 #include "sechash.h"
     16 
     17 /* from libevent.h */
     18 typedef void (*ETVoidPtrFunc)(void *data);
     19 
     20 /* key database wrapper */
     21 /* static SECKEYKeyDBHandle *jar_open_key_database (void); */
     22 /* CHUNQ is our bite size */
     23 
     24 #define CHUNQ 64000
     25 #define FILECHUNQ 32768
     26 
     27 /*
     28 *  J A R _ c a l c u l a t e _ d i g e s t
     29 *
     30 *  Quick calculation of a digest for
     31 *  the specified block of memory. Will calculate
     32 *  for all supported algorithms, now MD5.
     33 *
     34 */
     35 JAR_Digest *PR_CALLBACK
     36 JAR_calculate_digest(void *data, long length)
     37 {
     38    PK11Context *md5 = 0;
     39    PK11Context *sha1 = 0;
     40    JAR_Digest *dig = PORT_ZNew(JAR_Digest);
     41    long chunq;
     42    unsigned int md5_length, sha1_length;
     43 
     44    if (dig == NULL) {
     45        /* out of memory allocating digest */
     46        return NULL;
     47    }
     48 
     49    md5 = PK11_CreateDigestContext(SEC_OID_MD5);
     50    if (md5 == NULL) {
     51        PORT_ZFree(dig, sizeof(JAR_Digest));
     52        return NULL;
     53    }
     54    sha1 = PK11_CreateDigestContext(SEC_OID_SHA1);
     55    if (sha1 == NULL) {
     56        PK11_DestroyContext(md5, PR_TRUE);
     57        /* added due to bug Bug 1250214 - prevent the 2nd memory leak */
     58        PORT_ZFree(dig, sizeof(JAR_Digest));
     59        return NULL;
     60    }
     61 
     62    if (length >= 0) {
     63        PK11_DigestBegin(md5);
     64        PK11_DigestBegin(sha1);
     65 
     66        do {
     67            chunq = length;
     68 
     69            PK11_DigestOp(md5, (unsigned char *)data, chunq);
     70            PK11_DigestOp(sha1, (unsigned char *)data, chunq);
     71            length -= chunq;
     72            data = ((char *)data + chunq);
     73        } while (length > 0);
     74 
     75        PK11_DigestFinal(md5, dig->md5, &md5_length, MD5_LENGTH);
     76        PK11_DigestFinal(sha1, dig->sha1, &sha1_length, SHA1_LENGTH);
     77 
     78        PK11_DestroyContext(md5, PR_TRUE);
     79        PK11_DestroyContext(sha1, PR_TRUE);
     80    }
     81    return dig;
     82 }
     83 
     84 /*
     85 *  J A R _ d i g e s t _ f i l e
     86 *
     87 *  Calculates the MD5 and SHA1 digests for a file
     88 *  present on disk, and returns these in JAR_Digest struct.
     89 *
     90 */
     91 int
     92 JAR_digest_file(char *filename, JAR_Digest *dig)
     93 {
     94    JAR_FILE fp;
     95    PK11Context *md5 = 0;
     96    PK11Context *sha1 = 0;
     97    unsigned char *buf = (unsigned char *)PORT_ZAlloc(FILECHUNQ);
     98    int num;
     99    unsigned int md5_length, sha1_length;
    100 
    101    if (buf == NULL) {
    102        /* out of memory */
    103        return JAR_ERR_MEMORY;
    104    }
    105 
    106    if ((fp = JAR_FOPEN(filename, "rb")) == 0) {
    107        /* perror (filename); FIX XXX XXX XXX XXX XXX XXX */
    108        PORT_Free(buf);
    109        return JAR_ERR_FNF;
    110    }
    111 
    112    md5 = PK11_CreateDigestContext(SEC_OID_MD5);
    113    sha1 = PK11_CreateDigestContext(SEC_OID_SHA1);
    114 
    115    if (md5 == NULL || sha1 == NULL) {
    116        if (md5) {
    117            PK11_DestroyContext(md5, PR_TRUE);
    118        }
    119        if (sha1) {
    120            PK11_DestroyContext(sha1, PR_TRUE);
    121        }
    122        /* can't generate digest contexts */
    123        PORT_Free(buf);
    124        JAR_FCLOSE(fp);
    125        return JAR_ERR_GENERAL;
    126    }
    127 
    128    PK11_DigestBegin(md5);
    129    PK11_DigestBegin(sha1);
    130 
    131    while (1) {
    132        if ((num = JAR_FREAD(fp, buf, FILECHUNQ)) == 0)
    133            break;
    134 
    135        PK11_DigestOp(md5, buf, num);
    136        PK11_DigestOp(sha1, buf, num);
    137    }
    138 
    139    PK11_DigestFinal(md5, dig->md5, &md5_length, MD5_LENGTH);
    140    PK11_DigestFinal(sha1, dig->sha1, &sha1_length, SHA1_LENGTH);
    141 
    142    PK11_DestroyContext(md5, PR_TRUE);
    143    PK11_DestroyContext(sha1, PR_TRUE);
    144 
    145    PORT_Free(buf);
    146    JAR_FCLOSE(fp);
    147 
    148    return 0;
    149 }
    150 
    151 /*
    152 *  J A R _ o p e n _ k e y _ d a t a b a s e
    153 *
    154 */
    155 
    156 void *
    157 jar_open_key_database(void)
    158 {
    159    return NULL;
    160 }
    161 
    162 int
    163 jar_close_key_database(void *keydb)
    164 {
    165    /* We never do close it */
    166    return 0;
    167 }
    168 
    169 /*
    170 *  j a r _ c r e a t e _ p k 7
    171 *
    172 */
    173 
    174 static void
    175 jar_pk7_out(void *arg, const char *buf, unsigned long len)
    176 {
    177    JAR_FWRITE((JAR_FILE)arg, buf, len);
    178 }
    179 
    180 int
    181 jar_create_pk7(CERTCertDBHandle *certdb, void *keydb, CERTCertificate *cert,
    182               char *password, JAR_FILE infp, JAR_FILE outfp)
    183 {
    184    SEC_PKCS7ContentInfo *cinfo;
    185    const SECHashObject *hashObj;
    186    void *mw = NULL;
    187    void *hashcx;
    188    unsigned int len;
    189    int status = 0;
    190    SECStatus rv;
    191    SECItem digest;
    192    unsigned char digestdata[32];
    193    unsigned char buffer[4096];
    194 
    195    if (outfp == NULL || infp == NULL || cert == NULL)
    196        return JAR_ERR_GENERAL;
    197 
    198    /* we sign with SHA */
    199    hashObj = HASH_GetHashObject(HASH_AlgSHA1);
    200 
    201    hashcx = (*hashObj->create)();
    202    if (hashcx == NULL)
    203        return JAR_ERR_GENERAL;
    204 
    205    (*hashObj->begin)(hashcx);
    206    while (1) {
    207        int nb = JAR_FREAD(infp, buffer, sizeof buffer);
    208        if (nb == 0) { /* eof */
    209            break;
    210        }
    211        (*hashObj->update)(hashcx, buffer, nb);
    212    }
    213    (*hashObj->end)(hashcx, digestdata, &len, 32);
    214    (*hashObj->destroy)(hashcx, PR_TRUE);
    215 
    216    digest.data = digestdata;
    217    digest.len = len;
    218 
    219    /* signtool must use any old context it can find since it's
    220       calling from inside javaland. */
    221    PORT_SetError(0);
    222    cinfo = SEC_PKCS7CreateSignedData(cert, certUsageObjectSigner, NULL,
    223                                      SEC_OID_SHA1, &digest, NULL, mw);
    224    if (cinfo == NULL)
    225        return JAR_ERR_PK7;
    226 
    227    rv = SEC_PKCS7IncludeCertChain(cinfo, NULL);
    228    if (rv != SECSuccess) {
    229        status = PORT_GetError();
    230        SEC_PKCS7DestroyContentInfo(cinfo);
    231        return status;
    232    }
    233 
    234    /* Having this here forces signtool to always include signing time. */
    235    rv = SEC_PKCS7AddSigningTime(cinfo);
    236    /* don't check error */
    237    PORT_SetError(0);
    238 
    239    /* if calling from mozilla thread*/
    240    rv = SEC_PKCS7Encode(cinfo, jar_pk7_out, outfp, NULL, NULL, mw);
    241    if (rv != SECSuccess)
    242        status = PORT_GetError();
    243    SEC_PKCS7DestroyContentInfo(cinfo);
    244    if (rv != SECSuccess) {
    245        return ((status < 0) ? status : JAR_ERR_GENERAL);
    246    }
    247    return 0;
    248 }