tor-browser

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

p7sign.c (10397B)


      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 * p7sign -- A command to create a *detached* pkcs7 signature (over a given
      7 * input file).
      8 */
      9 
     10 #include "nspr.h"
     11 #include "plgetopt.h"
     12 #include "secutil.h"
     13 #include "secpkcs7.h"
     14 #include "cert.h"
     15 #include "certdb.h"
     16 #include "sechash.h" /* for HASH_GetHashObject() */
     17 #include "nss.h"
     18 #include "pk11func.h"
     19 
     20 #if defined(XP_UNIX)
     21 #include <unistd.h>
     22 #endif
     23 
     24 #include <stdio.h>
     25 #include <string.h>
     26 
     27 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4))
     28 extern int fread(char *, size_t, size_t, FILE *);
     29 extern int fwrite(char *, size_t, size_t, FILE *);
     30 extern int fprintf(FILE *, char *, ...);
     31 #endif
     32 
     33 static secuPWData pwdata = { PW_NONE, 0 };
     34 
     35 static void
     36 Usage(char *progName)
     37 {
     38    HASH_HashType hashAlg;
     39 
     40    fprintf(stderr,
     41            "Usage:  %s -k keyname [-d keydir] [-i input] [-o output] [-e]\n",
     42            progName);
     43    fprintf(stderr,
     44            "        %*s [-p password|-f password file] [-a hash] [-u certusage]\n",
     45            (int)strlen(progName), "");
     46    fprintf(stderr, "%-20s Nickname of key to use for signature\n",
     47            "-k keyname");
     48    fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
     49            "-d keydir");
     50    fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
     51            "-i input");
     52    fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
     53            "-o output");
     54    fprintf(stderr, "%-20s Encapsulate content in signature message\n",
     55            "-e");
     56    fprintf(stderr, "%-20s Password to the key databse\n", "-p password");
     57    fprintf(stderr, "%-20s File to read password from\n", "-f password file");
     58    fprintf(stderr, "%-20s Use case-insensitive hash algorithm (default: SHA-1)\n",
     59            "-a hash");
     60    fprintf(stderr, "%-25s  ", "");
     61    for (hashAlg = HASH_AlgNULL + 1; hashAlg != HASH_AlgTOTAL; ++hashAlg)
     62        fprintf(stderr, "%s%s", hashAlg == HASH_AlgNULL + 1 ? "" : ", ",
     63                SECOID_FindOIDByTag(HASH_GetHashOidTagByHashType(hashAlg))->desc);
     64    fputc('\n', stderr);
     65    fprintf(stderr, "%-20s Sign for usage (default: certUsageEmailSigner)\n",
     66            "-u certusage");
     67    fprintf(stderr, "%-25s  0 - certUsageSSLClient\n", "");
     68    fprintf(stderr, "%-25s  1 - certUsageSSLServer\n", "");
     69    fprintf(stderr, "%-25s  2 - certUsageSSLServerWithStepUp\n", "");
     70    fprintf(stderr, "%-25s  3 - certUsageSSLCA\n", "");
     71    fprintf(stderr, "%-25s  4 - certUsageEmailSigner\n", "");
     72    fprintf(stderr, "%-25s  5 - certUsageEmailRecipient\n", "");
     73    fprintf(stderr, "%-25s  6 - certUsageObjectSigner\n", "");
     74    fprintf(stderr, "%-25s  7 - certUsageUserCertImport\n", "");
     75    fprintf(stderr, "%-25s  8 - certUsageVerifyCA\n", "");
     76    fprintf(stderr, "%-25s  9 - certUsageProtectedObjectSigner\n", "");
     77    fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", "");
     78    fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", "");
     79    fprintf(stderr, "%-25s 12 - certUsageIPsec\n", "");
     80    exit(-1);
     81 }
     82 
     83 static void
     84 SignOut(void *arg, const char *buf, unsigned long len)
     85 {
     86    FILE *out;
     87 
     88    out = (FILE *)arg;
     89    fwrite(buf, len, 1, out);
     90 }
     91 
     92 static int
     93 CreateDigest(SECItem *data, char *digestdata, unsigned int *len,
     94             unsigned int maxlen, HASH_HashType hashAlg)
     95 {
     96    const SECHashObject *hashObj;
     97    void *hashcx;
     98 
     99    hashObj = HASH_GetHashObject(hashAlg);
    100 
    101    hashcx = (*hashObj->create)();
    102    if (hashcx == NULL)
    103        return -1;
    104 
    105    (*hashObj->begin)(hashcx);
    106    (*hashObj->update)(hashcx, data->data, data->len);
    107    (*hashObj->end)(hashcx, (unsigned char *)digestdata, len, maxlen);
    108    (*hashObj->destroy)(hashcx, PR_TRUE);
    109    return 0;
    110 }
    111 
    112 static int
    113 SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert,
    114         PRBool encapsulated, HASH_HashType hashAlg, SECOidTag hashAlgOid,
    115         SECCertUsage usage)
    116 {
    117    char digestdata[HASH_LENGTH_MAX];
    118    unsigned int len;
    119    SECItem digest, data2sign;
    120    SEC_PKCS7ContentInfo *cinfo;
    121    SECStatus rv;
    122 
    123    if (outFile == NULL || inFile == NULL || cert == NULL)
    124        return -1;
    125 
    126    /* suck the file in */
    127    if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE,
    128                             PR_FALSE) != SECSuccess)
    129        return -1;
    130 
    131    if (!encapsulated) {
    132        /* unfortunately, we must create the digest ourselves */
    133        /* SEC_PKCS7CreateSignedData should have a flag to not include */
    134        /* the content for non-encapsulated content at encode time, but */
    135        /* should always compute the hash itself */
    136        if (CreateDigest(&data2sign, digestdata, &len,
    137                         sizeof(digestdata), hashAlg) < 0) {
    138            SECITEM_FreeItem(&data2sign, PR_FALSE);
    139            return -1;
    140        }
    141        digest.data = (unsigned char *)digestdata;
    142        digest.len = len;
    143    }
    144 
    145    cinfo = SEC_PKCS7CreateSignedData(cert, usage, NULL,
    146                                      hashAlgOid,
    147                                      encapsulated ? NULL : &digest,
    148                                      NULL, NULL);
    149    if (cinfo == NULL) {
    150        SECITEM_FreeItem(&data2sign, PR_FALSE);
    151        return -1;
    152    }
    153 
    154    if (encapsulated) {
    155        SEC_PKCS7SetContent(cinfo, (char *)data2sign.data, data2sign.len);
    156    }
    157 
    158    rv = SEC_PKCS7IncludeCertChain(cinfo, NULL);
    159    if (rv != SECSuccess) {
    160        SEC_PKCS7DestroyContentInfo(cinfo);
    161        SECITEM_FreeItem(&data2sign, PR_FALSE);
    162        return -1;
    163    }
    164 
    165    rv = SEC_PKCS7Encode(cinfo, SignOut, outFile, NULL,
    166                         NULL, &pwdata);
    167 
    168    SECITEM_FreeItem(&data2sign, PR_FALSE);
    169    SEC_PKCS7DestroyContentInfo(cinfo);
    170 
    171    if (rv != SECSuccess)
    172        return -1;
    173 
    174    return 0;
    175 }
    176 
    177 int
    178 main(int argc, char **argv)
    179 {
    180    char *progName;
    181    FILE *outFile;
    182    PRFileDesc *inFile;
    183    char *keyName = NULL;
    184    CERTCertDBHandle *certHandle;
    185    CERTCertificate *cert = NULL;
    186    PRBool encapsulated = PR_FALSE;
    187    HASH_HashType hashAlg = HASH_AlgSHA1;
    188    SECOidTag hashAlgOid = SEC_OID_SHA1;
    189    SECCertUsage usage = certUsageEmailSigner;
    190    PLOptState *optstate;
    191    PLOptStatus status;
    192    SECStatus rv;
    193 
    194    progName = strrchr(argv[0], '/');
    195    progName = progName ? progName + 1 : argv[0];
    196 
    197    inFile = NULL;
    198    outFile = NULL;
    199    keyName = NULL;
    200 
    201    /*
    202     * Parse command line arguments
    203     */
    204    optstate = PL_CreateOptState(argc, argv, "ed:k:i:o:p:f:a:u:");
    205    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
    206        switch (optstate->option) {
    207            case '?':
    208                Usage(progName);
    209                break;
    210 
    211            case 'e':
    212                /* create a message with the signed content encapsulated */
    213                encapsulated = PR_TRUE;
    214                break;
    215 
    216            case 'd':
    217                SECU_ConfigDirectory(optstate->value);
    218                break;
    219 
    220            case 'i':
    221                inFile = PR_Open(optstate->value, PR_RDONLY, 0);
    222                if (!inFile) {
    223                    fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
    224                            progName, optstate->value);
    225                    return -1;
    226                }
    227                break;
    228 
    229            case 'k':
    230                keyName = strdup(optstate->value);
    231                break;
    232 
    233            case 'o':
    234                outFile = fopen(optstate->value, "wb");
    235                if (!outFile) {
    236                    fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
    237                            progName, optstate->value);
    238                    return -1;
    239                }
    240                break;
    241            case 'p':
    242                pwdata.source = PW_PLAINTEXT;
    243                pwdata.data = strdup(optstate->value);
    244                break;
    245 
    246            case 'f':
    247                pwdata.source = PW_FROMFILE;
    248                pwdata.data = PORT_Strdup(optstate->value);
    249                break;
    250 
    251            case 'a':
    252                for (hashAlg = HASH_AlgNULL + 1; hashAlg != HASH_AlgTOTAL;
    253                     ++hashAlg) {
    254                    hashAlgOid = HASH_GetHashOidTagByHashType(hashAlg);
    255                    if (!PORT_Strcasecmp(optstate->value,
    256                                         SECOID_FindOIDByTag(hashAlgOid)->desc))
    257                        break;
    258                }
    259                if (hashAlg == HASH_AlgTOTAL)
    260                    Usage(progName);
    261                break;
    262 
    263            case 'u':
    264                usage = atoi(optstate->value);
    265                if (usage < certUsageSSLClient || usage > certUsageIPsec)
    266                    Usage(progName);
    267                break;
    268        }
    269    }
    270    PL_DestroyOptState(optstate);
    271 
    272    if (!keyName)
    273        Usage(progName);
    274 
    275    if (!inFile)
    276        inFile = PR_STDIN;
    277    if (!outFile)
    278        outFile = stdout;
    279 
    280    /* Call the initialization routines */
    281    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    282    rv = NSS_Init(SECU_ConfigDirectory(NULL));
    283    if (rv != SECSuccess) {
    284        SECU_PrintPRandOSError(progName);
    285        goto loser;
    286    }
    287 
    288    PK11_SetPasswordFunc(SECU_GetModulePassword);
    289 
    290    /* open cert database */
    291    certHandle = CERT_GetDefaultCertDB();
    292    if (certHandle == NULL) {
    293        rv = SECFailure;
    294        goto loser;
    295    }
    296 
    297    /* find cert */
    298    cert = SECU_FindCertByNicknameOrFilename(certHandle, keyName, PR_FALSE, NULL);
    299    if (cert == NULL) {
    300        SECU_PrintError(progName,
    301                        "the corresponding cert for key \"%s\" does not exist",
    302                        keyName);
    303        rv = SECFailure;
    304        goto loser;
    305    }
    306 
    307    if (SignFile(outFile, inFile, cert, encapsulated,
    308                 hashAlg, hashAlgOid, usage)) {
    309        SECU_PrintError(progName, "problem signing data");
    310        rv = SECFailure;
    311        goto loser;
    312    }
    313 
    314 loser:
    315    if (pwdata.data) {
    316        PORT_Free(pwdata.data);
    317    }
    318    if (keyName) {
    319        PORT_Free(keyName);
    320    }
    321    if (cert) {
    322        CERT_DestroyCertificate(cert);
    323    }
    324    if (inFile && inFile != PR_STDIN) {
    325        PR_Close(inFile);
    326    }
    327    if (outFile && outFile != stdout) {
    328        fclose(outFile);
    329    }
    330    if (NSS_Shutdown() != SECSuccess) {
    331        SECU_PrintError(progName, "NSS shutdown:");
    332        exit(1);
    333    }
    334 
    335    return (rv != SECSuccess);
    336 }