Using the JAR Installation Manager to Install a PKCS #11 Cryptographic Module

[Contents]


Using the JAR Installation Manager to Install a PKCS #11 Cryptographic Module

This document describes how to prepare a PKCS #11 cryptographic module so that users can download it from the Internet, verify its integrity, and install it, all with just a few mouse clicks. This document should be used with Implementing PKCS #11 for the Netscape Security Library.

Introduction

The packaged module that this document describes how to prepare is a signed JAR file. This JAR file contains a dynamically linked library that implements the security module and an installer script (
.js) that installs, registers, and configures the module.

SmartUpdate allows users to download a JAR file that has been digitally signed by the software vendor. SmartUpdate then decompresses the JAR file, verifies the digital signature, and verifies the integrity of the archived files. If  this verification process is successful, SmartUpdate runs the installer script. The installer script instructs SmartUpdate to move the downloaded cryptographic module library to a specified location, registers the module with Navigator, and configures it.

This document does not describe how SmartUpdate works. For information about SmartUpdate, see Using JAR Installation Manager for SmartUpdate.

How to Create a Cryptographic Module JAR

  1. Obtain a copy of PKCS #11: Cryptographic Token Interface Standard, version 2.0, published by RSA Laboratories, Redwood City, California.
  2. Obtain a copy of Implementing PKCS #11 for the Netscape Security Library.
  3. Implement a PKCS #11 module according to PKCS #11 standards.
  4. Write an installer script that registers the module with Navigator.
  5. Use the Netscape Signing Tool (also known as "zigbert") to package the module and the script in a signed JAR file.
  6. Publish the JAR file on the web and inform users that they can use it to install your module.

Sample Installer Script

The following installer script performs these actions:
  1. Start SmartUpdate and declare the version and the name of the module to be installed.
  2. Based on the platform on which Navigator is running, the script decides the name of the module to be extracted and its destination.
  3. Extract a module called dummy from the JAR file and copy it to its destination.
  4. Register the installed module by calling pkcs11.addmodule() method with information about the capabilities of the module.
  5. Check whether pkcs11.addmodule() has been successful and display appropriate messages.
Since the script can figure out the module name at time of installation, it is possible for vendors to package modules targeted for different platforms inside the same JAR file. As a result, a single JAR file may contain a common install script and various modules for HP-UX, IRIX, MacOS, SunOS, Window 3.1, and so on. When users download a module, they don't need to figure out which JAR file is appropriate for their computers, because there is only one JAR file for all platforms.  Of course, the JAR file can grow very large, which may not be desirable for modem users.

See Mechanism Flag Definitions for guidance on which flags to set. Most tokens shouldn't set any of these flags.

////////////////////////////////////////////////////////////////////////////////////////
// Crypto Mechanism Flags
PKCS11_MECH_RSA_FLAG           =  0x1<<0;
PKCS11_MECH_DSA_FLAG           =  0x1<<1;
PKCS11_MECH_RC2_FLAG           =  0x1<<2;
PKCS11_MECH_RC4_FLAG           =  0x1<<3;
PKCS11_MECH_DES_FLAG           =  0x1<<4;
PKCS11_MECH_DH_FLAG            =  0x1<<5; //Diffie-Hellman
PKCS11_MECH_SKIPJACK_FLAG      =  0x1<<6; //SKIPJACK algorithm as in Fortezza cards
PKCS11_MECH_RC5_FLAG           =  0x1<<7;
PKCS11_MECH_SHA1_FLAG          =  0x1<<8;
PKCS11_MECH_MD5_FLAG           =  0x1<<9;
PKCS11_MECH_MD2_FLAG           =  0x1<<10;
PKCS11_MECH_RANDOM_FLAG        =  0x1<<27; //Random number generator
PKCS11_PUB_READABLE_CERT_FLAG  =  0x1<<28; //Stored certs can be read off the token w/o logging in
PKCS11_DISABLE_FLAG            =  0x1<<30; //tell Navigator to disable this slot by default

// Important:
// 0x1<<11, 0x1<<12, ... , 0x1<<26, 0x1<<29, and 0x1<<31 are reserved
// for internal use in Navigator.
// Therefore, these bits should always be set to 0; otherwise,
// Navigator might exhibit unpredictable behavior.

