1 /* 2 * Copyright (c) 2003, 2017, 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.math.BigInteger; 29 30 import java.security.*; 31 import java.security.spec.*; 32 33 import javax.crypto.spec.DHParameterSpec; 34 35 import sun.security.provider.ParameterCache; 36 import static sun.security.util.SecurityProviderConstants.*; 37 38 import static sun.security.pkcs11.TemplateManager.*; 39 import sun.security.pkcs11.wrapper.*; 40 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 41 42 43 import sun.security.rsa.RSAKeyFactory; 44 45 /** 46 * KeyPairGenerator implementation class. This class currently supports 47 * RSA, DSA, DH, and EC. 48 * 49 * Note that for DSA and DH we rely on the Sun and SunJCE providers to 50 * obtain the parameters from. 51 * 52 * @author Andreas Sterbenz 53 * @since 1.5 54 */ 55 final class P11KeyPairGenerator extends KeyPairGeneratorSpi { 56 57 // token instance 58 private final Token token; 59 60 // algorithm name 61 private final String algorithm; 62 63 // mechanism id 64 private final long mechanism; 65 66 // selected or default key size, always valid 67 private int keySize; 68 69 // parameters specified via init, if any 70 private AlgorithmParameterSpec params; 71 72 // for RSA, selected or default value of public exponent, always valid 73 private BigInteger rsaPublicExponent = RSAKeyGenParameterSpec.F4; 74 75 // the supported keysize range of the native PKCS11 library 76 // if the value cannot be retrieved or unspecified, -1 is used. 77 private final int minKeySize; 78 private final int maxKeySize; 79 80 // SecureRandom instance, if specified in init 81 private SecureRandom random; 82 83 P11KeyPairGenerator(Token token, String algorithm, long mechanism) 84 throws PKCS11Exception { 85 super(); 86 int minKeyLen = -1; 87 int maxKeyLen = -1; 88 try { 89 CK_MECHANISM_INFO mechInfo = token.getMechanismInfo(mechanism); 90 if (mechInfo != null) { 91 minKeyLen = (int) mechInfo.ulMinKeySize; 92 maxKeyLen = (int) mechInfo.ulMaxKeySize; 93 } 94 } catch (PKCS11Exception p11e) { 95 // Should never happen 96 throw new ProviderException 97 ("Unexpected error while getting mechanism info", p11e); 98 } 99 // set default key sizes and apply our own algorithm-specific limits 100 // override lower limit to disallow unsecure keys being generated 101 // override upper limit to deter DOS attack 102 if (algorithm.equals("EC")) { 103 keySize = DEF_EC_KEY_SIZE; 104 if ((minKeyLen == -1) || (minKeyLen < 112)) { 105 minKeyLen = 112; 106 } 107 if ((maxKeyLen == -1) || (maxKeyLen > 2048)) { 108 maxKeyLen = 2048; 109 } 110 } else { 111 if (algorithm.equals("DSA")) { 112 keySize = DEF_DSA_KEY_SIZE; 113 } else if (algorithm.equals("RSA")) { 114 keySize = DEF_RSA_KEY_SIZE; 115 } else { 116 keySize = DEF_DH_KEY_SIZE; 117 } 118 if ((minKeyLen == -1) || (minKeyLen < 512)) { 119 minKeyLen = 512; 120 } 121 if (algorithm.equals("RSA")) { 122 if ((maxKeyLen == -1) || (maxKeyLen > 64 * 1024)) { 123 maxKeyLen = 64 * 1024; 124 } 125 } 126 } 127 128 // auto-adjust default keysize in case it's out-of-range 129 if ((minKeyLen != -1) && (keySize < minKeyLen)) { 130 keySize = minKeyLen; 131 } 132 if ((maxKeyLen != -1) && (keySize > maxKeyLen)) { 133 keySize = maxKeyLen; 134 } 135 this.token = token; 136 this.algorithm = algorithm; 137 this.mechanism = mechanism; 138 this.minKeySize = minKeyLen; 139 this.maxKeySize = maxKeyLen; 140 initialize(keySize, null); 141 } 142 143 // see JCA spec 144 public void initialize(int keySize, SecureRandom random) { 145 token.ensureValid(); 146 try { 147 checkKeySize(keySize, null); 148 } catch (InvalidAlgorithmParameterException e) { 149 throw new InvalidParameterException(e.getMessage()); 150 } 151 this.params = null; 152 if (algorithm.equals("EC")) { 153 params = P11ECKeyFactory.getECParameterSpec(keySize); 154 if (params == null) { 155 throw new InvalidParameterException( 156 "No EC parameters available for key size " 157 + keySize + " bits"); 158 } 159 } 160 this.keySize = keySize; 161 this.random = random; 162 } 163 164 // see JCA spec 165 public void initialize(AlgorithmParameterSpec params, SecureRandom random) 166 throws InvalidAlgorithmParameterException { 167 token.ensureValid(); 168 int tmpKeySize; 169 if (algorithm.equals("DH")) { 170 if (params instanceof DHParameterSpec == false) { 171 throw new InvalidAlgorithmParameterException 172 ("DHParameterSpec required for Diffie-Hellman"); 173 } 174 DHParameterSpec dhParams = (DHParameterSpec) params; 175 tmpKeySize = dhParams.getP().bitLength(); 176 checkKeySize(tmpKeySize, null); 177 // XXX sanity check params 178 } else if (algorithm.equals("RSA")) { 179 if (params instanceof RSAKeyGenParameterSpec == false) { 180 throw new InvalidAlgorithmParameterException 181 ("RSAKeyGenParameterSpec required for RSA"); 182 } 183 RSAKeyGenParameterSpec rsaParams = 184 (RSAKeyGenParameterSpec) params; 185 tmpKeySize = rsaParams.getKeysize(); 186 checkKeySize(tmpKeySize, rsaParams); 187 // override the supplied params to null 188 params = null; 189 this.rsaPublicExponent = rsaParams.getPublicExponent(); 190 // XXX sanity check params 191 } else if (algorithm.equals("DSA")) { 192 if (params instanceof DSAParameterSpec == false) { 193 throw new InvalidAlgorithmParameterException 194 ("DSAParameterSpec required for DSA"); 195 } 196 DSAParameterSpec dsaParams = (DSAParameterSpec) params; 197 tmpKeySize = dsaParams.getP().bitLength(); 198 checkKeySize(tmpKeySize, null); 199 // XXX sanity check params 200 } else if (algorithm.equals("EC")) { 201 ECParameterSpec ecParams; 202 if (params instanceof ECParameterSpec) { 203 ecParams = P11ECKeyFactory.getECParameterSpec( 204 (ECParameterSpec)params); 205 if (ecParams == null) { 206 throw new InvalidAlgorithmParameterException 207 ("Unsupported curve: " + params); 208 } 209 } else if (params instanceof ECGenParameterSpec) { 210 String name = ((ECGenParameterSpec) params).getName(); 211 ecParams = P11ECKeyFactory.getECParameterSpec(name); 212 if (ecParams == null) { 213 throw new InvalidAlgorithmParameterException 214 ("Unknown curve name: " + name); 215 } 216 // override the supplied params with the derived one 217 params = ecParams; 218 } else { 219 throw new InvalidAlgorithmParameterException 220 ("ECParameterSpec or ECGenParameterSpec required for EC"); 221 } 222 tmpKeySize = ecParams.getCurve().getField().getFieldSize(); 223 checkKeySize(tmpKeySize, null); 224 } else { 225 throw new ProviderException("Unknown algorithm: " + algorithm); 226 } 227 this.keySize = tmpKeySize; 228 this.params = params; 229 this.random = random; 230 } 231 232 // NOTE: 'params' is only used for checking RSA keys currently. 233 private void checkKeySize(int keySize, RSAKeyGenParameterSpec params) 234 throws InvalidAlgorithmParameterException { 235 // check native range first 236 if ((minKeySize != -1) && (keySize < minKeySize)) { 237 throw new InvalidAlgorithmParameterException(algorithm + 238 " key must be at least " + minKeySize + " bits. " + 239 "The specific key size " + keySize + " is not supported"); 240 } 241 if ((maxKeySize != -1) && (keySize > maxKeySize)) { 242 throw new InvalidAlgorithmParameterException(algorithm + 243 " key must be at most " + maxKeySize + " bits. " + 244 "The specific key size " + keySize + " is not supported"); 245 } 246 247 // check our own algorithm-specific limits also 248 if (algorithm.equals("EC")) { 249 if (keySize < 112) { 250 throw new InvalidAlgorithmParameterException( 251 "EC key size must be at least 112 bit. " + 252 "The specific key size " + keySize + " is not supported"); 253 } 254 if (keySize > 2048) { 255 // sanity check, nobody really wants keys this large 256 throw new InvalidAlgorithmParameterException( 257 "EC key size must be at most 2048 bit. " + 258 "The specific key size " + keySize + " is not supported"); 259 } 260 } else { 261 // RSA, DH, DSA 262 if (keySize < 512) { 263 throw new InvalidAlgorithmParameterException(algorithm + 264 " key size must be at least 512 bit. " + 265 "The specific key size " + keySize + " is not supported"); 266 } 267 if (algorithm.equals("RSA")) { 268 BigInteger tmpExponent = rsaPublicExponent; 269 if (params != null) { 270 tmpExponent = params.getPublicExponent(); 271 } 272 try { 273 // Reuse the checking in SunRsaSign provider. 274 // If maxKeySize is -1, then replace it with 275 // Integer.MAX_VALUE to indicate no limit. 276 RSAKeyFactory.checkKeyLengths(keySize, tmpExponent, 277 minKeySize, 278 (maxKeySize==-1? Integer.MAX_VALUE:maxKeySize)); 279 } catch (InvalidKeyException e) { 280 throw new InvalidAlgorithmParameterException(e.getMessage()); 281 } 282 } else { 283 if (algorithm.equals("DH") && (params != null)) { 284 // sanity check, nobody really wants keys this large 285 if (keySize > 64 * 1024) { 286 throw new InvalidAlgorithmParameterException( 287 "DH key size must be at most 65536 bit. " + 288 "The specific key size " + 289 keySize + " is not supported"); 290 } 291 } else { 292 // this restriction is in the spec for DSA 293 // since we currently use DSA parameters for DH as well, 294 // it also applies to DH if no parameters are specified 295 if ((keySize != 2048) && 296 ((keySize > 1024) || ((keySize & 0x3f) != 0))) { 297 throw new InvalidAlgorithmParameterException(algorithm + 298 " key must be multiples of 64 if less than 1024 bits" + 299 ", or 2048 bits. " + 300 "The specific key size " + 301 keySize + " is not supported"); 302 } 303 } 304 } 305 } 306 } 307 308 // see JCA spec 309 public KeyPair generateKeyPair() { 310 token.ensureValid(); 311 CK_ATTRIBUTE[] publicKeyTemplate; 312 CK_ATTRIBUTE[] privateKeyTemplate; 313 long keyType; 314 if (algorithm.equals("RSA")) { 315 keyType = CKK_RSA; 316 publicKeyTemplate = new CK_ATTRIBUTE[] { 317 new CK_ATTRIBUTE(CKA_MODULUS_BITS, keySize), 318 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, rsaPublicExponent), 319 }; 320 privateKeyTemplate = new CK_ATTRIBUTE[] { 321 // empty 322 }; 323 } else if (algorithm.equals("DSA")) { 324 keyType = CKK_DSA; 325 DSAParameterSpec dsaParams; 326 if (params == null) { 327 try { 328 dsaParams = ParameterCache.getDSAParameterSpec 329 (keySize, random); 330 } catch (GeneralSecurityException e) { 331 throw new ProviderException 332 ("Could not generate DSA parameters", e); 333 } 334 } else { 335 dsaParams = (DSAParameterSpec)params; 336 } 337 publicKeyTemplate = new CK_ATTRIBUTE[] { 338 new CK_ATTRIBUTE(CKA_PRIME, dsaParams.getP()), 339 new CK_ATTRIBUTE(CKA_SUBPRIME, dsaParams.getQ()), 340 new CK_ATTRIBUTE(CKA_BASE, dsaParams.getG()), 341 }; 342 privateKeyTemplate = new CK_ATTRIBUTE[] { 343 // empty 344 }; 345 } else if (algorithm.equals("DH")) { 346 keyType = CKK_DH; 347 DHParameterSpec dhParams; 348 int privateBits; 349 if (params == null) { 350 try { 351 dhParams = ParameterCache.getDHParameterSpec 352 (keySize, random); 353 } catch (GeneralSecurityException e) { 354 throw new ProviderException 355 ("Could not generate DH parameters", e); 356 } 357 privateBits = 0; 358 } else { 359 dhParams = (DHParameterSpec)params; 360 privateBits = dhParams.getL(); 361 } 362 if (privateBits <= 0) { 363 // XXX find better defaults 364 privateBits = (keySize >= 1024) ? 768 : 512; 365 } 366 publicKeyTemplate = new CK_ATTRIBUTE[] { 367 new CK_ATTRIBUTE(CKA_PRIME, dhParams.getP()), 368 new CK_ATTRIBUTE(CKA_BASE, dhParams.getG()) 369 }; 370 privateKeyTemplate = new CK_ATTRIBUTE[] { 371 new CK_ATTRIBUTE(CKA_VALUE_BITS, privateBits), 372 }; 373 } else if (algorithm.equals("EC")) { 374 keyType = CKK_EC; 375 byte[] encodedParams = 376 P11ECKeyFactory.encodeParameters((ECParameterSpec)params); 377 publicKeyTemplate = new CK_ATTRIBUTE[] { 378 new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), 379 }; 380 privateKeyTemplate = new CK_ATTRIBUTE[] { 381 // empty 382 }; 383 } else { 384 throw new ProviderException("Unknown algorithm: " + algorithm); 385 } 386 Session session = null; 387 try { 388 session = token.getObjSession(); 389 publicKeyTemplate = token.getAttributes 390 (O_GENERATE, CKO_PUBLIC_KEY, keyType, publicKeyTemplate); 391 privateKeyTemplate = token.getAttributes 392 (O_GENERATE, CKO_PRIVATE_KEY, keyType, privateKeyTemplate); 393 long[] keyIDs = token.p11.C_GenerateKeyPair 394 (session.id(), new CK_MECHANISM(mechanism), 395 publicKeyTemplate, privateKeyTemplate); 396 PublicKey publicKey = P11Key.publicKey 397 (session, keyIDs[0], algorithm, keySize, publicKeyTemplate); 398 PrivateKey privateKey = P11Key.privateKey 399 (session, keyIDs[1], algorithm, keySize, privateKeyTemplate); 400 return new KeyPair(publicKey, privateKey); 401 } catch (PKCS11Exception e) { 402 throw new ProviderException(e); 403 } finally { 404 token.releaseSession(session); 405 } 406 } 407 }