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