284 lines · 10.9 KB · Java
RawDownload
/* * Copyright (c) 2003, 2008, 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.security.*;import java.security.spec.AlgorithmParameterSpec; import javax.crypto.*; import static sun.security.pkcs11.TemplateManager.*;import sun.security.pkcs11.wrapper.*;import static sun.security.pkcs11.wrapper.PKCS11Constants.*; /** * KeyGenerator implementation class. This class currently supports * DES, DESede, AES, ARCFOUR, and Blowfish. * * @author  Andreas Sterbenz * @since   1.5 */final class P11KeyGenerator extends KeyGeneratorSpi {     // token instance    private final Token token;     // algorithm name    private final String algorithm;     // mechanism id    private long mechanism;     // raw key size in bits, e.g. 64 for DES. Always valid.    private int keySize;     // bits of entropy in the key, e.g. 56 for DES. Always valid.    private int significantKeySize;     // keyType (CKK_*), needed for TemplateManager call only.    private long keyType;     // for determining if both 112 and 168 bits of DESede key lengths    // are supported.    private boolean supportBothKeySizes;     /**     * Utility method for checking if the specified key size is valid     * and within the supported range. Return the significant key size     * upon successful validation.     * @param keyGenMech the PKCS#11 key generation mechanism.     * @param keySize the to-be-checked key size for this mechanism.     * @param token token which provides this mechanism.     * @return the significant key size (in bits) corresponding to the     * specified key size.     * @throws InvalidParameterException if the specified key size is invalid.     * @throws ProviderException if this mechanism isn't supported by SunPKCS11     * or underlying native impl.     */    static int checkKeySize(long keyGenMech, int keySize, Token token)        throws InvalidAlgorithmParameterException, ProviderException {        int sigKeySize;        switch ((int)keyGenMech) {            case (int)CKM_DES_KEY_GEN:                if ((keySize != 64) && (keySize != 56)) {                    throw new InvalidAlgorithmParameterException                            ("DES key length must be 56 bits");                }                sigKeySize = 56;                break;            case (int)CKM_DES2_KEY_GEN:            case (int)CKM_DES3_KEY_GEN:                if ((keySize == 112) || (keySize == 128)) {                    sigKeySize = 112;                } else if ((keySize == 168) || (keySize == 192)) {                    sigKeySize = 168;                } else {                    throw new InvalidAlgorithmParameterException                            ("DESede key length must be 112, or 168 bits");                }                break;            default:                // Handle all variable-key-length algorithms here                CK_MECHANISM_INFO info = null;                try {                    info = token.getMechanismInfo(keyGenMech);                } catch (PKCS11Exception p11e) {                    // Should never happen                    throw new ProviderException                            ("Cannot retrieve mechanism info", p11e);                }                if (info == null) {                    // XXX Unable to retrieve the supported key length from                    // the underlying native impl. Skip the checking for now.                    return keySize;                }                // PKCS#11 defines these to be in number of bytes except for                // RC4 which is in bits. However, some PKCS#11 impls still use                // bytes for all mechs, e.g. NSS. We try to detect this                // inconsistency if the minKeySize seems unreasonably small.                int minKeySize = (int)info.ulMinKeySize;                int maxKeySize = (int)info.ulMaxKeySize;                if (keyGenMech != CKM_RC4_KEY_GEN || minKeySize < 8) {                    minKeySize = (int)info.ulMinKeySize << 3;                    maxKeySize = (int)info.ulMaxKeySize << 3;                }                // Explicitly disallow keys shorter than 40-bits for security                if (minKeySize < 40) minKeySize = 40;                if (keySize < minKeySize || keySize > maxKeySize) {                    throw new InvalidAlgorithmParameterException                            ("Key length must be between " + minKeySize +                            " and " + maxKeySize + " bits");                }                if (keyGenMech == CKM_AES_KEY_GEN) {                    if ((keySize != 128) && (keySize != 192) &&                        (keySize != 256)) {                        throw new InvalidAlgorithmParameterException                                ("AES key length must be " + minKeySize +                                (maxKeySize >= 192? ", 192":"") +                                (maxKeySize >= 256? ", or 256":"") + " bits");                    }                }                sigKeySize = keySize;        }        return sigKeySize;    }     P11KeyGenerator(Token token, String algorithm, long mechanism)            throws PKCS11Exception {        super();        this.token = token;        this.algorithm = algorithm;        this.mechanism = mechanism;         if (this.mechanism == CKM_DES3_KEY_GEN) {            /* Given the current lookup order specified in SunPKCS11.java,               if CKM_DES2_KEY_GEN is used to construct this object, it               means that CKM_DES3_KEY_GEN is disabled or unsupported.            */            supportBothKeySizes =                (token.provider.config.isEnabled(CKM_DES2_KEY_GEN) &&                 (token.getMechanismInfo(CKM_DES2_KEY_GEN) != null));        }        setDefaultKeySize();    }     // set default keysize and also initialize keyType    private void setDefaultKeySize() {        switch ((int)mechanism) {        case (int)CKM_DES_KEY_GEN:            keySize = 64;            keyType = CKK_DES;            break;        case (int)CKM_DES2_KEY_GEN:            keySize = 128;            keyType = CKK_DES2;            break;        case (int)CKM_DES3_KEY_GEN:            keySize = 192;            keyType = CKK_DES3;            break;        case (int)CKM_AES_KEY_GEN:            keySize = 128;            keyType = CKK_AES;            break;        case (int)CKM_RC4_KEY_GEN:            keySize = 128;            keyType = CKK_RC4;            break;        case (int)CKM_BLOWFISH_KEY_GEN:            keySize = 128;            keyType = CKK_BLOWFISH;            break;        default:            throw new ProviderException("Unknown mechanism " + mechanism);        }        try {            significantKeySize = checkKeySize(mechanism, keySize, token);        } catch (InvalidAlgorithmParameterException iape) {            throw new ProviderException("Unsupported default key size", iape);        }    }     // see JCE spec    protected void engineInit(SecureRandom random) {        token.ensureValid();        setDefaultKeySize();    }     // see JCE spec    protected void engineInit(AlgorithmParameterSpec params,            SecureRandom random) throws InvalidAlgorithmParameterException {        throw new InvalidAlgorithmParameterException                ("AlgorithmParameterSpec not supported");    }     // see JCE spec    protected void engineInit(int keySize, SecureRandom random) {        token.ensureValid();        int newSignificantKeySize;        try {            newSignificantKeySize = checkKeySize(mechanism, keySize, token);        } catch (InvalidAlgorithmParameterException iape) {            throw (InvalidParameterException)                    (new InvalidParameterException().initCause(iape));        }        if ((mechanism == CKM_DES2_KEY_GEN) ||            (mechanism == CKM_DES3_KEY_GEN))  {            long newMechanism = (newSignificantKeySize == 112 ?                CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN);            if (mechanism != newMechanism) {                if (supportBothKeySizes) {                    mechanism = newMechanism;                    // Adjust keyType to reflect the mechanism change                    keyType = (mechanism == CKM_DES2_KEY_GEN ?                        CKK_DES2 : CKK_DES3);                } else {                    throw new InvalidParameterException                            ("Only " + significantKeySize +                             "-bit DESede is supported");                }            }        }        this.keySize = keySize;        this.significantKeySize = newSignificantKeySize;    }     // see JCE spec    protected SecretKey engineGenerateKey() {        Session session = null;        try {            session = token.getObjSession();            CK_ATTRIBUTE[] attributes;            switch ((int)keyType) {            case (int)CKK_DES:            case (int)CKK_DES2:            case (int)CKK_DES3:                // fixed length, do not specify CKA_VALUE_LEN                attributes = new CK_ATTRIBUTE[] {                    new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),                };                break;            default:                attributes = new CK_ATTRIBUTE[] {                    new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),                    new CK_ATTRIBUTE(CKA_VALUE_LEN, keySize >> 3),                };                break;            }            attributes = token.getAttributes                (O_GENERATE, CKO_SECRET_KEY, keyType, attributes);            long keyID = token.p11.C_GenerateKey                (session.id(), new CK_MECHANISM(mechanism), attributes);            return P11Key.secretKey                (session, keyID, algorithm, significantKeySize, attributes);        } catch (PKCS11Exception e) {            throw new ProviderException("Could not generate key", e);        } finally {            token.releaseSession(session);        }    } }