tor-browser

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

p7verify.c (7895B)


      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 * p7verify -- A command to do a verification of a *detached* pkcs7 signature.
      7 */
      8 
      9 #include "nspr.h"
     10 #include "secutil.h"
     11 #include "plgetopt.h"
     12 #include "secpkcs7.h"
     13 #include "cert.h"
     14 #include "certdb.h"
     15 #include "secoid.h"
     16 #include "sechash.h" /* for HASH_GetHashObject() */
     17 #include "nss.h"
     18 
     19 #if defined(XP_UNIX)
     20 #include <unistd.h>
     21 #endif
     22 
     23 #include <stdio.h>
     24 #include <string.h>
     25 
     26 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4))
     27 extern int fread(char *, size_t, size_t, FILE *);
     28 extern int fprintf(FILE *, char *, ...);
     29 #endif
     30 
     31 static int
     32 DigestFile(unsigned char *digest, unsigned int *len, unsigned int maxLen,
     33           FILE *inFile, HASH_HashType hashType)
     34 {
     35    int nb;
     36    unsigned char ibuf[4096];
     37    const SECHashObject *hashObj;
     38    void *hashcx;
     39 
     40    hashObj = HASH_GetHashObject(hashType);
     41 
     42    hashcx = (*hashObj->create)();
     43    if (hashcx == NULL)
     44        return -1;
     45 
     46    (*hashObj->begin)(hashcx);
     47 
     48    for (;;) {
     49        if (feof(inFile))
     50            break;
     51        nb = fread(ibuf, 1, sizeof(ibuf), inFile);
     52        if (nb != sizeof(ibuf)) {
     53            if (nb == 0) {
     54                if (ferror(inFile)) {
     55                    PORT_SetError(SEC_ERROR_IO);
     56                    (*hashObj->destroy)(hashcx, PR_TRUE);
     57                    return -1;
     58                }
     59                /* eof */
     60                break;
     61            }
     62        }
     63        (*hashObj->update)(hashcx, ibuf, nb);
     64    }
     65 
     66    (*hashObj->end)(hashcx, digest, len, maxLen);
     67    (*hashObj->destroy)(hashcx, PR_TRUE);
     68 
     69    return 0;
     70 }
     71 
     72 static void
     73 Usage(char *progName)
     74 {
     75    fprintf(stderr,
     76            "Usage:  %s -c content -s signature [-d dbdir] [-u certusage]\n",
     77            progName);
     78    fprintf(stderr, "%-20s content file that was signed\n",
     79            "-c content");
     80    fprintf(stderr, "%-20s file containing signature for that content\n",
     81            "-s signature");
     82    fprintf(stderr,
     83            "%-20s Key/Cert database directory (default is ~/.netscape)\n",
     84            "-d dbdir");
     85    fprintf(stderr, "%-20s Define the type of certificate usage (default is certUsageEmailSigner)\n",
     86            "-u certusage");
     87    fprintf(stderr, "%-25s  0 - certUsageSSLClient\n", " ");
     88    fprintf(stderr, "%-25s  1 - certUsageSSLServer\n", " ");
     89    fprintf(stderr, "%-25s  2 - certUsageSSLServerWithStepUp\n", " ");
     90    fprintf(stderr, "%-25s  3 - certUsageSSLCA\n", " ");
     91    fprintf(stderr, "%-25s  4 - certUsageEmailSigner\n", " ");
     92    fprintf(stderr, "%-25s  5 - certUsageEmailRecipient\n", " ");
     93    fprintf(stderr, "%-25s  6 - certUsageObjectSigner\n", " ");
     94    fprintf(stderr, "%-25s  7 - certUsageUserCertImport\n", " ");
     95    fprintf(stderr, "%-25s  8 - certUsageVerifyCA\n", " ");
     96    fprintf(stderr, "%-25s  9 - certUsageProtectedObjectSigner\n", " ");
     97    fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " ");
     98    fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " ");
     99    fprintf(stderr, "%-25s 12 - certUsageIPsec\n", " ");
    100 
    101    exit(-1);
    102 }
    103 
    104 static int
    105 HashDecodeAndVerify(FILE *out, FILE *content, PRFileDesc *signature,
    106                    SECCertUsage usage, char *progName)
    107 {
    108    SECItem derdata;
    109    SEC_PKCS7ContentInfo *cinfo;
    110    SEC_PKCS7SignedData *signedData;
    111    HASH_HashType digestType;
    112    SECItem digest;
    113    unsigned char buffer[32];
    114 
    115    if (SECU_ReadDERFromFile(&derdata, signature, PR_FALSE,
    116                             PR_FALSE) != SECSuccess) {
    117        SECU_PrintError(progName, "error reading signature file");
    118        return -1;
    119    }
    120 
    121    cinfo = SEC_PKCS7DecodeItem(&derdata, NULL, NULL, NULL, NULL,
    122                                NULL, NULL, NULL);
    123    if (cinfo == NULL)
    124        return -1;
    125 
    126    if (!SEC_PKCS7ContentIsSigned(cinfo)) {
    127        fprintf(out, "Signature file is pkcs7 data, but not signed.\n");
    128        return -1;
    129    }
    130 
    131    signedData = cinfo->content.signedData;
    132 
    133    /* assume that there is only one digest algorithm for now */
    134    digestType = HASH_GetHashTypeByOidTag(
    135        SECOID_GetAlgorithmTag(signedData->digestAlgorithms[0]));
    136    if (digestType == HASH_AlgNULL) {
    137        fprintf(out, "Invalid hash algorithmID\n");
    138        return -1;
    139    }
    140 
    141    digest.data = buffer;
    142    if (DigestFile(digest.data, &digest.len, 32, content, digestType)) {
    143        SECU_PrintError(progName, "problem computing message digest");
    144        return -1;
    145    }
    146 
    147    fprintf(out, "Signature is ");
    148    if (SEC_PKCS7VerifyDetachedSignature(cinfo, usage, &digest, digestType,
    149                                         PR_FALSE))
    150        fprintf(out, "valid.\n");
    151    else
    152        fprintf(out, "invalid (Reason: %s).\n",
    153                SECU_Strerror(PORT_GetError()));
    154 
    155    SECITEM_FreeItem(&derdata, PR_FALSE);
    156    SEC_PKCS7DestroyContentInfo(cinfo);
    157    return 0;
    158 }
    159 
    160 int
    161 main(int argc, char **argv)
    162 {
    163    char *progName;
    164    FILE *contentFile, *outFile;
    165    PRFileDesc *signatureFile;
    166    SECCertUsage certUsage = certUsageEmailSigner;
    167    PLOptState *optstate;
    168    PLOptStatus status;
    169    SECStatus rv;
    170 
    171    progName = strrchr(argv[0], '/');
    172    progName = progName ? progName + 1 : argv[0];
    173 
    174    contentFile = NULL;
    175    signatureFile = NULL;
    176    outFile = NULL;
    177 
    178    /*
    179     * Parse command line arguments
    180     */
    181    optstate = PL_CreateOptState(argc, argv, "c:d:o:s:u:");
    182    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
    183        switch (optstate->option) {
    184            case '?':
    185                Usage(progName);
    186                break;
    187 
    188            case 'c':
    189                contentFile = fopen(optstate->value, "r");
    190                if (!contentFile) {
    191                    fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
    192                            progName, optstate->value);
    193                    return -1;
    194                }
    195                break;
    196 
    197            case 'd':
    198                SECU_ConfigDirectory(optstate->value);
    199                break;
    200 
    201            case 'o':
    202                outFile = fopen(optstate->value, "w");
    203                if (!outFile) {
    204                    fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
    205                            progName, optstate->value);
    206                    return -1;
    207                }
    208                break;
    209 
    210            case 's':
    211                signatureFile = PR_Open(optstate->value, PR_RDONLY, 0);
    212                if (!signatureFile) {
    213                    fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
    214                            progName, optstate->value);
    215                    return -1;
    216                }
    217                break;
    218 
    219            case 'u': {
    220                int usageType;
    221 
    222                usageType = atoi(optstate->value);
    223                if (usageType < certUsageSSLClient || usageType > certUsageIPsec)
    224                    return -1;
    225                certUsage = (SECCertUsage)usageType;
    226                break;
    227            }
    228        }
    229    }
    230    PL_DestroyOptState(optstate);
    231 
    232    if (!contentFile)
    233        Usage(progName);
    234    if (!signatureFile)
    235        Usage(progName);
    236    if (!outFile)
    237        outFile = stdout;
    238 
    239    /* Call the NSS initialization routines */
    240    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    241    rv = NSS_Init(SECU_ConfigDirectory(NULL));
    242    if (rv != SECSuccess) {
    243        SECU_PrintPRandOSError(progName);
    244        return -1;
    245    }
    246 
    247    if (HashDecodeAndVerify(outFile, contentFile, signatureFile,
    248                            certUsage, progName)) {
    249        SECU_PrintError(progName, "problem decoding/verifying signature");
    250        return -1;
    251    }
    252 
    253    fclose(contentFile);
    254    PR_Close(signatureFile);
    255    if (outFile && outFile != stdout) {
    256        fclose(outFile);
    257    }
    258 
    259    if (NSS_Shutdown() != SECSuccess) {
    260        exit(1);
    261    }
    262 
    263    return 0;
    264 }