// These flags indicate which mechanisms should be turned on by
var pkcs11MechanismFlags = PKCS11_MECH_RANDOM_FLAG;
 
////////////////////////////////////////////////////////////////////////////////////////
// Ciphers that support SSL or S/MIME
PKCS11_CIPHER_FORTEZZA_FLAG    = 0x1<<0;

// Important:
// 0x1<<1, 0x1<<2, ... , 0x1<<31 are reserved
// for internal use in Navigator.
// Therefore, these bits should ALWAYS be set to 0; otherwise,
// Navigator might exhibit unpredictable behavior.

// These flags indicate which SSL ciphers are supported
var pkcs11CipherFlags = PKCS11_CIPHER_FORTEZZA_FLAG;
 
////////////////////////////////////////////////////////////////////////////////////////
// Return values of pkcs11.addmodule() & pkcs11.delmodule()
// success codes
JS_OK_ADD_MODULE                 = 3; // Successfully added a module
JS_OK_DEL_EXTERNAL_MODULE        = 2; // Successfully deleted ext. module
JS_OK_DEL_INTERNAL_MODULE        = 1; // Successfully deleted int. module

// failure codes
JS_ERR_OTHER                     = -1; // Other errors than the followings
JS_ERR_USER_CANCEL_ACTION        = -2; // User abort an action
JS_ERR_INCORRECT_NUM_OF_ARGUMENTS= -3; // Calling a method w/ incorrect # of arguments
JS_ERR_DEL_MODULE                = -4; // Error deleting a module
JS_ERR_ADD_MODULE                = -5; // Error adding a module
JS_ERR_BAD_MODULE_NAME           = -6; // The module name is invalid
JS_ERR_BAD_DLL_NAME              = -7; // The DLL name is bad
JS_ERR_BAD_MECHANISM_FLAGS       = -8; // The mechanism flags are invalid
JS_ERR_BAD_CIPHER_ENABLE_FLAGS   = -9; // The SSL, S/MIME cipher flags are invalid
JS_ERR_ADD_MODULE_DULICATE       =-10; // Module with the same name already installed

////////////////////////////////////////////////////////////////////////////////////////
// Find out which file is to be installed depending on the platform

// pathname seperator is platform specific
var sep = "/";
var vendor = "netscape";
var moduleName = "not_supported";
var plat = navigator.platform;

// destination of module
var dir = "pkcs11/" + vendor + "/" + plat + "/";
if (plat == "Win16") {
    dir = "pkcs11/";
}

bAbort = false;
if (plat == "Win32") {
    moduleName = "dummy32.dll";
    sep = "\\";
} else if (plat == "Win16") {
    moduleName = "dummy16.dll";
    sep = "\\";
} else if (plat == "MacPPC") {
    moduleName = "dummyLib";
    sep = ":";
} else if (plat == "AIX4.1") {
    moduleName = "dummy.a";
} else if (plat == "SunOS4.1.3_U1") {
    moduleName = "dummy.so.1.0";
} else if ((plat == "SunOS5.4") || (plat == "SunOS5.5.1")){
    moduleName = "dummy.so";
} else if ((plat == "HP-UXA.09") || (plat == "HP-UXB.10")){
    moduleName = "dummy.sl";
} else {
    window.alert("Sorry, platform "+plat+" is not supported.");
    bAbort = true;
}

