Back to index

lightning-sunbird  0.9+nobinonly
signver.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "secutil.h"
00038 #include "secmod.h"
00039 #include "cert.h"
00040 #include "secoid.h"
00041 #include "nss.h"
00042 
00043 /* NSPR 2.0 header files */
00044 #include "prinit.h"
00045 #include "prprf.h"
00046 #include "prsystem.h"
00047 #include "prmem.h"
00048 /* Portable layer header files */
00049 #include "plstr.h"
00050 #include "sechash.h" /* for HASH_GetHashObject() */
00051 
00052 static int debugInfo = 0;
00053 
00054 static char *usageInfo[] = {
00055        "Options:",
00056        " -a                           signature file is ASCII",
00057        " -d certdir                   directory containing cert database",
00058        " -i dataFileName              input file name containing data,",
00059        "                              use - for stdin",
00060        " -s signatureFileName         input file name containing signature,",
00061        "                              use - for stdin",
00062        " -o outputFileName            output file name, default stdout",
00063        " -A                           display all information from pkcs #7",
00064        " -V                           verify the signed object and display result",
00065        " -V -v                        verify the signed object and display",
00066        "                              result and reason for failure",
00067        "Version 2.0"
00068 };
00069 static int nUsageInfo = sizeof(usageInfo)/sizeof(char *);
00070 
00071 extern int SV_PrintPKCS7ContentInfo(FILE *, SECItem *);
00072 
00073 static void Usage(char *progName, FILE *outFile)
00074 {
00075        int i;
00076        fprintf(outFile, "Usage:  %s  options\n", progName);
00077        for (i = 0; i < nUsageInfo; i++)
00078               fprintf(outFile, "%s\n", usageInfo[i]);
00079        exit(-1);
00080 }
00081 
00082 static HASH_HashType
00083 AlgorithmToHashType(SECAlgorithmID *digestAlgorithms)
00084 {
00085        SECOidTag tag;
00086 
00087        tag = SECOID_GetAlgorithmTag(digestAlgorithms);
00088 
00089        switch (tag) {
00090               case SEC_OID_MD2:
00091                      if (debugInfo) PR_fprintf(PR_STDERR, "Hash algorithm: HASH_AlgMD2 SEC_OID_MD2\n");
00092                      return HASH_AlgMD2;
00093               case SEC_OID_MD5:
00094                      if (debugInfo) PR_fprintf(PR_STDERR, "Hash algorithm: HASH_AlgMD5 SEC_OID_MD5\n");
00095                      return HASH_AlgMD5;
00096               case SEC_OID_SHA1:
00097                      if (debugInfo) PR_fprintf(PR_STDERR, "Hash algorithm: HASH_AlgSHA1 SEC_OID_SHA1\n");
00098                      return HASH_AlgSHA1;
00099               default:
00100                      if (debugInfo) PR_fprintf(PR_STDERR, "should never get here\n");
00101                      return HASH_AlgNULL;
00102        }
00103 }
00104 
00105 
00106 static int
00107 DigestData (unsigned char *digest, unsigned char *data,
00108                      unsigned int *len, unsigned int maxLen,
00109                      HASH_HashType hashType)
00110 {
00111        const SECHashObject *hashObj;
00112        void *hashcx;
00113 
00114        hashObj = HASH_GetHashObject(hashType);
00115        hashcx = (* hashObj->create)();
00116        if (hashcx == NULL)
00117        return -1;
00118 
00119        (* hashObj->begin)(hashcx);
00120        (* hashObj->update)(hashcx, data, PORT_Strlen((char *)data));
00121        (* hashObj->end)(hashcx, digest, len, maxLen);
00122        (* hashObj->destroy)(hashcx, PR_TRUE);
00123 
00124        return 0;
00125 }
00126 
00127 enum {
00128        cmd_DisplayAllPCKS7Info = 0,
00129        cmd_DisplayCertInfo,
00130        cmd_DisplaySignerInfo,
00131        cmd_VerifySignedObj
00132 };
00133 
00134 enum {
00135        opt_ASCII,
00136        opt_CertDir,
00137        opt_InputDataFile,
00138        opt_ItemNumber,
00139        opt_OutputFile,
00140        opt_InputSigFile,
00141        opt_TypeTag,
00142        opt_PrintWhyFailure
00143 };
00144 
00145 static secuCommandFlag signver_commands[] =
00146 {
00147        { /* cmd_DisplayAllPCKS7Info*/  'A', PR_FALSE, 0, PR_FALSE },
00148        { /* cmd_VerifySignedObj    */  'V', PR_FALSE, 0, PR_FALSE }
00149 };
00150 
00151 static secuCommandFlag signver_options[] =
00152 {
00153        { /* opt_ASCII              */  'a', PR_FALSE, 0, PR_FALSE },
00154        { /* opt_CertDir            */  'd', PR_TRUE,  0, PR_FALSE },
00155        { /* opt_InputDataFile      */  'i', PR_TRUE,  0, PR_FALSE },
00156        { /* opt_OutputFile         */  'o', PR_TRUE,  0, PR_FALSE },
00157        { /* opt_InputSigFile       */  's', PR_TRUE,  0, PR_FALSE },
00158        { /* opt_TypeTag            */  't', PR_TRUE,  0, PR_FALSE },
00159        { /* opt_PrintWhyFailure    */  'v', PR_FALSE, 0, PR_FALSE }
00160 };
00161 
00162 int main(int argc, char **argv)
00163 {
00164        PRExplodedTime explodedCurrent;
00165        SECItem der, data;
00166        char *progName;
00167        int rv;
00168        PRFileDesc *dataFile = 0;
00169        PRFileDesc *signFile = 0;
00170        FILE *outFile = stdout;
00171        char *typeTag = 0;
00172        SECStatus secstatus;
00173 
00174        secuCommand signver;
00175        signver.numCommands = sizeof(signver_commands) /sizeof(secuCommandFlag);
00176        signver.numOptions = sizeof(signver_options) / sizeof(secuCommandFlag);
00177        signver.commands = signver_commands;
00178        signver.options = signver_options;
00179 
00180 #ifdef XP_PC
00181        progName = strrchr(argv[0], '\\');
00182 #else
00183        progName = strrchr(argv[0], '/');
00184 #endif
00185        progName = progName ? progName+1 : argv[0];
00186 
00187        /*_asm int 3*/
00188 
00189        PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &explodedCurrent);
00190 #if 0
00191        if (explodedCurrent.tm_year >= 1998
00192               && explodedCurrent.tm_month >= 5 /* months past tm_year (0-11, Jan = 0) */
00193               && explodedCurrent.tm_mday >= 1) {
00194               PR_fprintf(PR_STDERR, "%s: expired\n", progName);
00195               return -1;
00196        }
00197 #endif
00198 
00199        rv = SECU_ParseCommandLine(argc, argv, progName, &signver);
00200 
00201         if (SECSuccess != rv) {
00202             Usage(progName, outFile);
00203         }
00204 
00205        /*  Set the certdb directory (default is ~/.{browser}) */
00206        SECU_ConfigDirectory(signver.options[opt_CertDir].arg);
00207 
00208        /*  Set the certificate type.  */
00209        typeTag = SECU_GetOptionArg(&signver, opt_TypeTag);
00210 
00211        /*  -i and -s without filenames  */
00212        if (signver.options[opt_InputDataFile].activated &&
00213            signver.options[opt_InputSigFile].activated &&
00214            !PL_strcmp("-", signver.options[opt_InputDataFile].arg) &&
00215            !PL_strcmp("-", signver.options[opt_InputSigFile].arg))
00216               PR_fprintf(PR_STDERR, 
00217                      "%s: Only data or signature file can use stdin (not both).\n",
00218                      progName);
00219 
00220        /*  Open the input data file (no arg == use stdin). */
00221        if (signver.options[opt_InputDataFile].activated) {
00222               if (PL_strcmp("-", signver.options[opt_InputDataFile].arg))
00223                      dataFile = PR_Open(signver.options[opt_InputDataFile].arg, 
00224                                         PR_RDONLY, 0);
00225               else
00226                      dataFile = PR_STDIN;
00227               if (!dataFile) {
00228                      PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading.\n",
00229                                 progName, signver.options[opt_InputDataFile].arg);
00230                      return -1;
00231               }
00232        }
00233 
00234        /*  Open the input signature file (no arg == use stdin).  */
00235        if (signver.options[opt_InputSigFile].activated) {
00236               if (PL_strcmp("-", signver.options[opt_InputSigFile].arg))
00237                      signFile = PR_Open(signver.options[opt_InputSigFile].arg, 
00238                                         PR_RDONLY, 0);
00239               else
00240                      signFile = PR_STDIN;
00241               if (!signFile) {
00242                      PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading.\n",
00243                                 progName, signver.options[opt_InputSigFile].arg);
00244                      return -1;
00245               }
00246        }
00247 
00248 #if 0
00249                             if (!typeTag) ascii = 1;
00250 #endif
00251 
00252        /*  Open|Create the output file.  */
00253        if (signver.options[opt_OutputFile].activated) {
00254               outFile = fopen(signver.options[opt_OutputFile].arg, "w");
00255                      /*
00256               outFile = PR_Open(signver.options[opt_OutputFile].arg,
00257                                 PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 00660);
00258                                             */
00259               if (!outFile) {
00260                      PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for writing.\n",
00261                                 progName, signver.options[opt_OutputFile].arg);
00262                      return -1;
00263               }
00264        }
00265 
00266        if (!signFile && !dataFile && !typeTag) 
00267               Usage(progName, outFile);
00268 
00269        if (!signFile && !dataFile && 
00270             signver.commands[cmd_VerifySignedObj].activated) {
00271               PR_fprintf(PR_STDERR, 
00272                          "%s: unable to read all data from standard input\n", 
00273                          progName);
00274               return -1;
00275        } 
00276 
00277        PR_SetError(0, 0); /* PR_Init("pp", 1, 1, 0);*/
00278        secstatus = NSS_Init(SECU_ConfigDirectory(NULL));
00279        if (secstatus != SECSuccess) {
00280            SECU_PrintPRandOSError(progName);
00281            return -1;
00282        }
00283        SECU_RegisterDynamicOids();
00284 
00285        rv = SECU_ReadDERFromFile(&der, signFile, 
00286                                  signver.options[opt_ASCII].activated);
00287 
00288        /* Data is untyped, using the specified type */
00289        data.data = der.data;
00290        data.len = der.len;
00291 
00292 
00293        /* Signature Verification */
00294        if (!signver.options[opt_TypeTag].activated) {
00295               if (signver.commands[cmd_VerifySignedObj].activated) {
00296                      SEC_PKCS7ContentInfo *cinfo;
00297 
00298                      cinfo = SEC_PKCS7DecodeItem(&data, NULL, NULL, NULL, NULL,
00299                                                  NULL, NULL, NULL);
00300                      if (cinfo != NULL) {
00301 #if 0
00302                             if (debugInfo) {
00303                                    PR_fprintf(PR_STDERR, "Content %s encrypted.\n",
00304                                                     SEC_PKCS7ContentIsEncrypted(cinfo) ? "was" : "was not");
00305 
00306                                    PR_fprintf(PR_STDERR, "Content %s signed.\n",
00307                                                     SEC_PKCS7ContentIsSigned(cinfo) ? "was" : "was not");
00308                             }
00309 #endif
00310 
00311                             if (SEC_PKCS7ContentIsSigned(cinfo)) {
00312                                    SEC_PKCS7SignedData *signedData;
00313                                    HASH_HashType digestType;
00314                                    SECItem digest, data;
00315                                    unsigned char *dataToVerify, digestBuffer[32];
00316 
00317                                    signedData = cinfo->content.signedData;
00318 
00319                                    /* assume that there is only one digest algorithm for now */
00320                                    digestType = 
00321                                      AlgorithmToHashType(signedData->digestAlgorithms[0]);
00322                                    if (digestType == HASH_AlgNULL) {
00323                                           PR_fprintf(PR_STDERR, "Invalid hash algorithmID\n");
00324                                           return (-1);
00325                                    }
00326                                    rv = SECU_FileToItem(&data, dataFile);
00327                                    dataToVerify = data.data;
00328                                    if (dataToVerify) {
00329                                                              /*certUsageObjectSigner;*/
00330                                           SECCertUsage usage = certUsageEmailSigner; 
00331                                           
00332 
00333 #if 0
00334                                           if (debugInfo) 
00335                                                  PR_fprintf(PR_STDERR, "dataToVerify=%s\n", 
00336                                                             dataToVerify);
00337 #endif
00338                                           digest.data = digestBuffer;
00339                                           if (DigestData (digest.data, dataToVerify, 
00340                                                           &digest.len, 32, digestType)) {
00341                                                  PR_fprintf(PR_STDERR, "Fail to compute message digest for verification. Reason: %s\n",
00342                                                                  SECU_ErrorString((int16)PORT_GetError()));
00343                                                  return (-1);
00344                                           }
00345 #if 0
00346                                           if (debugInfo) {
00347                                                  PR_fprintf(PR_STDERR, "Data Digest=:");
00348                                                  for (i = 0; i < digest.len; i++)
00349                                                         PR_fprintf(PR_STDERR, "%02x:", digest.data[i]);
00350                                                  PR_fprintf(PR_STDERR, "\n");
00351                                           }
00352 #endif
00353 
00354 
00355                                           if (signver.commands[cmd_VerifySignedObj].activated)
00356                                                  fprintf(outFile, "signatureValid=");
00357                                           PORT_SetError(0);
00358                                           if (SEC_PKCS7VerifyDetachedSignature (cinfo, usage, 
00359                                                                  &digest, digestType, PR_FALSE)) {
00360                                                  if (signver.commands[cmd_VerifySignedObj].activated)
00361                                                         fprintf(outFile, "yes");
00362                                           } else {
00363                                                  if (signver.commands[cmd_VerifySignedObj].activated){
00364                                                         fprintf(outFile, "no");
00365                                                  if (signver.options[opt_PrintWhyFailure].activated)
00366                                                  fprintf(outFile, ":%s", SECU_ErrorString((int16)PORT_GetError()));
00367                                                  }
00368                                           }
00369                                           if (signver.commands[cmd_VerifySignedObj].activated)
00370                                                  fprintf(outFile, "\n");
00371 
00372                                           SECITEM_FreeItem(&data, PR_FALSE);
00373                                    } else {
00374                                           PR_fprintf(PR_STDERR, "Cannot read data\n");
00375                                           return (-1);
00376                                    }
00377                             }
00378 
00379                             SEC_PKCS7DestroyContentInfo(cinfo);
00380                      } else
00381                             PR_fprintf(PR_STDERR, "Unable to decode PKCS7 data\n");
00382               }
00383 
00384               if (signver.commands[cmd_DisplayAllPCKS7Info].activated)
00385                      SV_PrintPKCS7ContentInfo(outFile, &data);
00386 
00387        /* Pretty print it */
00388        } else if (PL_strcmp(typeTag, SEC_CT_CERTIFICATE) == 0) {
00389               rv = SECU_PrintSignedData(outFile, &data, "Certificate", 0,
00390                                                           SECU_PrintCertificate);
00391        } else if (PL_strcmp(typeTag, SEC_CT_CERTIFICATE_REQUEST) == 0) {
00392               rv = SECU_PrintSignedData(outFile, &data, "Certificate Request", 0,
00393                                                           SECU_PrintCertificateRequest);
00394        } else if (PL_strcmp (typeTag, SEC_CT_CRL) == 0) {
00395               rv = SECU_PrintSignedData (outFile, &data, "CRL", 0, SECU_PrintCrl);
00396 #ifdef HAVE_EPK_TEMPLATE
00397        } else if (PL_strcmp(typeTag, SEC_CT_PRIVATE_KEY) == 0) {
00398               rv = SECU_PrintPrivateKey(outFile, &data, "Private Key", 0);
00399 #endif
00400        } else if (PL_strcmp(typeTag, SEC_CT_PUBLIC_KEY) == 0) {
00401               rv = SECU_PrintPublicKey(outFile, &data, "Public Key", 0);
00402        } else if (PL_strcmp(typeTag, SEC_CT_PKCS7) == 0) {
00403               rv = SECU_PrintPKCS7ContentInfo(outFile, &data,
00404                                                                       "PKCS #7 Content Info", 0);
00405        } else {
00406               PR_fprintf(PR_STDERR, "%s: don't know how to print out '%s' files\n",
00407                                progName, typeTag);
00408               return -1;
00409        }
00410 
00411        if (rv) {
00412               PR_fprintf(PR_STDERR, "%s: problem converting data (%s)\n",
00413                                progName, SECU_ErrorString((int16)PORT_GetError()));
00414               return -1;
00415        }
00416 
00417        if (NSS_Shutdown() != SECSuccess) {
00418            exit(1);
00419        }
00420 
00421        return 0;
00422 }