mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
afdeb339c5
r=wtc
1132 lines
29 KiB
C
1132 lines
29 KiB
C
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is the Netscape security libraries.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "signtool.h"
|
|
#include "prio.h"
|
|
#include "prmem.h"
|
|
#include "nss.h"
|
|
|
|
static int is_dir (char *filename);
|
|
|
|
/***********************************************************
|
|
* Nasty hackish function definitions
|
|
*/
|
|
|
|
long *mozilla_event_queue = 0;
|
|
|
|
#ifndef XP_WIN
|
|
char *XP_GetString (int i)
|
|
{
|
|
return SECU_ErrorStringRaw ((int16) i);
|
|
}
|
|
#endif
|
|
|
|
void FE_SetPasswordEnabled()
|
|
{
|
|
}
|
|
|
|
|
|
void /*MWContext*/ *FE_GetInitContext (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
void /*MWContext*/ *XP_FindSomeContext()
|
|
{
|
|
/* No windows context in command tools */
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void ET_moz_CallFunction()
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* R e m o v e A l l A r c
|
|
*
|
|
* Remove .arc directories that are lingering
|
|
* from a previous run of signtool.
|
|
*
|
|
*/
|
|
int
|
|
RemoveAllArc(char *tree)
|
|
{
|
|
PRDir * dir;
|
|
PRDirEntry * entry;
|
|
char *archive = NULL;
|
|
int retval = 0;
|
|
|
|
dir = PR_OpenDir (tree);
|
|
if (!dir)
|
|
return - 1;
|
|
|
|
for (entry = PR_ReadDir (dir, 0); entry; entry = PR_ReadDir (dir,
|
|
0)) {
|
|
|
|
if (entry->name[0] == '.') {
|
|
continue;
|
|
}
|
|
|
|
if (archive)
|
|
PR_Free(archive);
|
|
archive = PR_smprintf("%s/%s", tree, entry->name);
|
|
|
|
if (PL_strcaserstr (entry->name, ".arc")
|
|
== (entry->name + strlen(entry->name) - 4) ) {
|
|
|
|
if (verbosity >= 0) {
|
|
PR_fprintf(outputFD, "removing: %s\n", archive);
|
|
}
|
|
|
|
if (rm_dash_r(archive)) {
|
|
PR_fprintf(errorFD, "Error removing %s\n", archive);
|
|
errorCount++;
|
|
retval = -1;
|
|
goto finish;
|
|
}
|
|
} else if (is_dir(archive)) {
|
|
if (RemoveAllArc(archive)) {
|
|
retval = -1;
|
|
goto finish;
|
|
}
|
|
}
|
|
}
|
|
|
|
finish:
|
|
PR_CloseDir (dir);
|
|
if (archive)
|
|
PR_Free(archive);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
/*
|
|
* r m _ d a s h _ r
|
|
*
|
|
* Remove a file, or a directory recursively.
|
|
*
|
|
*/
|
|
int rm_dash_r (char *path)
|
|
{
|
|
PRDir * dir;
|
|
PRDirEntry * entry;
|
|
PRFileInfo fileinfo;
|
|
char filename[FNSIZE];
|
|
|
|
if (PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) {
|
|
/*fprintf(stderr, "Error: Unable to access %s\n", filename);*/
|
|
return - 1;
|
|
}
|
|
if (fileinfo.type == PR_FILE_DIRECTORY) {
|
|
|
|
dir = PR_OpenDir(path);
|
|
if (!dir) {
|
|
PR_fprintf(errorFD, "Error: Unable to open directory %s.\n", path);
|
|
errorCount++;
|
|
return - 1;
|
|
}
|
|
|
|
/* Recursively delete all entries in the directory */
|
|
while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
|
|
sprintf(filename, "%s/%s", path, entry->name);
|
|
if (rm_dash_r(filename))
|
|
return - 1;
|
|
}
|
|
|
|
if (PR_CloseDir(dir) != PR_SUCCESS) {
|
|
PR_fprintf(errorFD, "Error: Could not close %s.\n", path);
|
|
errorCount++;
|
|
return - 1;
|
|
}
|
|
|
|
/* Delete the directory itself */
|
|
if (PR_RmDir(path) != PR_SUCCESS) {
|
|
PR_fprintf(errorFD, "Error: Unable to delete %s\n", path);
|
|
errorCount++;
|
|
return - 1;
|
|
}
|
|
} else {
|
|
if (PR_Delete(path) != PR_SUCCESS) {
|
|
PR_fprintf(errorFD, "Error: Unable to delete %s\n", path);
|
|
errorCount++;
|
|
return - 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* u s a g e
|
|
*
|
|
* Print some useful help information
|
|
*
|
|
*/
|
|
|
|
|
|
void
|
|
Usage (void)
|
|
{
|
|
#define FPS PR_fprintf(outputFD,
|
|
FPS "%s %s -a signing tool for jar files\n", LONG_PROGRAM_NAME,NSS_VERSION);
|
|
FPS "\n\nType %s -H for more detailed descriptions\n", PROGRAM_NAME);
|
|
FPS "\nUsage: %s -k keyName [-b basename] [-c Compression Level]\n"
|
|
"\t\t [-d cert-dir] [-i installer script] [-m metafile] [-x name]\n"
|
|
"\t\t [-e extension] [-o] [-z] [-X] [--outfile] [--verbose value]\n"
|
|
"\t\t [--norecurse] [--leavearc] [-j directory] [-Z jarfile] [-O]\n"
|
|
"\t\t [-p password] directory-tree\n", PROGRAM_NAME);
|
|
FPS "\t%s -J -k keyName [-b basename] [-c Compression Level]\n"
|
|
"\t\t [-d cert-dir][-i installer script] [-m metafile] [-x name]\n"
|
|
"\t\t [-e extension] [-o] [-z] [-X] [--outfile] [--verbose value]\n"
|
|
"\t\t [--norecurse] [--leavearc] [-j directory] [-p password] [-O] \n"
|
|
"\t\t directory-tree\n", PROGRAM_NAME);
|
|
FPS "\t%s -h \n", PROGRAM_NAME);
|
|
FPS "\t%s -H \n", PROGRAM_NAME);
|
|
FPS "\t%s -l [-k keyName] [-d cert-dir] [--outfile] [-O] \n", PROGRAM_NAME);
|
|
FPS "\t%s -L [-k keyName] [-d cert-dir] [--outfile] [-O] \n", PROGRAM_NAME);
|
|
FPS "\t%s -M [--outfile] [-O] \n", PROGRAM_NAME);
|
|
FPS "\t%s -v [-d cert-dir] [--outfile] [-O] archive\n", PROGRAM_NAME);
|
|
FPS "\t%s -w [--outfile] [-O] archive\n" , PROGRAM_NAME);
|
|
FPS "\t%s -G nickname [--keysize|-s size] [-t |--token tokenname]\n"
|
|
"\t\t [--outfile] [-O] \n", PROGRAM_NAME);
|
|
FPS "\t%s -f filename\n" , PROGRAM_NAME);
|
|
exit (ERRX);
|
|
}
|
|
|
|
void
|
|
LongUsage(void)
|
|
{
|
|
FPS "%s %s -a signing tool for jar files\n", LONG_PROGRAM_NAME,NSS_VERSION);
|
|
FPS "\n%-20s Signs the directory-tree\n",
|
|
"signtool directory-tree");
|
|
FPS "%-30s Nickname (key) of the certificate to sign with\n",
|
|
" -k keyname");
|
|
FPS "%-30s Base filename for the .rsa and.sf files in the\n",
|
|
" -b basename");
|
|
FPS "%-30s META-INF directory\n"," ");
|
|
FPS "%-30s Set the compression level. 0-9, 0=none\n",
|
|
" -c CompressionLevel");
|
|
FPS "%-30s Certificate database directory containing cert*db\n",
|
|
" -d certificate directory");
|
|
FPS "%-30s and key*db\n"," ");
|
|
FPS "%-30s Name of the installer script for SmartUpdate\n",
|
|
" -i installer script");
|
|
FPS "%-30s Name of a metadata control file\n",
|
|
" -m metafile");
|
|
FPS "%-30s For optimizing the archive for size.\n",
|
|
" -o");
|
|
FPS "%-30s Omit Optional Headers\n"," ");
|
|
FPS "%-30s Excludes the specified directory or file from\n",
|
|
" -x directory or file name");
|
|
FPS "%-30s signing\n"," ");
|
|
FPS "%-30s To not store the signing time in digital\n",
|
|
" -z directory or file name");
|
|
FPS "%-30s signature\n"," ");
|
|
FPS "%-30s Create XPI Compatible Archive. It requires -Z\n",
|
|
" -X directory or file name");
|
|
FPS "%-30s option\n"," ");
|
|
FPS "%-30s Sign only files with the given extension\n",
|
|
" -e");
|
|
FPS "%-30s Causes the specified directory to be signed and\n",
|
|
" -j");
|
|
FPS "%-30s tags its entries as inline JavaScript\n"," ");
|
|
FPS "%-30s Creates a JAR file with the specified name.\n",
|
|
" -Z");
|
|
FPS "%-30s -Z option cannot be used with -J option\n"," ");
|
|
FPS "%-30s Specifies a password for the private-key database\n",
|
|
" -p");
|
|
FPS "%-30s (insecure)\n"," ");
|
|
FPS "%-30s File to receive redirected output\n",
|
|
" --outfile filename");
|
|
FPS "%-30s Sets the quantity of information generated in\n",
|
|
" --verbosity value");
|
|
FPS "%-30s operation\n"," ");
|
|
FPS "%-30s Blocks recursion into subdirectories\n",
|
|
" --norecurse");
|
|
FPS "%-30s Retains the temporary .arc (archive) directories\n",
|
|
" --leavearc");
|
|
FPS "%-30s -J option creates\n"," ");
|
|
|
|
FPS "\n%-20s Signs a directory of HTML files containing JavaScript and\n",
|
|
"-J" );
|
|
FPS "%-20s creates as many archive files as are in the HTML tags.\n"," ");
|
|
|
|
FPS "%-20s The options are same as without any command option given\n"," ");
|
|
FPS "%-20s above. -Z and -J options are not allowed together\n"," ");
|
|
|
|
FPS "\n%-20s Generates a new private-public key pair and corresponding\n",
|
|
"-G nickname");
|
|
FPS "%-20s object-signing certificates with the given nickname\n"," ");
|
|
FPS "%-30s Specifies the size of the key for generated \n",
|
|
" --keysize|-s keysize");
|
|
FPS "%-30s certificate\n"," ");
|
|
FPS "%-30s Specifies which available token should generate\n",
|
|
" --token|-t token name ");
|
|
FPS "%-30s the key and receive the certificate\n"," ");
|
|
FPS "%-30s Specifies a file to receive redirected output\n",
|
|
" --outfile filename ");
|
|
|
|
FPS "\n%-20s Display signtool help\n",
|
|
"-h ");
|
|
|
|
FPS "\n%-20s Display signtool help(Detailed)\n",
|
|
"-H ");
|
|
|
|
FPS "\n%-20s Lists signing certificates, including issuing CAs\n",
|
|
"-l ");
|
|
FPS "%-30s Certificate database directory containing cert*db\n",
|
|
" -d certificate directory");
|
|
FPS "%-30s and key*db\n"," ");
|
|
|
|
FPS "%-30s Specifies a file to receive redirected output\n",
|
|
" --outfile filename ");
|
|
FPS "%-30s Specifies the nickname (key) of the certificate\n",
|
|
" -k keyname");
|
|
|
|
|
|
FPS "\n%-20s Lists the certificates in your database\n",
|
|
"-L ");
|
|
FPS "%-30s Certificate database directory containing cert*db\n",
|
|
" -d certificate directory");
|
|
FPS "%-30s and key*db\n"," ");
|
|
|
|
FPS "%-30s Specifies a file to receive redirected output\n",
|
|
" --outfile filename ");
|
|
FPS "%-30s Specifies the nickname (key) of the certificate\n",
|
|
" -k keyname");
|
|
|
|
FPS "\n%-20s Lists the PKCS #11 modules available to signtool\n",
|
|
"-M ");
|
|
|
|
FPS "\n%-20s Displays the contents of an archive and verifies\n",
|
|
"-v archive");
|
|
FPS "%-20s cryptographic integrity\n"," ");
|
|
FPS "%-30s Certificate database directory containing cert*db\n",
|
|
" -d certificate directory");
|
|
FPS "%-30s and key*db\n"," ");
|
|
FPS "%-30s Specifies a file to receive redirected output\n",
|
|
" --outfile filename ");
|
|
|
|
FPS "\n%-20s Displays the names of signers in the archive\n",
|
|
"-w archive");
|
|
FPS "%-30s Specifies a file to receive redirected output\n",
|
|
" --outfile filename ");
|
|
|
|
|
|
FPS "\n%-30s Common option to all the above.\n",
|
|
" -O");
|
|
FPS "%-30s Enable OCSP checking\n"," ");
|
|
|
|
FPS "\n%-20s Specifies a text file containing options and arguments in\n",
|
|
"-f command-file");
|
|
FPS "%-20s keyword=value format. Commands are taken from this file\n"," ");
|
|
|
|
FPS "\n\n\n");
|
|
FPS "Example:\n");
|
|
FPS "%-10s -d \"certificate directory\" -k \"certnickname\" \\",
|
|
PROGRAM_NAME);
|
|
FPS "\n%-10s -p \"password\" -X -Z \"file.xpi\" directory-tree\n"," " );
|
|
FPS "Common syntax to create an XPInstall compatible"
|
|
" signed archive\n\n"," ");
|
|
FPS "\nCommand File Keywords and Example:\n");
|
|
FPS "\nKeyword\t\tValue\n");
|
|
FPS "basename\tSame as -b option\n");
|
|
FPS "compression\tSame as -c option\n");
|
|
FPS "certdir\t\tSame as -d option\n");
|
|
FPS "extension\tSame as -e option\n");
|
|
FPS "generate\tSame as -G option\n");
|
|
FPS "installscript\tSame as -i option\n");
|
|
FPS "javascriptdir\tSame as -j option\n");
|
|
FPS "htmldir\t\tSame as -J option\n");
|
|
FPS "certname\tNickname of certificate, as with -k option\n");
|
|
FPS "signdir\t\tThe directory to be signed, as with -k option\n");
|
|
FPS "list\t\tSame as -l option. Value is ignored,\n"
|
|
" \t\tbut = sign must be present\n");
|
|
FPS "listall\t\tSame as -L option. Value is ignored\n"
|
|
" \t\tbut = sign must be present\n");
|
|
FPS "metafile\tSame as -m option\n");
|
|
FPS "modules\t\tSame as -M option. Value is ignored,\n"
|
|
" \t\tbut = sign must be present\n");
|
|
FPS "optimize\tSame as -o option. Value is ignored,\n"
|
|
" \tbut = sign must be present\n");
|
|
FPS "ocsp\t\tSame as -O option\n");
|
|
FPS "password\tSame as -p option\n");
|
|
FPS "verify\t\tSame as -v option\n");
|
|
FPS "who\t\tSame as -w option\n");
|
|
FPS "exclude\t\tSame as -x option\n");
|
|
FPS "notime\t\tSame as -z option. Value is ignored,\n"
|
|
" \t\tbut = sign must be present\n");
|
|
FPS "jarfile\t\tSame as -Z option\n");
|
|
FPS "outfile\t\tSame as --outfile option. The argument\n");
|
|
FPS " \t\tis the name of a file to which output\n");
|
|
FPS " \t\tof a file and error messages will be \n");
|
|
FPS " \t\tredirected\n");
|
|
FPS "leavearc\tSame as --leavearc option\n");
|
|
FPS "verbosity\tSame as --verbosity option\n");
|
|
FPS "keysize\t\tSame as -s option\n");
|
|
FPS "token\t\tSame as -t option\n");
|
|
FPS "xpi\t\tSame as -X option\n");
|
|
FPS "\n\n");
|
|
FPS "Here's an example of the use of the command file. The command\n\n");
|
|
FPS " signtool -d c:\\netscape\\users\\james -k mycert -Z myjar.jar \\\n"
|
|
" signdir > output.txt\n\n");
|
|
FPS "becomes\n\n");
|
|
FPS " signtool -f somefile\n\n");
|
|
FPS "where somefile contains the following lines:\n\n");
|
|
FPS " certdir=c:\\netscape\\users\\james\n"," ");
|
|
FPS " certname=mycert\n"," ");
|
|
FPS " jarfile=myjar.jar\n"," ");
|
|
FPS " signdir=signdir\n"," ");
|
|
FPS " outfile=output.txt\n"," ");
|
|
exit (ERRX);
|
|
#undef FPS
|
|
}
|
|
|
|
/*
|
|
* p r i n t _ e r r o r
|
|
*
|
|
* For the undocumented -E function. If an older version
|
|
* of communicator gives you a numeric error, we can see what
|
|
* really happened without doing hex math.
|
|
*
|
|
*/
|
|
|
|
void
|
|
print_error (int err)
|
|
{
|
|
PR_fprintf(errorFD, "Error %d: %s\n", err, JAR_get_error (err));
|
|
errorCount++;
|
|
give_help (err);
|
|
}
|
|
|
|
|
|
/*
|
|
* o u t _ o f _ m e m o r y
|
|
*
|
|
* Out of memory, exit Signtool.
|
|
*
|
|
*/
|
|
void
|
|
out_of_memory (void)
|
|
{
|
|
PR_fprintf(errorFD, "%s: out of memory\n", PROGRAM_NAME);
|
|
errorCount++;
|
|
exit (ERRX);
|
|
}
|
|
|
|
|
|
/*
|
|
* V e r i f y C e r t D i r
|
|
*
|
|
* Validate that the specified directory
|
|
* contains a certificate database
|
|
*
|
|
*/
|
|
void
|
|
VerifyCertDir(char *dir, char *keyName)
|
|
{
|
|
char fn [FNSIZE];
|
|
|
|
/* don't try verifying if we don't have a local directory */
|
|
if (strncmp(dir, "multiaccess:", sizeof("multiaccess:") - 1) == 0) {
|
|
return;
|
|
}
|
|
/* this function is truly evil. Tools and applications should not have
|
|
* any knowledge of actual cert databases! */
|
|
return;
|
|
|
|
/* This code is really broken because it makes underlying assumptions about
|
|
* how the NSS profile directory is laid out, but these names can change
|
|
* from release to release. */
|
|
sprintf (fn, "%s/cert8.db", dir);
|
|
|
|
if (PR_Access (fn, PR_ACCESS_EXISTS)) {
|
|
PR_fprintf(errorFD, "%s: No certificate database in \"%s\"\n",
|
|
PROGRAM_NAME, dir);
|
|
PR_fprintf(errorFD, "%s: Check the -d arguments that you gave\n",
|
|
PROGRAM_NAME);
|
|
errorCount++;
|
|
exit (ERRX);
|
|
}
|
|
|
|
if (verbosity >= 0) {
|
|
PR_fprintf(outputFD, "using certificate directory: %s\n", dir);
|
|
}
|
|
|
|
if (keyName == NULL)
|
|
return;
|
|
|
|
/* if the user gave the -k key argument, verify that
|
|
a key database already exists */
|
|
|
|
sprintf (fn, "%s/key3.db", dir);
|
|
|
|
if (PR_Access (fn, PR_ACCESS_EXISTS)) {
|
|
PR_fprintf(errorFD, "%s: No private key database in \"%s\"\n",
|
|
PROGRAM_NAME,
|
|
dir);
|
|
PR_fprintf(errorFD, "%s: Check the -d arguments that you gave\n",
|
|
PROGRAM_NAME);
|
|
errorCount++;
|
|
exit (ERRX);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* f o r e a c h
|
|
*
|
|
* A recursive function to loop through all names in
|
|
* the specified directory, as well as all subdirectories.
|
|
*
|
|
* FIX: Need to see if all platforms allow multiple
|
|
* opendir's to be called.
|
|
*
|
|
*/
|
|
|
|
int
|
|
foreach(char *dirname, char *prefix,
|
|
int (*fn)(char *relpath, char *basedir, char *reldir, char *filename,
|
|
void*arg),
|
|
PRBool recurse, PRBool includeDirs, void *arg)
|
|
{
|
|
char newdir [FNSIZE];
|
|
int retval = 0;
|
|
|
|
PRDir * dir;
|
|
PRDirEntry * entry;
|
|
|
|
strcpy (newdir, dirname);
|
|
if (*prefix) {
|
|
strcat (newdir, "/");
|
|
strcat (newdir, prefix);
|
|
}
|
|
|
|
dir = PR_OpenDir (newdir);
|
|
if (!dir)
|
|
return - 1;
|
|
|
|
for (entry = PR_ReadDir (dir, 0); entry; entry = PR_ReadDir (dir, 0)) {
|
|
if ( strcmp(entry->name, ".") == 0 ||
|
|
strcmp(entry->name, "..") == 0 ) {
|
|
/* no infinite recursion, please */
|
|
continue;
|
|
}
|
|
|
|
/* can't sign self */
|
|
if (!strcmp (entry->name, "META-INF"))
|
|
continue;
|
|
|
|
/* -x option */
|
|
if (PL_HashTableLookup(excludeDirs, entry->name))
|
|
continue;
|
|
|
|
strcpy (newdir, dirname);
|
|
if (*dirname)
|
|
strcat (newdir, "/");
|
|
|
|
if (*prefix) {
|
|
strcat (newdir, prefix);
|
|
strcat (newdir, "/");
|
|
}
|
|
strcat (newdir, entry->name);
|
|
|
|
if (!is_dir(newdir) || includeDirs) {
|
|
char newpath [FNSIZE];
|
|
|
|
strcpy (newpath, prefix);
|
|
if (*newpath)
|
|
strcat (newpath, "/");
|
|
strcat (newpath, entry->name);
|
|
|
|
if ( (*fn) (newpath, dirname, prefix, (char *) entry->name,
|
|
arg)) {
|
|
retval = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (is_dir (newdir)) {
|
|
if (recurse) {
|
|
char newprefix [FNSIZE];
|
|
|
|
strcpy (newprefix, prefix);
|
|
if (*newprefix) {
|
|
strcat (newprefix, "/");
|
|
}
|
|
strcat (newprefix, entry->name);
|
|
|
|
if (foreach (dirname, newprefix, fn, recurse,
|
|
includeDirs, arg)) {
|
|
retval = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
PR_CloseDir (dir);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
/*
|
|
* i s _ d i r
|
|
*
|
|
* Return 1 if file is a directory.
|
|
* Wonder if this runs on a mac, trust not.
|
|
*
|
|
*/
|
|
static int is_dir (char *filename)
|
|
{
|
|
PRFileInfo finfo;
|
|
|
|
if ( PR_GetFileInfo(filename, &finfo) != PR_SUCCESS ) {
|
|
printf("Unable to get information about %s\n", filename);
|
|
return 0;
|
|
}
|
|
|
|
return ( finfo.type == PR_FILE_DIRECTORY );
|
|
}
|
|
|
|
|
|
/***************************************************************
|
|
*
|
|
* s e c E r r o r S t r i n g
|
|
*
|
|
* Returns an error string corresponding to the given error code.
|
|
* Doesn't cover all errors; returns a default for many.
|
|
* Returned string is only valid until the next call of this function.
|
|
*/
|
|
const char *
|
|
secErrorString(long code)
|
|
{
|
|
static char errstring[80]; /* dynamically constructed error string */
|
|
char *c; /* the returned string */
|
|
|
|
switch (code) {
|
|
case SEC_ERROR_IO:
|
|
c = "io error";
|
|
break;
|
|
case SEC_ERROR_LIBRARY_FAILURE:
|
|
c = "security library failure";
|
|
break;
|
|
case SEC_ERROR_BAD_DATA:
|
|
c = "bad data";
|
|
break;
|
|
case SEC_ERROR_OUTPUT_LEN:
|
|
c = "output length";
|
|
break;
|
|
case SEC_ERROR_INPUT_LEN:
|
|
c = "input length";
|
|
break;
|
|
case SEC_ERROR_INVALID_ARGS:
|
|
c = "invalid args";
|
|
break;
|
|
case SEC_ERROR_EXPIRED_CERTIFICATE:
|
|
c = "expired certificate";
|
|
break;
|
|
case SEC_ERROR_REVOKED_CERTIFICATE:
|
|
c = "revoked certificate";
|
|
break;
|
|
case SEC_ERROR_INADEQUATE_KEY_USAGE:
|
|
c = "inadequate key usage";
|
|
break;
|
|
case SEC_ERROR_INADEQUATE_CERT_TYPE:
|
|
c = "inadequate certificate type";
|
|
break;
|
|
case SEC_ERROR_UNTRUSTED_CERT:
|
|
c = "untrusted cert";
|
|
break;
|
|
case SEC_ERROR_NO_KRL:
|
|
c = "no key revocation list";
|
|
break;
|
|
case SEC_ERROR_KRL_BAD_SIGNATURE:
|
|
c = "key revocation list: bad signature";
|
|
break;
|
|
case SEC_ERROR_KRL_EXPIRED:
|
|
c = "key revocation list expired";
|
|
break;
|
|
case SEC_ERROR_REVOKED_KEY:
|
|
c = "revoked key";
|
|
break;
|
|
case SEC_ERROR_CRL_BAD_SIGNATURE:
|
|
c = "certificate revocation list: bad signature";
|
|
break;
|
|
case SEC_ERROR_CRL_EXPIRED:
|
|
c = "certificate revocation list expired";
|
|
break;
|
|
case SEC_ERROR_CRL_NOT_YET_VALID:
|
|
c = "certificate revocation list not yet valid";
|
|
break;
|
|
case SEC_ERROR_UNKNOWN_ISSUER:
|
|
c = "unknown issuer";
|
|
break;
|
|
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
|
c = "expired issuer certificate";
|
|
break;
|
|
case SEC_ERROR_BAD_SIGNATURE:
|
|
c = "bad signature";
|
|
break;
|
|
case SEC_ERROR_BAD_KEY:
|
|
c = "bad key";
|
|
break;
|
|
case SEC_ERROR_NOT_FORTEZZA_ISSUER:
|
|
c = "not fortezza issuer";
|
|
break;
|
|
case SEC_ERROR_CA_CERT_INVALID:
|
|
c = "Certificate Authority certificate invalid";
|
|
break;
|
|
case SEC_ERROR_EXTENSION_NOT_FOUND:
|
|
c = "extension not found";
|
|
break;
|
|
case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
|
|
c = "certificate not in name space";
|
|
break;
|
|
case SEC_ERROR_UNTRUSTED_ISSUER:
|
|
c = "untrusted issuer";
|
|
break;
|
|
default:
|
|
sprintf(errstring, "security error %ld", code);
|
|
c = errstring;
|
|
break;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
|
|
/***************************************************************
|
|
*
|
|
* d i s p l a y V e r i f y L o g
|
|
*
|
|
* Prints the log of a cert verification.
|
|
*/
|
|
void
|
|
displayVerifyLog(CERTVerifyLog *log)
|
|
{
|
|
CERTVerifyLogNode * node;
|
|
CERTCertificate * cert;
|
|
char *name;
|
|
|
|
if ( !log || (log->count <= 0) ) {
|
|
return;
|
|
}
|
|
|
|
for (node = log->head; node != NULL; node = node->next) {
|
|
|
|
if ( !(cert = node->cert) ) {
|
|
continue;
|
|
}
|
|
|
|
/* Get a name for this cert */
|
|
if (cert->nickname != NULL) {
|
|
name = cert->nickname;
|
|
} else if (cert->emailAddr && cert->emailAddr[0]) {
|
|
name = cert->emailAddr;
|
|
} else {
|
|
name = cert->subjectName;
|
|
}
|
|
|
|
printf( "%s%s:\n", name,
|
|
(node->depth > 0) ? " [Certificate Authority]" : "");
|
|
|
|
printf("\t%s\n", secErrorString(node->error));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* J a r L i s t M o d u l e s
|
|
*
|
|
* Print a list of the PKCS11 modules that are
|
|
* available. This is useful for smartcard people to
|
|
* make sure they have the drivers loaded.
|
|
*
|
|
*/
|
|
void
|
|
JarListModules(void)
|
|
{
|
|
int i;
|
|
int count = 0;
|
|
|
|
SECMODModuleList * modules = NULL;
|
|
static SECMODListLock *moduleLock = NULL;
|
|
|
|
SECMODModuleList * mlp;
|
|
|
|
if ((moduleLock = SECMOD_GetDefaultModuleListLock()) == NULL) {
|
|
/* this is the wrong text */
|
|
PR_fprintf(errorFD, "%s: unable to acquire lock on module list\n",
|
|
PROGRAM_NAME);
|
|
errorCount++;
|
|
exit (ERRX);
|
|
}
|
|
|
|
SECMOD_GetReadLock (moduleLock);
|
|
|
|
modules = SECMOD_GetDefaultModuleList();
|
|
|
|
if (modules == NULL) {
|
|
SECMOD_ReleaseReadLock (moduleLock);
|
|
PR_fprintf(errorFD, "%s: Can't get module list\n", PROGRAM_NAME);
|
|
errorCount++;
|
|
exit (ERRX);
|
|
}
|
|
|
|
PR_fprintf(outputFD, "\nListing of PKCS11 modules\n");
|
|
PR_fprintf(outputFD, "-----------------------------------------------\n");
|
|
|
|
for (mlp = modules; mlp != NULL; mlp = mlp->next) {
|
|
count++;
|
|
PR_fprintf(outputFD, "%3d. %s\n", count, mlp->module->commonName);
|
|
|
|
if (mlp->module->internal)
|
|
PR_fprintf(outputFD, " (this module is internally loaded)\n");
|
|
else
|
|
PR_fprintf(outputFD, " (this is an external module)\n");
|
|
|
|
if (mlp->module->dllName)
|
|
PR_fprintf(outputFD, " DLL name: %s\n",
|
|
mlp->module->dllName);
|
|
|
|
if (mlp->module->slotCount == 0)
|
|
PR_fprintf(outputFD, " slots: There are no slots attached to this module\n");
|
|
else
|
|
PR_fprintf(outputFD, " slots: %d slots attached\n",
|
|
mlp->module->slotCount);
|
|
|
|
if (mlp->module->loaded == 0)
|
|
PR_fprintf(outputFD, " status: Not loaded\n");
|
|
else
|
|
PR_fprintf(outputFD, " status: loaded\n");
|
|
|
|
for (i = 0; i < mlp->module->slotCount; i++) {
|
|
PK11SlotInfo * slot = mlp->module->slots[i];
|
|
|
|
PR_fprintf(outputFD, "\n");
|
|
PR_fprintf(outputFD, " slot: %s\n", PK11_GetSlotName(slot));
|
|
PR_fprintf(outputFD, " token: %s\n", PK11_GetTokenName(slot));
|
|
}
|
|
}
|
|
|
|
PR_fprintf(outputFD, "-----------------------------------------------\n");
|
|
|
|
if (count == 0)
|
|
PR_fprintf(outputFD,
|
|
"Warning: no modules were found (should have at least one)\n");
|
|
|
|
SECMOD_ReleaseReadLock (moduleLock);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* c h o p
|
|
*
|
|
* Eliminates leading and trailing whitespace. Returns a pointer to the
|
|
* beginning of non-whitespace, or an empty string if it's all whitespace.
|
|
*/
|
|
char*
|
|
chop(char *str)
|
|
{
|
|
char *start, *end;
|
|
|
|
if (str) {
|
|
start = str;
|
|
|
|
/* Nip leading whitespace */
|
|
while (isspace(*start)) {
|
|
start++;
|
|
}
|
|
|
|
/* Nip trailing whitespace */
|
|
if (*start) {
|
|
end = start + strlen(start) - 1;
|
|
while (isspace(*end) && end > start) {
|
|
end--;
|
|
}
|
|
*(end + 1) = '\0';
|
|
}
|
|
|
|
return start;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* F a t a l E r r o r
|
|
*
|
|
* Outputs an error message and bails out of the program.
|
|
*/
|
|
void
|
|
FatalError(char *msg)
|
|
{
|
|
if (!msg)
|
|
msg = "";
|
|
|
|
PR_fprintf(errorFD, "FATAL ERROR: %s\n", msg);
|
|
errorCount++;
|
|
exit(ERRX);
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* I n i t C r y p t o
|
|
*/
|
|
int
|
|
InitCrypto(char *cert_dir, PRBool readOnly)
|
|
{
|
|
SECStatus rv;
|
|
static int prior = 0;
|
|
PK11SlotInfo * slotinfo;
|
|
|
|
if (prior == 0) {
|
|
/* some functions such as OpenKeyDB expect this path to be
|
|
* implicitly set prior to calling */
|
|
if (readOnly) {
|
|
rv = NSS_Init(cert_dir);
|
|
} else {
|
|
rv = NSS_InitReadWrite(cert_dir);
|
|
}
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintPRandOSError(PROGRAM_NAME);
|
|
exit(-1);
|
|
}
|
|
|
|
SECU_ConfigDirectory (cert_dir);
|
|
|
|
/* Been there done that */
|
|
prior++;
|
|
|
|
PK11_SetPasswordFunc(SECU_GetModulePassword);
|
|
|
|
/* Must login to FIPS before you do anything else */
|
|
if (PK11_IsFIPS()) {
|
|
slotinfo = PK11_GetInternalSlot();
|
|
if (!slotinfo) {
|
|
fprintf(stderr, "%s: Unable to get PKCS #11 Internal Slot."
|
|
"\n", PROGRAM_NAME);
|
|
return - 1;
|
|
}
|
|
if (PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/,
|
|
&pwdata) != SECSuccess) {
|
|
fprintf(stderr, "%s: Unable to authenticate to %s.\n",
|
|
PROGRAM_NAME, PK11_GetSlotName(slotinfo));
|
|
PK11_FreeSlot(slotinfo);
|
|
return - 1;
|
|
}
|
|
PK11_FreeSlot(slotinfo);
|
|
}
|
|
|
|
/* Make sure there is a password set on the internal key slot */
|
|
slotinfo = PK11_GetInternalKeySlot();
|
|
if (!slotinfo) {
|
|
fprintf(stderr, "%s: Unable to get PKCS #11 Internal Key Slot."
|
|
"\n", PROGRAM_NAME);
|
|
return - 1;
|
|
}
|
|
if (PK11_NeedUserInit(slotinfo)) {
|
|
PR_fprintf(errorFD,
|
|
"\nWARNING: No password set on internal key database. Most operations will fail."
|
|
"\nYou must create a password.\n");
|
|
warningCount++;
|
|
}
|
|
|
|
/* Make sure we can authenticate to the key slot in FIPS mode */
|
|
if (PK11_IsFIPS()) {
|
|
if (PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/,
|
|
&pwdata) != SECSuccess) {
|
|
fprintf(stderr, "%s: Unable to authenticate to %s.\n",
|
|
PROGRAM_NAME, PK11_GetSlotName(slotinfo));
|
|
PK11_FreeSlot(slotinfo);
|
|
return - 1;
|
|
}
|
|
}
|
|
PK11_FreeSlot(slotinfo);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Windows foolishness is now in the secutil lib */
|
|
|
|
/*****************************************************************
|
|
* g e t _ d e f a u l t _ c e r t _ d i r
|
|
*
|
|
* Attempt to locate a certificate directory.
|
|
* Failing that, complain that the user needs to
|
|
* use the -d(irectory) parameter.
|
|
*
|
|
*/
|
|
char *get_default_cert_dir (void)
|
|
{
|
|
char *home;
|
|
|
|
char *cd = NULL;
|
|
static char db [FNSIZE];
|
|
|
|
#ifdef XP_UNIX
|
|
home = getenv ("HOME");
|
|
|
|
if (home && *home) {
|
|
sprintf (db, "%s/.netscape", home);
|
|
cd = db;
|
|
}
|
|
#endif
|
|
|
|
#ifdef XP_PC
|
|
FILE * fp;
|
|
|
|
/* first check the environment override */
|
|
|
|
home = getenv ("JAR_HOME");
|
|
|
|
if (home && *home) {
|
|
sprintf (db, "%s/cert7.db", home);
|
|
|
|
if ((fp = fopen (db, "r")) != NULL) {
|
|
fclose (fp);
|
|
cd = home;
|
|
}
|
|
}
|
|
|
|
/* try the old navigator directory */
|
|
|
|
if (cd == NULL) {
|
|
home = "c:/Program Files/Netscape/Navigator";
|
|
|
|
sprintf (db, "%s/cert7.db", home);
|
|
|
|
if ((fp = fopen (db, "r")) != NULL) {
|
|
fclose (fp);
|
|
cd = home;
|
|
}
|
|
}
|
|
|
|
/* Try the current directory, I wonder if this
|
|
is really a good idea. Remember, Windows only.. */
|
|
|
|
if (cd == NULL) {
|
|
home = ".";
|
|
|
|
sprintf (db, "%s/cert7.db", home);
|
|
|
|
if ((fp = fopen (db, "r")) != NULL) {
|
|
fclose (fp);
|
|
cd = home;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!cd) {
|
|
PR_fprintf(errorFD,
|
|
"You must specify the location of your certificate directory\n");
|
|
PR_fprintf(errorFD,
|
|
"with the -d option. Example: -d ~/.netscape in many cases with Unix.\n");
|
|
errorCount++;
|
|
exit (ERRX);
|
|
}
|
|
|
|
return cd;
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* g i v e _ h e l p
|
|
*/
|
|
void give_help (int status)
|
|
{
|
|
if (status == SEC_ERROR_UNKNOWN_ISSUER) {
|
|
PR_fprintf(errorFD,
|
|
"The Certificate Authority (CA) for this certificate\n");
|
|
PR_fprintf(errorFD,
|
|
"does not appear to be in your database. You should contact\n");
|
|
PR_fprintf(errorFD,
|
|
"the organization which issued this certificate to obtain\n");
|
|
PR_fprintf(errorFD, "a copy of its CA Certificate.\n");
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
*
|
|
* p r _ f g e t s
|
|
*
|
|
* fgets implemented with NSPR.
|
|
*/
|
|
char*
|
|
pr_fgets(char *buf, int size, PRFileDesc *file)
|
|
{
|
|
int i;
|
|
int status;
|
|
char c;
|
|
|
|
i = 0;
|
|
while (i < size - 1) {
|
|
status = PR_Read(file, &c, 1);
|
|
if (status == -1) {
|
|
return NULL;
|
|
} else if (status == 0) {
|
|
if (i == 0) {
|
|
return NULL;
|
|
}
|
|
break;
|
|
}
|
|
buf[i++] = c;
|
|
if (c == '\n') {
|
|
break;
|
|
}
|
|
}
|
|
buf[i] = '\0';
|
|
|
|
return buf;
|
|
}
|
|
|
|
|