////////////////////////////////////////////////////////////////////////////////////////
// Installation begins...
if (!bAbort) {
if (confirm("This script will install a cryptographic module. \nIt may over-write older files having the same name. \nDo you want to continue?")) {
 // Step 1. Create a version object and a software update object.
 vi = new netscape.softupdate.VersionInfo(1, 1, 0, 0);
 su = new netscape.softupdate.SoftwareUpdate(this, "Dummy Card PKCS#11 Module");
                 // "Dummy ... Module" is the logical name of the bundle

 ////////////////////////////////////////
 // Step 2. Start the install process.
 bAbort = false;
 err = su.StartInstall("NSDummy", // NSDummy is the component folder (logical).
                       vi,
                       netscape.softupdate.SoftwareUpdate.FULL_INSTALL);
 
 bAbort = (err!=0);

 if (err == 0) {
     ////////////////////////////////////////
    // Step 3. Find out the physical location of the Program dir.
    Folder = su.GetFolder("Program");

     ////////////////////////////////////////
    // Step 4. Install the files. Unpack them and list where they go.

    err = su.AddSubcomponent("DummyLibrary_"+plat, //component name (logical)
                                    vi, // version info
                                    moduleName, // source file in JAR (physical)
                                    Folder, // target folder (physical)
                                    dir + moduleName, // target path & filename (physical)
                                    true); // forces update
    if (err != 0) {
        if (err == -200) {
             errmsg = "Bad Package Name.";
        } else if (err == -201) {
             errmsg = "Unexpected error.";
        } else if (err == -203) {
             errmsg = "Installation script was signed by more than one certificate.";
        } else if (err == -204) {
             errmsg = "Installation script was not signed."
        } else if (err == -205) {
             errmsg = "The file to be installed is not signed."
        } else if (err == -206) {
             errmsg = "The file to be installed is not present, or signed with a different certificate than the one used to sign the install script."
        } else if (err == -207) {
             errmsg = "JAR archive has not been opened."
        } else if (err == -208) {
             errmsg = "Bad arguments to AddSubcomponent( )."
        } else if (err == -209) {
             errmsg = "Illegal relative path."
        } else if (err == -210) {
             errmsg = "User cancelled installation."
        } else if (err == -211) {
             errmsg = "A problem occurred with the StartInstall( )."
        } else {
             errmsg = "Unknown error";
        }
        window.alert("Error adding sub-component: "+"("+err+")"+errmsg);

        bAbort = true;
    }
 }

 ////////////////////////////////////////
 // Step 5. Unless there was a problem, move files to final location
 // and update the Client Version Registry.
 if (bAbort) {
    su.AbortInstall();
 } else {
    err = su.FinalizeInstall();

    if (err != 0) {

        if (err == -900) {
             errmsg = "Restart the computer, and install again.";
        } else if (err == -201) {
             errmsg = "Unexpected error.";
        } else if (err == -202) {
             errmsg = "Access denied. Make sure you have the permissions to write to the disk.";
        } else if (err == -203) {
             errmsg = "Installation script was signed by more than one certificate.";
        } else if (err == -204) {
             errmsg = "Installation script was not signed."
        } else if (err == -205) {
             errmsg = "The file to be installed is not signed."
        } else if (err == -206) {
             errmsg = "The file to be installed is not present, or it is signed with a different certificate than the one used to sign the installation script."
        } else if (err == -207) {
             errmsg = "JAR archive has not been opened."
        } else if (err == -208) {
             errmsg = "Bad arguments to AddSubcomponent( )."
        } else if (err == -209) {
             errmsg = "Illegal relative path( )."
        } else if (err == -210) {
             errmsg = "User cancelled installation."
        } else if (err == -211) {
             errmsg = "A problem occurred with the StartInstall( )."
        } else {
             errmsg = "\nIf you already have Dummy module installed, try deleting it first.";
        }
        window.alert("Error Finalizing Install: "+"("+err+")"+errmsg);

    } else {

        // Platform specific full path
        if (plat=="Win16") {
            fullpath = Folder +  "pkcs11" + sep + moduleName;
        } else {
            fullpath = Folder +  "pkcs11" + sep + vendor + sep + plat + sep + moduleName;
        }

         ////////////////////////////////////////
        // Step 6: Call pkcs11.addmodule() to register the newly downloaded module
        moduleCommonName = "Netscape Dummy Module " + plat;
        result = pkcs11.addmodule(moduleCommonName,
                              fullpath,
                              pkcs11MechanismFlags,
                              pkcs11CipherFlags);
       if (result == -10) {
           window.alert("New module was copied to destination, \nbut setup failed because a module "
                   +"having the same name has been installed. \nTry deleting the module "
                   + moduleCommonName +" first.")
       } else if (result < 0) {
           window.alert("New module was copied to destination, but setup failed.  Error code: " + result);
       }
    }
 }
}
}
 

Programmer's Reference

This section documents two functions:

addmodule

