Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
38919 views
/*1* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.pkcs11;2627import java.math.BigInteger;2829import java.security.*;30import java.security.spec.*;3132import javax.crypto.spec.DHParameterSpec;3334import sun.security.provider.ParameterCache;35import static sun.security.util.SecurityProviderConstants.*;3637import static sun.security.pkcs11.TemplateManager.*;38import sun.security.pkcs11.wrapper.*;39import static sun.security.pkcs11.wrapper.PKCS11Constants.*;404142import sun.security.rsa.RSAKeyFactory;4344/**45* KeyPairGenerator implementation class. This class currently supports46* RSA, DSA, DH, and EC.47*48* Note that for DSA and DH we rely on the Sun and SunJCE providers to49* obtain the parameters from.50*51* @author Andreas Sterbenz52* @since 1.553*/54final class P11KeyPairGenerator extends KeyPairGeneratorSpi {5556// token instance57private final Token token;5859// algorithm name60private final String algorithm;6162// mechanism id63private final long mechanism;6465// selected or default key size, always valid66private int keySize;6768// parameters specified via init, if any69private AlgorithmParameterSpec params;7071// for RSA, selected or default value of public exponent, always valid72private BigInteger rsaPublicExponent = RSAKeyGenParameterSpec.F4;7374// the supported keysize range of the native PKCS11 library75// if the value cannot be retrieved or unspecified, -1 is used.76private final int minKeySize;77private final int maxKeySize;7879// SecureRandom instance, if specified in init80private SecureRandom random;8182P11KeyPairGenerator(Token token, String algorithm, long mechanism)83throws PKCS11Exception {84super();85int minKeyLen = -1;86int maxKeyLen = -1;87try {88CK_MECHANISM_INFO mechInfo = token.getMechanismInfo(mechanism);89if (mechInfo != null) {90minKeyLen = (int) mechInfo.ulMinKeySize;91maxKeyLen = (int) mechInfo.ulMaxKeySize;92}93} catch (PKCS11Exception p11e) {94// Should never happen95throw new ProviderException96("Unexpected error while getting mechanism info", p11e);97}98// set default key sizes and apply our own algorithm-specific limits99// override lower limit to disallow unsecure keys being generated100// override upper limit to deter DOS attack101if (algorithm.equals("EC")) {102keySize = DEF_EC_KEY_SIZE;103if ((minKeyLen == -1) || (minKeyLen < 112)) {104minKeyLen = 112;105}106if ((maxKeyLen == -1) || (maxKeyLen > 2048)) {107maxKeyLen = 2048;108}109} else {110if (algorithm.equals("DSA")) {111keySize = DEF_DSA_KEY_SIZE;112} else if (algorithm.equals("RSA")) {113keySize = DEF_RSA_KEY_SIZE;114} else {115keySize = DEF_DH_KEY_SIZE;116}117if ((minKeyLen == -1) || (minKeyLen < 512)) {118minKeyLen = 512;119}120if (algorithm.equals("RSA")) {121if ((maxKeyLen == -1) || (maxKeyLen > 64 * 1024)) {122maxKeyLen = 64 * 1024;123}124}125}126127// auto-adjust default keysize in case it's out-of-range128if ((minKeyLen != -1) && (keySize < minKeyLen)) {129keySize = minKeyLen;130}131if ((maxKeyLen != -1) && (keySize > maxKeyLen)) {132keySize = maxKeyLen;133}134this.token = token;135this.algorithm = algorithm;136this.mechanism = mechanism;137this.minKeySize = minKeyLen;138this.maxKeySize = maxKeyLen;139initialize(keySize, null);140}141142// see JCA spec143@Override144public void initialize(int keySize, SecureRandom random) {145token.ensureValid();146try {147checkKeySize(keySize, null);148} catch (InvalidAlgorithmParameterException e) {149throw new InvalidParameterException(e.getMessage());150}151this.params = null;152if (algorithm.equals("EC")) {153params = P11ECKeyFactory.getECParameterSpec(keySize);154if (params == null) {155throw new InvalidParameterException(156"No EC parameters available for key size "157+ keySize + " bits");158}159}160this.keySize = keySize;161this.random = random;162}163164// see JCA spec165@Override166public void initialize(AlgorithmParameterSpec params, SecureRandom random)167throws InvalidAlgorithmParameterException {168token.ensureValid();169int tmpKeySize;170if (algorithm.equals("DH")) {171if (params instanceof DHParameterSpec == false) {172throw new InvalidAlgorithmParameterException173("DHParameterSpec required for Diffie-Hellman");174}175DHParameterSpec dhParams = (DHParameterSpec) params;176tmpKeySize = dhParams.getP().bitLength();177checkKeySize(tmpKeySize, dhParams);178// XXX sanity check params179} else if (algorithm.equals("RSA")) {180if (params instanceof RSAKeyGenParameterSpec == false) {181throw new InvalidAlgorithmParameterException182("RSAKeyGenParameterSpec required for RSA");183}184RSAKeyGenParameterSpec rsaParams =185(RSAKeyGenParameterSpec) params;186tmpKeySize = rsaParams.getKeysize();187checkKeySize(tmpKeySize, rsaParams);188// override the supplied params to null189params = null;190this.rsaPublicExponent = rsaParams.getPublicExponent();191// XXX sanity check params192} else if (algorithm.equals("DSA")) {193if (params instanceof DSAParameterSpec == false) {194throw new InvalidAlgorithmParameterException195("DSAParameterSpec required for DSA");196}197DSAParameterSpec dsaParams = (DSAParameterSpec) params;198tmpKeySize = dsaParams.getP().bitLength();199checkKeySize(tmpKeySize, dsaParams);200// XXX sanity check params201} else if (algorithm.equals("EC")) {202ECParameterSpec ecParams;203if (params instanceof ECParameterSpec) {204ecParams = P11ECKeyFactory.getECParameterSpec(205(ECParameterSpec)params);206if (ecParams == null) {207throw new InvalidAlgorithmParameterException208("Unsupported curve: " + params);209}210} else if (params instanceof ECGenParameterSpec) {211String name = ((ECGenParameterSpec) params).getName();212ecParams = P11ECKeyFactory.getECParameterSpec(name);213if (ecParams == null) {214throw new InvalidAlgorithmParameterException215("Unknown curve name: " + name);216}217// override the supplied params with the derived one218params = ecParams;219} else {220throw new InvalidAlgorithmParameterException221("ECParameterSpec or ECGenParameterSpec required for EC");222}223tmpKeySize = ecParams.getCurve().getField().getFieldSize();224checkKeySize(tmpKeySize, ecParams);225} else {226throw new ProviderException("Unknown algorithm: " + algorithm);227}228this.keySize = tmpKeySize;229this.params = params;230this.random = random;231}232233private void checkKeySize(int keySize, AlgorithmParameterSpec params)234throws InvalidAlgorithmParameterException {235// check native range first236if ((minKeySize != -1) && (keySize < minKeySize)) {237throw new InvalidAlgorithmParameterException(algorithm +238" key must be at least " + minKeySize + " bits. " +239"The specific key size " + keySize + " is not supported");240}241if ((maxKeySize != -1) && (keySize > maxKeySize)) {242throw new InvalidAlgorithmParameterException(algorithm +243" key must be at most " + maxKeySize + " bits. " +244"The specific key size " + keySize + " is not supported");245}246247// check our own algorithm-specific limits also248if (algorithm.equals("EC")) {249if (keySize < 112) {250throw new InvalidAlgorithmParameterException(251"EC key size must be at least 112 bit. " +252"The specific key size " + keySize + " is not supported");253}254if (keySize > 2048) {255// sanity check, nobody really wants keys this large256throw 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, DSA262if (keySize < 512) {263throw new InvalidAlgorithmParameterException(algorithm +264" key size must be at least 512 bit. " +265"The specific key size " + keySize + " is not supported");266}267if (algorithm.equals("RSA")) {268BigInteger tmpExponent = rsaPublicExponent;269if (params != null) {270tmpExponent =271((RSAKeyGenParameterSpec)params).getPublicExponent();272}273try {274// Reuse the checking in SunRsaSign provider.275// If maxKeySize is -1, then replace it with276// Integer.MAX_VALUE to indicate no limit.277RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,278minKeySize,279(maxKeySize==-1? Integer.MAX_VALUE:maxKeySize));280} catch (InvalidKeyException e) {281throw new InvalidAlgorithmParameterException(e);282}283} else if (algorithm.equals("DH")) {284if (params != null) { // initialized with specified parameters285// sanity check, nobody really wants keys this large286if (keySize > 64 * 1024) {287throw new InvalidAlgorithmParameterException(288"DH key size must be at most 65536 bit. " +289"The specific key size " +290keySize + " is not supported");291}292} else { // default parameters will be used.293// Range is based on the values in294// sun.security.provider.ParameterCache class.295if ((keySize > 8192) || (keySize < 512) ||296((keySize & 0x3f) != 0)) {297throw new InvalidAlgorithmParameterException(298"DH key size must be multiple of 64, and can " +299"only range from 512 to 8192 (inclusive). " +300"The specific key size " +301keySize + " is not supported");302}303304DHParameterSpec cache =305ParameterCache.getCachedDHParameterSpec(keySize);306// Except 2048 and 3072, not yet support generation of307// parameters bigger than 1024 bits.308if ((cache == null) && (keySize > 1024)) {309throw new InvalidAlgorithmParameterException(310"Unsupported " + keySize +311"-bit DH parameter generation");312}313}314} else {315// this restriction is in the spec for DSA316if ((keySize != 3072) && (keySize != 2048) &&317((keySize > 1024) || ((keySize & 0x3f) != 0))) {318throw new InvalidAlgorithmParameterException(319"DSA key must be multiples of 64 if less than " +320"1024 bits, or 2048, 3072 bits. " +321"The specific key size " +322keySize + " is not supported");323}324}325}326}327328// see JCA spec329@Override330public KeyPair generateKeyPair() {331token.ensureValid();332CK_ATTRIBUTE[] publicKeyTemplate;333CK_ATTRIBUTE[] privateKeyTemplate;334long keyType;335if (algorithm.equals("RSA")) {336keyType = CKK_RSA;337publicKeyTemplate = new CK_ATTRIBUTE[] {338new CK_ATTRIBUTE(CKA_MODULUS_BITS, keySize),339new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, rsaPublicExponent),340};341privateKeyTemplate = new CK_ATTRIBUTE[] {342// empty343};344} else if (algorithm.equals("DSA")) {345keyType = CKK_DSA;346DSAParameterSpec dsaParams;347if (params == null) {348try {349dsaParams = ParameterCache.getDSAParameterSpec350(keySize, random);351} catch (GeneralSecurityException e) {352throw new ProviderException353("Could not generate DSA parameters", e);354}355} else {356dsaParams = (DSAParameterSpec)params;357}358publicKeyTemplate = new CK_ATTRIBUTE[] {359new CK_ATTRIBUTE(CKA_PRIME, dsaParams.getP()),360new CK_ATTRIBUTE(CKA_SUBPRIME, dsaParams.getQ()),361new CK_ATTRIBUTE(CKA_BASE, dsaParams.getG()),362};363privateKeyTemplate = new CK_ATTRIBUTE[] {364// empty365};366} else if (algorithm.equals("DH")) {367keyType = CKK_DH;368DHParameterSpec dhParams;369int privateBits;370if (params == null) {371try {372dhParams = ParameterCache.getDHParameterSpec373(keySize, random);374} catch (GeneralSecurityException e) {375throw new ProviderException376("Could not generate DH parameters", e);377}378privateBits = 0;379} else {380dhParams = (DHParameterSpec)params;381privateBits = dhParams.getL();382}383if (privateBits <= 0) {384// XXX find better defaults385privateBits = (keySize >= 1024) ? 768 : 512;386}387publicKeyTemplate = new CK_ATTRIBUTE[] {388new CK_ATTRIBUTE(CKA_PRIME, dhParams.getP()),389new CK_ATTRIBUTE(CKA_BASE, dhParams.getG())390};391privateKeyTemplate = new CK_ATTRIBUTE[] {392new CK_ATTRIBUTE(CKA_VALUE_BITS, privateBits),393};394} else if (algorithm.equals("EC")) {395keyType = CKK_EC;396byte[] encodedParams =397P11ECKeyFactory.encodeParameters((ECParameterSpec)params);398publicKeyTemplate = new CK_ATTRIBUTE[] {399new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams),400};401privateKeyTemplate = new CK_ATTRIBUTE[] {402// empty403};404} else {405throw new ProviderException("Unknown algorithm: " + algorithm);406}407Session session = null;408try {409session = token.getObjSession();410publicKeyTemplate = token.getAttributes411(O_GENERATE, CKO_PUBLIC_KEY, keyType, publicKeyTemplate);412privateKeyTemplate = token.getAttributes413(O_GENERATE, CKO_PRIVATE_KEY, keyType, privateKeyTemplate);414long[] keyIDs = token.p11.C_GenerateKeyPair415(session.id(), new CK_MECHANISM(mechanism),416publicKeyTemplate, privateKeyTemplate);417PublicKey publicKey = P11Key.publicKey418(session, keyIDs[0], algorithm, keySize, publicKeyTemplate);419PrivateKey privateKey = P11Key.privateKey420(session, keyIDs[1], algorithm, keySize, privateKeyTemplate);421return new KeyPair(publicKey, privateKey);422} catch (PKCS11Exception e) {423throw new ProviderException(e);424} finally {425token.releaseSession(session);426}427}428}429430431