tor-browser

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

pk1sign.c (8077B)


      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 * pk1sign
      7 */
      8 
      9 #include "nspr.h"
     10 #include "plgetopt.h"
     11 #include "secutil.h"
     12 #include "secpkcs7.h"
     13 #include "cert.h"
     14 #include "certdb.h"
     15 #include "sechash.h" /* for HASH_GetHashObject() */
     16 #include "nss.h"
     17 #include "pk11func.h"
     18 #include "cryptohi.h"
     19 #include "plbase64.h"
     20 
     21 #if defined(XP_UNIX)
     22 #include <unistd.h>
     23 #endif
     24 
     25 #include <stdio.h>
     26 #include <string.h>
     27 
     28 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4))
     29 extern int fread(char *, size_t, size_t, FILE *);
     30 extern int fwrite(char *, size_t, size_t, FILE *);
     31 extern int fprintf(FILE *, char *, ...);
     32 #endif
     33 
     34 static secuPWData pwdata = { PW_NONE, 0 };
     35 
     36 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
     37 
     38 SEC_ASN1Template CERTSignatureDataTemplate[] = {
     39    { SEC_ASN1_SEQUENCE,
     40      0, NULL, sizeof(CERTSignedData) },
     41    { SEC_ASN1_INLINE,
     42      offsetof(CERTSignedData, signatureAlgorithm),
     43      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
     44    { SEC_ASN1_BIT_STRING,
     45      offsetof(CERTSignedData, signature) },
     46    { 0 }
     47 };
     48 
     49 static void
     50 Usage(char *progName)
     51 {
     52    fprintf(stderr,
     53            "Usage:  %s -k keyname [-d keydir] [-i input] [-o output]\n",
     54            progName);
     55    fprintf(stderr, "%-20s Nickname of key to use for signature\n",
     56            "-k keyname");
     57    fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
     58            "-d keydir");
     59    fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
     60            "-i input");
     61    fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
     62            "-o output");
     63    fprintf(stderr, "%-20s Password to the key databse\n", "-p");
     64    fprintf(stderr, "%-20s password file\n", "-f");
     65    exit(-1);
     66 }
     67 
     68 static int
     69 ExportPublicKey(FILE *outFile, CERTCertificate *cert)
     70 {
     71    char *data;
     72    SECKEYPublicKey *publicKey;
     73    SECItem *item;
     74 
     75    if (!cert)
     76        return -1;
     77 
     78    publicKey = CERT_ExtractPublicKey(cert);
     79    if (!publicKey)
     80        return -1;
     81 
     82    item = SECKEY_EncodeDERSubjectPublicKeyInfo(publicKey);
     83    SECKEY_DestroyPublicKey(publicKey);
     84    if (!item)
     85        return -1;
     86 
     87    data = PL_Base64Encode((const char *)item->data, item->len, NULL);
     88    SECITEM_FreeItem(item, PR_TRUE);
     89    if (!data)
     90        return -1;
     91 
     92    fputs("pubkey:\n", outFile);
     93    fputs(data, outFile);
     94    fputs("\n", outFile);
     95    PR_Free(data);
     96 
     97    return 0;
     98 }
     99 
    100 static int
    101 SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert)
    102 {
    103    SECItem data2sign;
    104    SECStatus rv;
    105    SECOidTag algID;
    106    CERTSignedData sd;
    107    SECKEYPrivateKey *privKey = NULL;
    108    char *data = NULL;
    109    PLArenaPool *arena = NULL;
    110    SECItem *result = NULL;
    111    int returnValue = 0;
    112 
    113    if (outFile == NULL || inFile == NULL || cert == NULL) {
    114        return -1;
    115    }
    116 
    117    /* suck the file in */
    118    if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE,
    119                             PR_FALSE) != SECSuccess) {
    120        return -1;
    121    }
    122 
    123    privKey = NULL;
    124    privKey = PK11_FindKeyByAnyCert(cert, NULL);
    125    if (!privKey) {
    126        returnValue = -1;
    127        goto loser;
    128    }
    129 
    130    algID = SEC_GetSignatureAlgorithmOidTagByKey(privKey, NULL, SEC_OID_UNKNOWN);
    131    if (algID == SEC_OID_UNKNOWN) {
    132        returnValue = -1;
    133        goto loser;
    134    }
    135 
    136    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    137 
    138    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
    139 
    140    rv = SEC_SignData(&(sd.signature), data2sign.data, data2sign.len, privKey, algID);
    141    if (rv != SECSuccess) {
    142        fprintf(stderr, "Could not sign.\n");
    143        returnValue = -1;
    144        goto loser;
    145    }
    146    sd.signature.len = sd.signature.len << 3;
    147 
    148    rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0);
    149    if (rv != SECSuccess) {
    150        fprintf(stderr, "Could not set alg id.\n");
    151        returnValue = -1;
    152        goto loser;
    153    }
    154 
    155    result = SEC_ASN1EncodeItem(arena, NULL, &sd, CERTSignatureDataTemplate);
    156    SECITEM_FreeItem(&(sd.signature), PR_FALSE);
    157 
    158    if (!result) {
    159        fprintf(stderr, "Could not encode.\n");
    160        returnValue = -1;
    161        goto loser;
    162    }
    163 
    164    data = PL_Base64Encode((const char *)result->data, result->len, NULL);
    165    if (!data) {
    166        returnValue = -1;
    167        goto loser;
    168    }
    169 
    170    fputs("signature:\n", outFile);
    171    fputs(data, outFile);
    172    fputs("\n", outFile);
    173    ExportPublicKey(outFile, cert);
    174 
    175 loser:
    176    if (privKey) {
    177        SECKEY_DestroyPrivateKey(privKey);
    178    }
    179    if (data) {
    180        PR_Free(data);
    181    }
    182    PORT_FreeArena(arena, PR_FALSE);
    183 
    184    return returnValue;
    185 }
    186 
    187 int
    188 main(int argc, char **argv)
    189 {
    190    char *progName;
    191    FILE *outFile;
    192    PRFileDesc *inFile;
    193    char *keyName = NULL;
    194    CERTCertDBHandle *certHandle;
    195    CERTCertificate *cert = NULL;
    196    PLOptState *optstate;
    197    PLOptStatus status;
    198    SECStatus rv;
    199 
    200    progName = strrchr(argv[0], '/');
    201    progName = progName ? progName + 1 : argv[0];
    202 
    203    inFile = NULL;
    204    outFile = NULL;
    205    keyName = NULL;
    206 
    207    /*
    208     * Parse command line arguments
    209     */
    210    optstate = PL_CreateOptState(argc, argv, "ed:k:i:o:p:f:");
    211    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
    212        switch (optstate->option) {
    213            case '?':
    214                Usage(progName);
    215                break;
    216 
    217            case 'd':
    218                SECU_ConfigDirectory(optstate->value);
    219                break;
    220 
    221            case 'i':
    222                inFile = PR_Open(optstate->value, PR_RDONLY, 0);
    223                if (!inFile) {
    224                    fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
    225                            progName, optstate->value);
    226                    return -1;
    227                }
    228                break;
    229 
    230            case 'k':
    231                keyName = strdup(optstate->value);
    232                break;
    233 
    234            case 'o':
    235                outFile = fopen(optstate->value, "wb");
    236                if (!outFile) {
    237                    fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
    238                            progName, optstate->value);
    239                    return -1;
    240                }
    241                break;
    242            case 'p':
    243                pwdata.source = PW_PLAINTEXT;
    244                pwdata.data = strdup(optstate->value);
    245                break;
    246 
    247            case 'f':
    248                pwdata.source = PW_FROMFILE;
    249                pwdata.data = PORT_Strdup(optstate->value);
    250                break;
    251        }
    252    }
    253 
    254    if (!keyName)
    255        Usage(progName);
    256 
    257    if (!inFile)
    258        inFile = PR_STDIN;
    259    if (!outFile)
    260        outFile = stdout;
    261 
    262    /* Call the initialization routines */
    263    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    264    rv = NSS_Init(SECU_ConfigDirectory(NULL));
    265    if (rv != SECSuccess) {
    266        SECU_PrintPRandOSError(progName);
    267        goto loser;
    268    }
    269 
    270    PK11_SetPasswordFunc(SECU_GetModulePassword);
    271 
    272    /* open cert database */
    273    certHandle = CERT_GetDefaultCertDB();
    274    if (certHandle == NULL) {
    275        rv = SECFailure;
    276        goto loser;
    277    }
    278 
    279    /* find cert */
    280    cert = CERT_FindCertByNickname(certHandle, keyName);
    281    if (cert == NULL) {
    282        SECU_PrintError(progName,
    283                        "the corresponding cert for key \"%s\" does not exist",
    284                        keyName);
    285        rv = SECFailure;
    286        goto loser;
    287    }
    288 
    289    if (SignFile(outFile, inFile, cert)) {
    290        SECU_PrintError(progName, "problem signing data");
    291        rv = SECFailure;
    292        goto loser;
    293    }
    294 
    295 loser:
    296    if (pwdata.data) {
    297        PORT_Free(pwdata.data);
    298    }
    299    if (keyName) {
    300        PORT_Free(keyName);
    301    }
    302    if (cert) {
    303        CERT_DestroyCertificate(cert);
    304    }
    305    if (inFile && inFile != PR_STDIN) {
    306        PR_Close(inFile);
    307    }
    308    if (outFile && outFile != stdout) {
    309        fclose(outFile);
    310    }
    311    if (NSS_Shutdown() != SECSuccess) {
    312        SECU_PrintError(progName, "NSS shutdown:");
    313        exit(1);
    314    }
    315 
    316    return (rv != SECSuccess);
    317 }