Adds a PKCS#11 cryptographic module to the cryptographic module database and notifies Communicator which cryptographic mechanisms should be turned on by default and which SSL or S/MIME ciphers are supported. For security reasons, it displays a dialog box to ask the user to confirm this action.It might display other dialog boxes if necessary.

Method of

pkcs11

Syntax

int pkcs11.addmodule(string ModuleName,
                   string LibraryFullPath,
                   int CryptoMechanismFlags,
                   int CipherFlags);

Parameters

ModuleName Name of the module.
LibraryFullPath The filename of the library prepended with its full path.
CryptoMechanismFlags A bit vector indicating all cryptographic mechanisms should be turned on by default (see below).
CipherFlags A bit vector indicating all SSL or S/MIME cipher functions supported by the module (see below).
NOTE: See Mechanism Flag Definitions for which flags to set. Most tokens shouldn't set any of these flags.

Cryptographic Mechanism Flags

PKCS11_MECH_RSA_FLAG           =  0x1<<0;
PKCS11_MECH_DSA_FLAG           =  0x1<<1;
PKCS11_MECH_RC2_FLAG           =  0x1<<2;
PKCS11_MECH_RC4_FLAG           =  0x1<<3;
PKCS11_MECH_DES_FLAG           =  0x1<<4;
PKCS11_MECH_DH_FLAG            =  0x1<<5; //Diffie-Hellman
PKCS11_MECH_SKIPJACK_FLAG      =  0x1<<6; //SKIPJACK algorithm as in Fortezza cards
PKCS11_MECH_RC5_FLAG           =  0x1<<7;
PKCS11_MECH_SHA1_FLAG          =  0x1<<8;
PKCS11_MECH_MD5_FLAG           =  0x1<<9;
PKCS11_MECH_MD2_FLAG           =  0x1<<10;
PKCS11_MECH_RANDOM_FLAG        =  0x1<<27; //Random number generator
PKCS11_PUB_READABLE_CERT_FLAG  =  0x1<<28; //Stored certs can be read off the token w/o logging in
PKCS11_DISABLE_FLAG            =  0x1<<30; //tell Navigator to disable this slot by default

Supported SSL or S/MIME Ciphers

PKCS11_CIPHER_FORTEZZA_FLAG    = 0x1<<0;

Important for CryptoMechanismFlags

0x1<<11, 0x1<<12, ... , 0x1<<26, 0x1<<29, and 0x1<<31 are reserved for internal use in Navigator.
Therefore, these bits should always be set to 0; otherwise, Navigator might exhibit unpredictable behavior.

Important for CipherFlags

0x1<<1, 0x1<<2, ... , 0x1<<31 are reserved for internal use in Navigator.
Therefore, these bits should always be set to 0; otherwise, Navigator might exhibit unpredictable behavior.

Example of CryptoMechanismFlags and CipherFlags

pkcs11MechanismFlags = PKCS11_MECH_DSA_FLAG | PKCS11_MECH_SKIPJACK_FLAG | PKCS11_MECH_RANDOM_FLAG;
pkcs11CipherFlags = PKCS11_CIPHER_FORTEZZA_FLAG;

Return Values

// Return values of pkcs11.addmod()
// success codes
JS_OK_ADD_MODULE                 = 3 // Successfully added a module

// failure codes
JS_ERR_OTHER                     = -1 // Errors other than the following
JS_ERR_USER_CANCEL_ACTION        = -2 // User abort an action
JS_ERR_INCORRECT_NUM_OF_ARGUMENTS= -3 // Calling a method w/ incorrect # of arguments
JS_ERR_ADD_MODULE                = -5 // Error adding a module
JS_ERR_BAD_MODULE_NAME           = -6 // The module name is invalid
JS_ERR_BAD_DLL_NAME              = -7 // The DLL name is bad
JS_ERR_BAD_MECHANISM_FLAGS       = -8 // The mechanism flags are invalid
JS_ERR_BAD_CIPHER_ENABLE_FLAGS   = -9 // The SSL, S/MIME cipher flags are invalid
JS_ERR_ADD_MODULE_DUPLICATE      =-10 // The module being installed has the same name as
                                      // one of the modules that has already been installed

delmodule

