Back to index

lightning-sunbird  0.9+nobinonly
vfychain.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 /****************************************************************************
00038  *  Read in a cert chain from one or more files, and verify the chain for
00039  *  some usage.
00040  *                                                                          *
00041  *  This code was modified from other code also kept in the NSS directory.
00042  ****************************************************************************/ 
00043 
00044 #include <stdio.h>
00045 #include <string.h>
00046 
00047 #if defined(XP_UNIX)
00048 #include <unistd.h>
00049 #endif
00050 
00051 #include "prerror.h"
00052 
00053 #include "nssrenam.h"
00054 #include "pk11func.h"
00055 #include "seccomon.h"
00056 #include "secutil.h"
00057 #include "secmod.h"
00058 #include "secitem.h"
00059 #include "cert.h"
00060 
00061 
00062 /* #include <stdlib.h> */
00063 /* #include <errno.h> */
00064 /* #include <fcntl.h> */
00065 /* #include <stdarg.h> */
00066 
00067 #include "nspr.h"
00068 #include "plgetopt.h"
00069 #include "prio.h"
00070 #include "nss.h"
00071 
00072 /* #include "vfyutil.h" */
00073 
00074 #define RD_BUF_SIZE (60 * 1024)
00075 
00076 int verbose;
00077 
00078 char *password = NULL;
00079 
00080 /* Function: char * myPasswd()
00081  * 
00082  * Purpose: This function is our custom password handler that is called by
00083  * SSL when retreiving private certs and keys from the database. Returns a
00084  * pointer to a string that with a password for the database. Password pointer
00085  * should point to dynamically allocated memory that will be freed later.
00086  */
00087 char *
00088 myPasswd(PK11SlotInfo *info, PRBool retry, void *arg)
00089 {
00090     char * passwd = NULL;
00091 
00092     if ( (!retry) && arg ) {
00093        passwd = PORT_Strdup((char *)arg);
00094     }
00095     return passwd;
00096 }
00097 
00098 static void
00099 Usage(const char *progName)
00100 {
00101     fprintf(stderr, 
00102            "Usage: %s [-d dbdir] certfile [certfile ...]\n",
00103             progName);
00104     exit(1);
00105 }
00106 
00107 /**************************************************************************
00108 ** 
00109 ** Error and information routines.
00110 **
00111 **************************************************************************/
00112 
00113 void
00114 errWarn(char *function)
00115 {
00116     PRErrorCode  errorNumber = PR_GetError();
00117     const char * errorString = SECU_Strerror(errorNumber);
00118 
00119     fprintf(stderr, "Error in function %s: %d\n - %s\n",
00120                   function, errorNumber, errorString);
00121 }
00122 
00123 void
00124 exitErr(char *function)
00125 {
00126     errWarn(function);
00127     /* Exit gracefully. */
00128     /* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/
00129     (void) NSS_Shutdown();
00130     PR_Cleanup();
00131     exit(1);
00132 }
00133 
00134 typedef struct certMemStr {
00135     struct certMemStr * next;
00136     CERTCertificate * cert;
00137 } certMem;
00138 
00139 certMem * theCerts;
00140 
00141 void
00142 rememberCert(CERTCertificate * cert)
00143 {
00144     certMem * newCertMem = PORT_ZNew(certMem);
00145     if (newCertMem) {
00146        newCertMem->next = theCerts;
00147        newCertMem->cert = cert;
00148        theCerts = newCertMem;
00149     }
00150 }
00151 
00152 void
00153 forgetCerts(void)
00154 {
00155     certMem * oldCertMem;
00156     while (oldCertMem = theCerts) {
00157        theCerts = oldCertMem->next;
00158        CERT_DestroyCertificate(oldCertMem->cert);
00159        PORT_Free(oldCertMem);
00160     }
00161     theCerts = NULL;
00162 }
00163 
00164 
00165 CERTCertificate *
00166 readCertFile(const char * fileName, PRBool isAscii)
00167 {
00168     unsigned char * pb;
00169     CERTCertificate * cert  = NULL;
00170     CERTCertDBHandle *defaultDB = NULL;
00171     PRFileDesc*     fd;
00172     PRInt32         cc      = -1;
00173     PRInt32         total;
00174     PRInt32         remaining;
00175     SECItem         item;
00176     static unsigned char certBuf[RD_BUF_SIZE];
00177 
00178     fd = PR_Open(fileName, PR_RDONLY, 0777); 
00179     if (!fd) {
00180        PRIntn err = PR_GetError();
00181        fprintf(stderr, "open of %s failed, %d = %s\n", 
00182                fileName, err, SECU_Strerror(err));
00183        return cert;
00184     }
00185     /* read until EOF or buffer is full */
00186     pb = certBuf;
00187     while (0 < (remaining = (sizeof certBuf) - (pb - certBuf))) {
00188        cc = PR_Read(fd, pb, remaining);
00189        if (cc == 0) 
00190            break;
00191        if (cc < 0) {
00192            PRIntn err = PR_GetError();
00193            fprintf(stderr, "read of %s failed, %d = %s\n", 
00194                fileName, err, SECU_Strerror(err));
00195            break;
00196        }
00197        /* cc > 0 */
00198        pb += cc;
00199     }
00200     PR_Close(fd);
00201     if (cc < 0)
00202        return cert;
00203     if (!remaining || cc > 0) { /* file was too big. */
00204        fprintf(stderr, "cert file %s was too big.\n", fileName);
00205        return cert;
00206     }
00207     total = pb - certBuf;
00208     if (!total) { /* file was empty */
00209        fprintf(stderr, "cert file %s was empty.\n", fileName);
00210        return cert;
00211     }
00212     if (isAscii) {
00213        /* convert from Base64 to binary here ... someday */
00214     }
00215     item.type = siBuffer;
00216     item.data = certBuf;
00217     item.len  = total;
00218     defaultDB = CERT_GetDefaultCertDB();
00219     cert = CERT_NewTempCertificate(defaultDB, &item, 
00220                                    NULL     /* nickname */, 
00221                                    PR_FALSE /* isPerm */, 
00222                                PR_TRUE  /* copyDER */);
00223     if (!cert) {
00224        PRIntn err = PR_GetError();
00225        fprintf(stderr, "couldn't import %s, %d = %s\n",
00226                fileName, err, SECU_Strerror(err));
00227     }
00228     return cert;
00229 }
00230 
00231 int
00232 main(int argc, char *argv[], char *envp[])
00233 {
00234     char *               certDir      = NULL;
00235     char *               progName     = NULL;
00236     CERTCertificate *    cert;
00237     CERTCertificate *    firstCert    = NULL;
00238     CERTCertDBHandle *   defaultDB    = NULL;
00239     PRBool               isAscii      = PR_FALSE;
00240     SECStatus            secStatus;
00241     SECCertificateUsage  certUsage    = certificateUsageSSLServer;
00242     PLOptState *         optstate;
00243     PLOptStatus          status;
00244     int                  rv = 1;
00245 
00246     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
00247 
00248     progName = PL_strdup(argv[0]);
00249 
00250     optstate = PL_CreateOptState(argc, argv, "ad:ru:w:v");
00251     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
00252        switch(optstate->option) {
00253        case  0  : /* positional parameter */  goto breakout;
00254        case 'a' : isAscii  = PR_TRUE;                        break;
00255        case 'd' : certDir  = PL_strdup(optstate->value);     break;
00256        case 'r' : isAscii  = PR_FALSE;                       break;
00257        case 'u' : certUsage = ((SECCertificateUsage) 1) << PORT_Atoi(optstate->value); break;
00258        case 'w' : password = PL_strdup(optstate->value);     break;
00259        case 'v' : verbose++;                                 break;
00260        default  : Usage(progName);                           break;
00261        }
00262     }
00263 breakout:
00264     if (status != PL_OPT_OK)
00265        Usage(progName);
00266 
00267     /* Set our password function callback. */
00268     PK11_SetPasswordFunc(myPasswd);
00269 
00270     /* Initialize the NSS libraries. */
00271     if (certDir) {
00272        secStatus = NSS_Init(certDir);
00273     } else {
00274        secStatus = NSS_NoDB_Init(NULL);
00275 
00276        /* load the builtins */
00277        SECMOD_AddNewModule("Builtins", DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0);
00278     }
00279     if (secStatus != SECSuccess) {
00280        exitErr("NSS_Init");
00281     }
00282     SECU_RegisterDynamicOids();
00283 
00284     while (status == PL_OPT_OK) {
00285        switch(optstate->option) {
00286        default  : Usage(progName);                           break;
00287        case 'a' : isAscii  = PR_TRUE;                        break;
00288        case 'r' : isAscii  = PR_FALSE;                       break;
00289        case  0  : /* positional parameter */
00290            cert = readCertFile(optstate->value, isAscii);
00291            if (!cert) 
00292                goto punt;
00293            rememberCert(cert);
00294            if (!firstCert)
00295                firstCert = cert;
00296            break;
00297        }
00298         status = PL_GetNextOpt(optstate);
00299     }
00300     if (status == PL_OPT_BAD || !firstCert)
00301        Usage(progName);
00302 
00303     /* NOW, verify the cert chain. */
00304     defaultDB = CERT_GetDefaultCertDB();
00305     secStatus = CERT_VerifyCertificate(defaultDB, firstCert, 
00306                                 PR_TRUE /* check sig */,
00307                             certUsage, 
00308                             PR_Now(), 
00309                             NULL,         /* wincx  */
00310                             NULL,         /* error log */
00311                                 NULL);          /* returned usages */
00312 
00313     if (secStatus != SECSuccess) {
00314        PRIntn err = PR_GetError();
00315        fprintf(stderr, "Chain is bad, %d = %s\n", err, SECU_Strerror(err));
00316        SECU_printCertProblems(stderr, defaultDB, firstCert, 
00317                        PR_TRUE, certUsage, NULL, verbose);
00318        rv = 1;
00319     } else {
00320        fprintf(stderr, "Chain is good!\n");
00321        rv = 0;
00322     }
00323 
00324 punt:
00325     forgetCerts();
00326     if (NSS_Shutdown() != SECSuccess) {
00327        SECU_PrintError(progName, "NSS_Shutdown");
00328        rv = 1;
00329     }
00330     PR_Cleanup();
00331     return rv;
00332 }