1 /*
   2  * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.pkcs11;
  27 
  28 import java.security.*;
  29 import java.security.spec.AlgorithmParameterSpec;
  30 
  31 import javax.crypto.*;
  32 
  33 import static sun.security.pkcs11.TemplateManager.*;
  34 import sun.security.pkcs11.wrapper.*;
  35 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
  36 
  37 /**
  38  * KeyGenerator implementation class. This class currently supports
  39  * DES, DESede, AES, ARCFOUR, and Blowfish.
  40  *
  41  * @author  Andreas Sterbenz
  42  * @since   1.5
  43  */
  44 final class P11KeyGenerator extends KeyGeneratorSpi {
  45 
  46     // token instance
  47     private final Token token;
  48 
  49     // algorithm name
  50     private final String algorithm;
  51 
  52     // mechanism id
  53     private long mechanism;
  54 
  55     // raw key size in bits, e.g. 64 for DES. Always valid.
  56     private int keySize;
  57 
  58     // bits of entropy in the key, e.g. 56 for DES. Always valid.
  59     private int significantKeySize;
  60 
  61     // keyType (CKK_*), needed for TemplateManager call only.
  62     private long keyType;
  63 
  64     // for determining if both 112 and 168 bits of DESede key lengths
  65     // are supported.
  66     private boolean supportBothKeySizes;
  67 
  68     /**
  69      * Utility method for checking if the specified key size is valid
  70      * and within the supported range. Return the significant key size
  71      * upon successful validation.
  72      * @param keyGenMech the PKCS#11 key generation mechanism.
  73      * @param keySize the to-be-checked key size for this mechanism.
  74      * @param token token which provides this mechanism.
  75      * @return the significant key size (in bits) corresponding to the
  76      * specified key size.
  77      * @throws InvalidParameterException if the specified key size is invalid.
  78      * @throws ProviderException if this mechanism isn't supported by SunPKCS11
  79      * or underlying native impl.
  80      */
  81     static int checkKeySize(long keyGenMech, int keySize, Token token)
  82         throws InvalidAlgorithmParameterException, ProviderException {
  83         int sigKeySize;
  84         switch ((int)keyGenMech) {
  85             case (int)CKM_DES_KEY_GEN:
  86                 if ((keySize != 64) && (keySize != 56)) {
  87                     throw new InvalidAlgorithmParameterException
  88                             ("DES key length must be 56 bits");
  89                 }
  90                 sigKeySize = 56;
  91                 break;
  92             case (int)CKM_DES2_KEY_GEN:
  93             case (int)CKM_DES3_KEY_GEN:
  94                 if ((keySize == 112) || (keySize == 128)) {
  95                     sigKeySize = 112;
  96                 } else if ((keySize == 168) || (keySize == 192)) {
  97                     sigKeySize = 168;
  98                 } else {
  99                     throw new InvalidAlgorithmParameterException
 100                             ("DESede key length must be 112, or 168 bits");
 101                 }
 102                 break;
 103             default:
 104                 // Handle all variable-key-length algorithms here
 105                 CK_MECHANISM_INFO info = null;
 106                 try {
 107                     info = token.getMechanismInfo(keyGenMech);
 108                 } catch (PKCS11Exception p11e) {
 109                     // Should never happen
 110                     throw new ProviderException
 111                             ("Cannot retrieve mechanism info", p11e);
 112                 }
 113                 if (info == null) {
 114                     // XXX Unable to retrieve the supported key length from
 115                     // the underlying native impl. Skip the checking for now.
 116                     return keySize;
 117                 }
 118                 // PKCS#11 defines these to be in number of bytes except for
 119                 // RC4 which is in bits. However, some PKCS#11 impls still use
 120                 // bytes for all mechs, e.g. NSS. We try to detect this
 121                 // inconsistency if the minKeySize seems unreasonably small.
 122                 int minKeySize = (int)info.ulMinKeySize;
 123                 int maxKeySize = (int)info.ulMaxKeySize;
 124                 if (keyGenMech != CKM_RC4_KEY_GEN || minKeySize < 8) {
 125                     minKeySize = (int)info.ulMinKeySize << 3;
 126                     maxKeySize = (int)info.ulMaxKeySize << 3;
 127                 }
 128                 // Explicitly disallow keys shorter than 40-bits for security
 129                 if (minKeySize < 40) minKeySize = 40;
 130                 if (keySize < minKeySize || keySize > maxKeySize) {
 131                     throw new InvalidAlgorithmParameterException
 132                             ("Key length must be between " + minKeySize +
 133                             " and " + maxKeySize + " bits");
 134                 }
 135                 if (keyGenMech == CKM_AES_KEY_GEN) {
 136                     if ((keySize != 128) && (keySize != 192) &&
 137                         (keySize != 256)) {
 138                         throw new InvalidAlgorithmParameterException
 139                                 ("AES key length must be " + minKeySize +
 140                                 (maxKeySize >= 192? ", 192":"") +
 141                                 (maxKeySize >= 256? ", or 256":"") + " bits");
 142                     }
 143                 }
 144                 sigKeySize = keySize;
 145         }
 146         return sigKeySize;
 147     }
 148 
 149     P11KeyGenerator(Token token, String algorithm, long mechanism)
 150             throws PKCS11Exception {
 151         super();
 152         this.token = token;
 153         this.algorithm = algorithm;
 154         this.mechanism = mechanism;
 155 
 156         if (this.mechanism == CKM_DES3_KEY_GEN) {
 157             /* Given the current lookup order specified in SunPKCS11.java,
 158                if CKM_DES2_KEY_GEN is used to construct this object, it
 159                means that CKM_DES3_KEY_GEN is disabled or unsupported.
 160             */
 161             supportBothKeySizes =
 162                 (token.provider.config.isEnabled(CKM_DES2_KEY_GEN) &&
 163                  (token.getMechanismInfo(CKM_DES2_KEY_GEN) != null));
 164         }
 165         setDefaultKeySize();
 166     }
 167 
 168     // set default keysize and also initialize keyType
 169     private void setDefaultKeySize() {
 170         switch ((int)mechanism) {
 171         case (int)CKM_DES_KEY_GEN:
 172             keySize = 64;
 173             keyType = CKK_DES;
 174             break;
 175         case (int)CKM_DES2_KEY_GEN:
 176             keySize = 128;
 177             keyType = CKK_DES2;
 178             break;
 179         case (int)CKM_DES3_KEY_GEN:
 180             keySize = 192;
 181             keyType = CKK_DES3;
 182             break;
 183         case (int)CKM_AES_KEY_GEN:
 184             keySize = 128;
 185             keyType = CKK_AES;
 186             break;
 187         case (int)CKM_RC4_KEY_GEN:
 188             keySize = 128;
 189             keyType = CKK_RC4;
 190             break;
 191         case (int)CKM_BLOWFISH_KEY_GEN:
 192             keySize = 128;
 193             keyType = CKK_BLOWFISH;
 194             break;
 195         default:
 196             throw new ProviderException("Unknown mechanism " + mechanism);
 197         }
 198         try {
 199             significantKeySize = checkKeySize(mechanism, keySize, token);
 200         } catch (InvalidAlgorithmParameterException iape) {
 201             throw new ProviderException("Unsupported default key size", iape);
 202         }
 203     }
 204 
 205     // see JCE spec
 206     protected void engineInit(SecureRandom random) {
 207         token.ensureValid();
 208         setDefaultKeySize();
 209     }
 210 
 211     // see JCE spec
 212     protected void engineInit(AlgorithmParameterSpec params,
 213             SecureRandom random) throws InvalidAlgorithmParameterException {
 214         throw new InvalidAlgorithmParameterException
 215                 ("AlgorithmParameterSpec not supported");
 216     }
 217 
 218     // see JCE spec
 219     protected void engineInit(int keySize, SecureRandom random) {
 220         token.ensureValid();
 221         int newSignificantKeySize;
 222         try {
 223             newSignificantKeySize = checkKeySize(mechanism, keySize, token);
 224         } catch (InvalidAlgorithmParameterException iape) {
 225             throw (InvalidParameterException)
 226                     (new InvalidParameterException().initCause(iape));
 227         }
 228         if ((mechanism == CKM_DES2_KEY_GEN) ||
 229             (mechanism == CKM_DES3_KEY_GEN))  {
 230             long newMechanism = (newSignificantKeySize == 112 ?
 231                 CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN);
 232             if (mechanism != newMechanism) {
 233                 if (supportBothKeySizes) {
 234                     mechanism = newMechanism;
 235                     // Adjust keyType to reflect the mechanism change
 236                     keyType = (mechanism == CKM_DES2_KEY_GEN ?
 237                         CKK_DES2 : CKK_DES3);
 238                 } else {
 239                     throw new InvalidParameterException
 240                             ("Only " + significantKeySize +
 241                              "-bit DESede is supported");
 242                 }
 243             }
 244         }
 245         this.keySize = keySize;
 246         this.significantKeySize = newSignificantKeySize;
 247     }
 248 
 249     // see JCE spec
 250     protected SecretKey engineGenerateKey() {
 251         Session session = null;
 252         try {
 253             session = token.getObjSession();
 254             CK_ATTRIBUTE[] attributes;
 255             switch ((int)keyType) {
 256             case (int)CKK_DES:
 257             case (int)CKK_DES2:
 258             case (int)CKK_DES3:
 259                 // fixed length, do not specify CKA_VALUE_LEN
 260                 attributes = new CK_ATTRIBUTE[] {
 261                     new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
 262                 };
 263                 break;
 264             default:
 265                 attributes = new CK_ATTRIBUTE[] {
 266                     new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
 267                     new CK_ATTRIBUTE(CKA_VALUE_LEN, keySize >> 3),
 268                 };
 269                 break;
 270             }
 271             attributes = token.getAttributes
 272                 (O_GENERATE, CKO_SECRET_KEY, keyType, attributes);
 273             long keyID = token.p11.C_GenerateKey
 274                 (session.id(), new CK_MECHANISM(mechanism), attributes);
 275             return P11Key.secretKey
 276                 (session, keyID, algorithm, significantKeySize, attributes);
 277         } catch (PKCS11Exception e) {
 278             throw new ProviderException("Could not generate key", e);
 279         } finally {
 280             token.releaseSession(session);
 281         }
 282     }
 283 
 284 }