Deletes a PKCS #11 cryptographic module from the module database, but does not physically remove the file. For security reasons, it will display a dialog box to ask the user to confirm this action. It may display other dialog boxes if necessary.

Method of

pkcs11

Syntax

int pkcs11.delmodule(string ModuleName);

Parameter

ModuleName Name of the module

Return Values

// Return values of pkcs11.addmod() & pkcs11.delmod()
// success codes
JS_OK_DEL_EXTERNAL_MODULE        = 2 // Successfully deleted ext. module
JS_OK_DEL_INTERNAL_MODULE        = 1 // Successfully deleted int. module

// failure codes
JS_ERR_OTHER                     = -1 // Other errors than the followings
JS_ERR_USER_CANCEL_ACTION        = -2 // User abort an action
JS_ERR_INCORRECT_NUM_OF_ARGUMENTS= -3 // Calling a method w/ incorrect # of arguments
JS_ERR_DEL_MODULE                = -4 // Error deleting a module
JS_ERR_BAD_MODULE_NAME           = -6 // The module name is invalid

Mechanism Flag Definitions

In general, most tokens should not set any of the cipher flags. Setting these flags means you want your token to supply the default implementation for these functions. Normally Communicator uses its own internal module to supply these functions. These flags override that preference. If you choose to implement these flags, your module must supply the following additional functions for each flag:

PKCS11_MECH_FLAG: must support CKM_RSA_PKCS and CKM_RSA_X_509 and the following functions: C_WRAPKEY, C_ENCRYPT, C_SIGN, C_DECRYPT, C_UNWRAPKEY, C_VERIFYRECOVER, C_VERIFY, C_GENERATEKEYPAIR (2048, 1024, 512) size

PKCS11_MECH_DSA_FLAG: must support CKM_DSA and the following functions: C_SIGN, C_VERIFY, C_GENERATEKEYPAIR

PKCS11_MECH_RC2_FLAG: must support CKM_RC2_CBC and CKM_RC2_ECB and the following functions: C_GENERATEKEY, C_ENCRYPT, C_DECRYPT, C_WRAPKEY, C_UNWRAPKEY

PKCS11_MECH_RC4_FLAG: must support CKM_RC4_CBC and CKM_RC4_ECB and the following functions: C_GENERATEKEY, C_ENCRYPT, C_DECRYPT, C_WRAPKEY, C_UNWRAPKEY

PKCS11_MECH_DES_FLAG: must support CKM_CPMF_CBC, CKM_DES_CBC, CKM_DES3_CBC, CKM_CPMF_ECB, CKM_DES_ECB, CKM_DES3_ECB and the following functions: C_GENERATEKEY, C_ENCRYPT, C_DECRYPT, C_WRAPKEY, C_UNWRAPKEY

PKCS11_MECH_DH_FLAG: must support CKM_DH_PKCS_DERIVE and CKM_DH_KEY_PAIR_GEN and the following functions: C_DERIVEKEY, C_GENERATEKEYPAIR

PKCS11_SKIPJACK_FLAG: CKM_SKIPJACK_CBC64 and the following functions: C_GENERATEKEY, C_ENCRYPT, C_DECRYPT, C_WRAPKEY, C_UNWRAPKEY

PKCS11_MECH_MD5_FLAG: Hashing must be able to function without authentication.

PKCS11_MECH_SHA1_FLAG: Hashing must be able to function without authentication.

PKCS11_MECH_MD2_FLAG: Hashing must be able to function without authentication.

PKCS11_RANDOM_FLAG: Use token's Random Number Generator.
Warning: Must be able to use without authentication. Many hardware random number generators are not as secure as the Netscape internal one. Do not select this value unless you can show that your random number generator is secure. Even so, it's highly discouraged.

PKCS11_PUB_READABLE_CERT_FLAG: This is the only flag most smart tokens should turn on. You can turn this flag on if:
1) the certs on your token can be read without authentication and,
2) the public key on your token can be found by ID, MODULUS, or VALUE and all your private keys have the associated public key.
Turning this flag on will illuminate a large number of password prompts for your token when looking up certs in Communicator.
 

Last Updated: 12/08/97

Any sample code included above is provided for your use on an "AS IS" basis, under the Netscape License Agreement - Terms of Use