Back to index

lightning-sunbird  0.9+nobinonly
verify.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 "signtool.h"
00038 
00039 
00040 static int    jar_cb(int status, JAR *jar, const char *metafile, 
00041 char *pathname, char *errortext);
00042 static int    verify_global (JAR *jar);
00043 
00044 /*************************************************************************
00045  *
00046  * V e r i f y J a r
00047  */
00048 int
00049 VerifyJar(char *filename)
00050 {
00051     FILE * fp;
00052 
00053     int       ret;
00054     int       status;
00055     int       failed = 0;
00056     char      *err;
00057 
00058     JAR * jar;
00059     JAR_Context * ctx;
00060 
00061     JAR_Item * it;
00062 
00063     jar = JAR_new();
00064 
00065     if ((fp = fopen (filename, "r")) == NULL) {
00066        perror (filename);
00067        exit (ERRX);
00068     } else
00069        fclose (fp);
00070 
00071     JAR_set_callback (JAR_CB_SIGNAL, jar, jar_cb);
00072 
00073 
00074     status = JAR_pass_archive (jar, jarArchGuess, filename, "some-url");
00075 
00076     if (status < 0 || jar->valid < 0) {
00077        failed = 1;
00078        PR_fprintf(outputFD, 
00079            "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n",
00080             filename);
00081        if (status < 0) {
00082            char      *errtext;
00083 
00084            if (status >= JAR_BASE && status <= JAR_BASE_END) {
00085               errtext = JAR_get_error (status);
00086            } else {
00087               errtext = SECU_ErrorString ((int16) PORT_GetError());
00088            }
00089 
00090            PR_fprintf(outputFD, "  (reported reason: %s)\n\n",
00091                 errtext);
00092 
00093            /* corrupt files should not have their contents listed */
00094 
00095            if (status == JAR_ERR_CORRUPT)
00096               return - 1;
00097        }
00098        PR_fprintf(outputFD,
00099            "entries shown below will have their digests checked only.\n");
00100        jar->valid = 0;
00101     } else
00102        PR_fprintf(outputFD,
00103            "archive \"%s\" has passed crypto verification.\n", filename);
00104 
00105     if (verify_global (jar))
00106        failed = 1;
00107 
00108     PR_fprintf(outputFD, "\n");
00109     PR_fprintf(outputFD, "%16s   %s\n", "status", "path");
00110     PR_fprintf(outputFD, "%16s   %s\n", "------------", "-------------------");
00111 
00112     ctx = JAR_find (jar, NULL, jarTypeMF);
00113 
00114     while (JAR_find_next (ctx, &it) >= 0) {
00115        if (it && it->pathname) {
00116            rm_dash_r(TMP_OUTPUT);
00117            ret = JAR_verified_extract (jar, it->pathname, TMP_OUTPUT);
00118            /* if (ret < 0) printf ("error %d on %s\n", ret, it->pathname); */
00119            if (ret < 0) 
00120               failed = 1;
00121 
00122            if (ret == JAR_ERR_PNF)
00123               err = "NOT PRESENT";
00124            else if (ret == JAR_ERR_HASH)
00125               err = "HASH FAILED";
00126            else
00127               err = "NOT VERIFIED";
00128 
00129            PR_fprintf(outputFD, "%16s   %s\n", 
00130                ret >= 0 ? "verified" : err, it->pathname);
00131 
00132            if (ret != 0 && ret != JAR_ERR_PNF && ret != JAR_ERR_HASH)
00133               PR_fprintf(outputFD, "      (reason: %s)\n",
00134                    JAR_get_error (ret));
00135        }
00136     }
00137 
00138     JAR_find_end (ctx);
00139 
00140     if (status < 0 || jar->valid < 0) {
00141        failed = 1;
00142        PR_fprintf(outputFD,
00143            "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n",
00144             filename);
00145        give_help (status);
00146     }
00147 
00148     JAR_destroy (jar);
00149 
00150     if (failed)
00151        return - 1;
00152     return 0;
00153 }
00154 
00155 
00156 /***************************************************************************
00157  *
00158  * v e r i f y _ g l o b a l
00159  */
00160 static int    
00161 verify_global (JAR *jar)
00162 {
00163     FILE        * fp;
00164     JAR_Context * ctx;
00165     JAR_Item    * it;
00166     JAR_Digest  * globaldig;
00167     char      * ext;
00168     unsigned char *md5_digest, *sha1_digest;
00169     unsigned int  sha1_length, md5_length;
00170     int                 retval = 0;
00171     char        buf [BUFSIZ];
00172 
00173     ctx = JAR_find (jar, "*", jarTypePhy);
00174 
00175     while (JAR_find_next (ctx, &it) >= 0) {
00176        if (!PORT_Strncmp (it->pathname, "META-INF", 8)) {
00177            for (ext = it->pathname; *ext; ext++)
00178               ;
00179            while (ext > it->pathname && *ext != '.') 
00180               ext--;
00181 
00182            if (verbosity >= 0) {
00183               if (!PORT_Strcasecmp (ext, ".rsa")) {
00184                   PR_fprintf(outputFD, "found a RSA signature file: %s\n",
00185                                                    it->pathname);
00186               }
00187 
00188               if (!PORT_Strcasecmp (ext, ".dsa")) {
00189                   PR_fprintf(outputFD, "found a DSA signature file: %s\n",
00190                                                    it->pathname);
00191               }
00192 
00193               if (!PORT_Strcasecmp (ext, ".mf")) {
00194                   PR_fprintf(outputFD,
00195                       "found a MF master manifest file: %s\n",
00196                        it->pathname);
00197               }
00198            }
00199 
00200            if (!PORT_Strcasecmp (ext, ".sf")) {
00201               if (verbosity >= 0) {
00202                   PR_fprintf(outputFD,
00203                       "found a SF signature manifest file: %s\n",
00204                        it->pathname);
00205               }
00206 
00207               rm_dash_r(TMP_OUTPUT);
00208               if (JAR_extract (jar, it->pathname, TMP_OUTPUT) < 0) {
00209                   PR_fprintf(errorFD, "%s: error extracting %s\n",
00210                        PROGRAM_NAME, it->pathname);
00211                   errorCount++;
00212                   retval = -1;
00213                   continue;
00214               }
00215 
00216               md5_digest = NULL;
00217               sha1_digest = NULL;
00218 
00219               if ((fp = fopen (TMP_OUTPUT, "rb")) != NULL) {
00220                   while (fgets (buf, BUFSIZ, fp)) {
00221                      char   *s;
00222 
00223                      if (*buf == 0 || *buf == '\n' || *buf == '\r') 
00224                          break;
00225 
00226                      for (s = buf; *s && *s != '\n' && *s != '\r'; s++)
00227                          ;
00228                      *s = 0;
00229 
00230                      if (!PORT_Strncmp (buf, "MD5-Digest: ", 12)) {
00231                          md5_digest = 
00232                             ATOB_AsciiToData (buf + 12, &md5_length);
00233                      }
00234                      if (!PORT_Strncmp (buf, "SHA1-Digest: ", 13)) {
00235                          sha1_digest = 
00236                             ATOB_AsciiToData (buf + 13, &sha1_length);
00237                      }
00238                      if (!PORT_Strncmp (buf, "SHA-Digest: ", 12)) {
00239                          sha1_digest = 
00240                             ATOB_AsciiToData (buf + 12, &sha1_length);
00241                      }
00242                   }
00243 
00244                   globaldig = jar->globalmeta;
00245 
00246                   if (globaldig && md5_digest && verbosity >= 0) {
00247                      PR_fprintf(outputFD,
00248                         "  md5 digest on global metainfo: %s\n",
00249                          PORT_Memcmp(md5_digest, globaldig->md5, MD5_LENGTH)
00250                          ? "no match" : "match");
00251                   }
00252 
00253                   if (globaldig && sha1_digest && verbosity >= 0) {
00254                      PR_fprintf(outputFD,
00255                          "  sha digest on global metainfo: %s\n",
00256                          PORT_Memcmp(sha1_digest, globaldig->sha1, SHA1_LENGTH) 
00257                          ? "no match" : "match");
00258                   }
00259 
00260                   if (globaldig == NULL && verbosity >= 0) {
00261                      PR_fprintf(outputFD,
00262                           "global metadigest is not available, strange.\n");
00263                   }
00264 
00265                   fclose (fp);
00266               }
00267            }
00268        }
00269     }
00270 
00271     JAR_find_end (ctx);
00272 
00273     return retval;
00274 }
00275 
00276 
00277 /************************************************************************
00278  *
00279  * J a r W h o
00280  */
00281 int
00282 JarWho(char *filename)
00283 {
00284     FILE * fp;
00285 
00286     JAR * jar;
00287     JAR_Context * ctx;
00288 
00289     int       status;
00290     int       retval = 0;
00291 
00292     JAR_Item * it;
00293     JAR_Cert * fing;
00294 
00295     CERTCertificate * cert, *prev = NULL;
00296 
00297     jar = JAR_new();
00298 
00299     if ((fp = fopen (filename, "r")) == NULL) {
00300        perror (filename);
00301        exit (ERRX);
00302     } 
00303     fclose (fp);
00304 
00305     status = JAR_pass_archive (jar, jarArchGuess, filename, "some-url");
00306 
00307     if (status < 0 || jar->valid < 0) {
00308        PR_fprintf(outputFD,
00309            "NOTE -- \"%s\" archive DID NOT PASS crypto verification.\n",
00310             filename);
00311        retval = -1;
00312        if (jar->valid < 0 || status != -1) {
00313            char      *errtext;
00314 
00315            if (status >= JAR_BASE && status <= JAR_BASE_END) {
00316               errtext = JAR_get_error (status);
00317            } else {
00318               errtext = SECU_ErrorString ((int16) PORT_GetError());
00319            }
00320 
00321            PR_fprintf(outputFD, "  (reported reason: %s)\n\n", errtext);
00322        }
00323     }
00324 
00325     PR_fprintf(outputFD, "\nSigner information:\n\n");
00326 
00327     ctx = JAR_find (jar, NULL, jarTypeSign);
00328 
00329     while (JAR_find_next (ctx, &it) >= 0) {
00330        fing = (JAR_Cert * ) it->data;
00331        cert = fing->cert;
00332 
00333        if (cert) {
00334            if (prev == cert)
00335               break;
00336 
00337            if (cert->nickname)
00338               PR_fprintf(outputFD, "nickname: %s\n", cert->nickname);
00339            if (cert->subjectName)
00340               PR_fprintf(outputFD, "subject name: %s\n",
00341                    cert->subjectName);
00342            if (cert->issuerName)
00343               PR_fprintf(outputFD, "issuer name: %s\n", cert->issuerName);
00344        } else {
00345            PR_fprintf(outputFD, "no certificate could be found\n");
00346            retval = -1;
00347        }
00348 
00349        prev = cert;
00350     }
00351 
00352     JAR_find_end (ctx);
00353 
00354     JAR_destroy (jar);
00355     return retval;
00356 }
00357 
00358 
00359 /************************************************************************
00360  * j a r _ c b
00361  */
00362 static int    jar_cb(int status, JAR *jar, const char *metafile,
00363 char *pathname, char *errortext)
00364 {
00365     PR_fprintf(errorFD, "error %d: %s IN FILE %s\n", status, errortext,
00366          pathname);
00367     errorCount++;
00368     return 0;
00369 }
00370 
00371