760 lines · 26.1 KB · Java
RawDownload
/* * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.pkcs11; import java.io.*;import java.util.*; import java.security.*;import java.security.KeyStore.*;import java.security.cert.X509Certificate; import sun.security.pkcs11.wrapper.*;import static sun.security.pkcs11.wrapper.PKCS11Constants.*; /** * The Secmod class defines the interface to the native NSS * library and the configuration information it stores in its * secmod.db file. * * <p>Example code: * <pre> *   Secmod secmod = Secmod.getInstance(); *   if (secmod.isInitialized() == false) { *       secmod.initialize("/home/myself/.mozilla", "/usr/sfw/lib/mozilla"); *   } * *   Provider p = secmod.getModule(ModuleType.KEYSTORE).getProvider(); *   KeyStore ks = KeyStore.getInstance("PKCS11", p); *   ks.load(null, password); * </pre> * * @since   1.6 * @author  Andreas Sterbenz */public final class Secmod {     private final static boolean DEBUG = false;     private final static Secmod INSTANCE;     static {        sun.security.pkcs11.wrapper.PKCS11.loadNative();        INSTANCE = new Secmod();    }     private final static String NSS_LIB_NAME = "nss3";     private final static String SOFTTOKEN_LIB_NAME = "softokn3";     private final static String TRUST_LIB_NAME = "nssckbi";     // handle to be passed to the native code, 0 means not initialized    private long nssHandle;     // whether this is a supported version of NSS    private boolean supported;     // list of the modules    private List<Module> modules;     private String configDir;     private String nssLibDir;     private Secmod() {        // empty    }     /**     * Return the singleton Secmod instance.     */    public static Secmod getInstance() {        return INSTANCE;    }     private boolean isLoaded() {        if (nssHandle == 0) {            nssHandle = nssGetLibraryHandle(System.mapLibraryName(NSS_LIB_NAME));            if (nssHandle != 0) {                fetchVersions();            }        }        return (nssHandle != 0);    }     private void fetchVersions() {        supported = nssVersionCheck(nssHandle, "3.7");    }     /**     * Test whether this Secmod has been initialized. Returns true     * if NSS has been initialized using either the initialize() method     * or by directly calling the native NSS APIs. The latter may be     * the case if the current process contains components that use     * NSS directly.     *     * @throws IOException if an incompatible version of NSS     *   has been loaded     */    public synchronized boolean isInitialized() throws IOException {        // NSS does not allow us to check if it is initialized already        // assume that if it is loaded it is also initialized        if (isLoaded() == false) {            return false;        }        if (supported == false) {            throw new IOException                ("An incompatible version of NSS is already loaded, "                + "3.7 or later required");        }        return true;    }     String getConfigDir() {        return configDir;    }     String getLibDir() {        return nssLibDir;    }     /**     * Initialize this Secmod.     *     * @param configDir the directory containing the NSS configuration     *   files such as secmod.db     * @param nssLibDir the directory containing the NSS libraries     *   (libnss3.so or nss3.dll) or null if the library is on     *   the system default shared library path     *     * @throws IOException if NSS has already been initialized,     *   the specified directories are invalid, or initialization     *   fails for any other reason     */    public void initialize(String configDir, String nssLibDir)            throws IOException {        initialize(DbMode.READ_WRITE, configDir, nssLibDir);    }     public synchronized void initialize(DbMode dbMode, String configDir, String nssLibDir)            throws IOException {        if (isInitialized()) {            throw new IOException("NSS is already initialized");        }         if (dbMode == null) {            throw new NullPointerException();        }        if ((dbMode != DbMode.NO_DB) && (configDir == null)) {            throw new NullPointerException();        }        String platformLibName = System.mapLibraryName("nss3");        String platformPath;        if (nssLibDir == null) {            platformPath = platformLibName;        } else {            File base = new File(nssLibDir);            if (base.isDirectory() == false) {                throw new IOException("nssLibDir must be a directory:" + nssLibDir);            }            File platformFile = new File(base, platformLibName);            if (platformFile.isFile() == false) {                throw new FileNotFoundException(platformFile.getPath());            }            platformPath = platformFile.getPath();        }         if (configDir != null) {            File configBase = new File(configDir);            if (configBase.isDirectory() == false ) {                throw new IOException("configDir must be a directory: " + configDir);            }            File secmodFile = new File(configBase, "secmod.db");            if (secmodFile.isFile() == false) {                throw new FileNotFoundException(secmodFile.getPath());            }        }         if (DEBUG) System.out.println("lib: " + platformPath);        nssHandle = nssLoadLibrary(platformPath);        if (DEBUG) System.out.println("handle: " + nssHandle);        fetchVersions();        if (supported == false) {            throw new IOException                ("The specified version of NSS is incompatible, "                + "3.7 or later required");        }         if (DEBUG) System.out.println("dir: " + configDir);        boolean initok = nssInit(dbMode.functionName, nssHandle, configDir);        if (DEBUG) System.out.println("init: " + initok);        if (initok == false) {            throw new IOException("NSS initialization failed");        }         this.configDir = configDir;        this.nssLibDir = nssLibDir;    }     /**     * Return an immutable list of all available modules.     *     * @throws IllegalStateException if this Secmod is misconfigured     *   or not initialized     */    public synchronized List<Module> getModules() {        try {            if (isInitialized() == false) {                throw new IllegalStateException("NSS not initialized");            }        } catch (IOException e) {            // IOException if misconfigured            throw new IllegalStateException(e);        }        if (modules == null) {            List<Module> modules = (List<Module>)nssGetModuleList(nssHandle,                nssLibDir);            this.modules = Collections.unmodifiableList(modules);        }        return modules;    }     private static byte[] getDigest(X509Certificate cert, String algorithm) {        try {            MessageDigest md = MessageDigest.getInstance(algorithm);            return md.digest(cert.getEncoded());        } catch (GeneralSecurityException e) {            throw new ProviderException(e);        }    }     boolean isTrusted(X509Certificate cert, TrustType trustType) {        Bytes bytes = new Bytes(getDigest(cert, "SHA-1"));        TrustAttributes attr = getModuleTrust(ModuleType.KEYSTORE, bytes);        if (attr == null) {            attr = getModuleTrust(ModuleType.FIPS, bytes);            if (attr == null) {                attr = getModuleTrust(ModuleType.TRUSTANCHOR, bytes);            }        }        return (attr == null) ? false : attr.isTrusted(trustType);    }     private TrustAttributes getModuleTrust(ModuleType type, Bytes bytes) {        Module module = getModule(type);        TrustAttributes t = (module == null) ? null : module.getTrust(bytes);        return t;    }     /**     * Constants describing the different types of NSS modules.     * For this API, NSS modules are classified as either one     * of the internal modules delivered as part of NSS or     * as an external module provided by a 3rd party.     */    public static enum ModuleType {        /**         * The NSS Softtoken crypto module. This is the first         * slot of the softtoken object.         * This module provides         * implementations for cryptographic algorithms but no KeyStore.         */        CRYPTO,        /**         * The NSS Softtoken KeyStore module. This is the second         * slot of the softtoken object.         * This module provides         * implementations for cryptographic algorithms (after login)         * and the KeyStore.         */        KEYSTORE,        /**         * The NSS Softtoken module in FIPS mode. Note that in FIPS mode the         * softtoken presents only one slot, not separate CRYPTO and KEYSTORE         * slots as in non-FIPS mode.         */        FIPS,        /**         * The NSS builtin trust anchor module. This is the         * NSSCKBI object. It provides no crypto functions.         */        TRUSTANCHOR,        /**         * An external module.         */        EXTERNAL,    }     /**     * Returns the first module of the specified type. If no such     * module exists, this method returns null.     *     * @throws IllegalStateException if this Secmod is misconfigured     *   or not initialized     */    public Module getModule(ModuleType type) {        for (Module module : getModules()) {            if (module.getType() == type) {                return module;            }        }        return null;    }     static final String TEMPLATE_EXTERNAL =        "library = %s\n"        + "name = \"%s\"\n"        + "slotListIndex = %d\n";     static final String TEMPLATE_TRUSTANCHOR =        "library = %s\n"        + "name = \"NSS Trust Anchors\"\n"        + "slotListIndex = 0\n"        + "enabledMechanisms = { KeyStore }\n"        + "nssUseSecmodTrust = true\n";     static final String TEMPLATE_CRYPTO =        "library = %s\n"        + "name = \"NSS SoftToken Crypto\"\n"        + "slotListIndex = 0\n"        + "disabledMechanisms = { KeyStore }\n";     static final String TEMPLATE_KEYSTORE =        "library = %s\n"        + "name = \"NSS SoftToken KeyStore\"\n"        + "slotListIndex = 1\n"        + "nssUseSecmodTrust = true\n";     static final String TEMPLATE_FIPS =        "library = %s\n"        + "name = \"NSS FIPS SoftToken\"\n"        + "slotListIndex = 0\n"        + "nssUseSecmodTrust = true\n";     /**     * A representation of one PKCS#11 slot in a PKCS#11 module.     */    public static final class Module {        // path of the native library        final String libraryName;        // descriptive name used by NSS        final String commonName;        final int slot;        final ModuleType type;         private String config;        private SunPKCS11 provider;         // trust attributes. Used for the KEYSTORE and TRUSTANCHOR modules only        private Map<Bytes,TrustAttributes> trust;         Module(String libraryDir, String libraryName, String commonName,                boolean fips, int slot) {            ModuleType type;             if ((libraryName == null) || (libraryName.length() == 0)) {                // must be softtoken                libraryName = System.mapLibraryName(SOFTTOKEN_LIB_NAME);                if (fips == false) {                    type = (slot == 0) ? ModuleType.CRYPTO : ModuleType.KEYSTORE;                } else {                    type = ModuleType.FIPS;                    if (slot != 0) {                        throw new RuntimeException                            ("Slot index should be 0 for FIPS slot");                    }                }            } else {                if (libraryName.endsWith(System.mapLibraryName(TRUST_LIB_NAME))                        || commonName.equals("Builtin Roots Module")) {                    type = ModuleType.TRUSTANCHOR;                } else {                    type = ModuleType.EXTERNAL;                }                if (fips) {                    throw new RuntimeException("FIPS flag set for non-internal "                        + "module: " + libraryName + ", " + commonName);                }            }            this.libraryName = (new File(libraryDir, libraryName)).getPath();            this.commonName = commonName;            this.slot = slot;            this.type = type;            initConfiguration();        }         private void initConfiguration() {            switch (type) {            case EXTERNAL:                config = String.format(TEMPLATE_EXTERNAL, libraryName,                                            commonName + " " + slot, slot);                break;            case CRYPTO:                config = String.format(TEMPLATE_CRYPTO, libraryName);                break;            case KEYSTORE:                config = String.format(TEMPLATE_KEYSTORE, libraryName);                break;            case FIPS:                config = String.format(TEMPLATE_FIPS, libraryName);                break;            case TRUSTANCHOR:                config = String.format(TEMPLATE_TRUSTANCHOR, libraryName);                break;            default:                throw new RuntimeException("Unknown module type: " + type);            }        }         /**         * Get the configuration for this module. This is a string         * in the SunPKCS11 configuration format. It can be         * customized with additional options and then made         * current using the setConfiguration() method.         */        @Deprecated        public synchronized String getConfiguration() {            return config;        }         /**         * Set the configuration for this module.         *         * @throws IllegalStateException if the associated provider         *   instance has already been created.         */        @Deprecated        public synchronized void setConfiguration(String config) {            if (provider != null) {                throw new IllegalStateException("Provider instance already created");            }            this.config = config;        }         /**         * Return the pathname of the native library that implements         * this module. For example, /usr/lib/libpkcs11.so.         */        public String getLibraryName() {            return libraryName;        }         /**         * Returns the type of this module.         */        public ModuleType getType() {            return type;        }         /**         * Returns the provider instance that is associated with this         * module. The first call to this method creates the provider         * instance.         */        @Deprecated        public synchronized Provider getProvider() {            if (provider == null) {                provider = newProvider();            }            return provider;        }         synchronized boolean hasInitializedProvider() {            return provider != null;        }         void setProvider(SunPKCS11 p) {            if (provider != null) {                throw new ProviderException("Secmod provider already initialized");            }            provider = p;        }         private SunPKCS11 newProvider() {            try {                InputStream in = new ByteArrayInputStream(config.getBytes("UTF8"));                return new SunPKCS11(in);

Lines 1–500 of 760.