Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
41154 views
/*1* Copyright (c) 2003, 2019, 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 mechanism info is unavailable, 0/Integer.MAX_VALUE is used76private 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 = 0;86int maxKeyLen = Integer.MAX_VALUE;87try {88CK_MECHANISM_INFO mechInfo = token.getMechanismInfo(mechanism);89if (mechInfo != null) {90minKeyLen = mechInfo.iMinKeySize;91maxKeyLen = mechInfo.iMaxKeySize;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 < 112) {104minKeyLen = 112;105}106if (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;114if (maxKeyLen > 64 * 1024) {115maxKeyLen = 64 * 1024;116}117} else {118keySize = DEF_DH_KEY_SIZE;119}120if (minKeyLen < 512) {121minKeyLen = 512;122}123}124125// auto-adjust default keysize in case it's out-of-range126if (keySize < minKeyLen) {127keySize = minKeyLen;128}129if (keySize > maxKeyLen) {130keySize = maxKeyLen;131}132this.token = token;133this.algorithm = algorithm;134this.mechanism = mechanism;135this.minKeySize = minKeyLen;136this.maxKeySize = maxKeyLen;137initialize(keySize, null);138}139140// see JCA spec141@Override142public void initialize(int keySize, SecureRandom random) {143token.ensureValid();144try {145checkKeySize(keySize, null);146} catch (InvalidAlgorithmParameterException e) {147throw new InvalidParameterException(e.getMessage());148}149this.params = null;150if (algorithm.equals("EC")) {151params = P11ECKeyFactory.getECParameterSpec(keySize);152if (params == null) {153throw new InvalidParameterException(154"No EC parameters available for key size "155+ keySize + " bits");156}157}158this.keySize = keySize;159this.random = random;160}161162// see JCA spec163@Override164public void initialize(AlgorithmParameterSpec params, SecureRandom random)165throws InvalidAlgorithmParameterException {166token.ensureValid();167int tmpKeySize;168if (algorithm.equals("DH")) {169if (params instanceof DHParameterSpec == false) {170throw new InvalidAlgorithmParameterException171("DHParameterSpec required for Diffie-Hellman");172}173DHParameterSpec dhParams = (DHParameterSpec) params;174tmpKeySize = dhParams.getP().bitLength();175checkKeySize(tmpKeySize, dhParams);176// XXX sanity check params177} else if (algorithm.equals("RSA")) {178if (params instanceof RSAKeyGenParameterSpec == false) {179throw new InvalidAlgorithmParameterException180("RSAKeyGenParameterSpec required for RSA");181}182RSAKeyGenParameterSpec rsaParams =183(RSAKeyGenParameterSpec) params;184tmpKeySize = rsaParams.getKeysize();185checkKeySize(tmpKeySize, rsaParams);186// override the supplied params to null187params = null;188this.rsaPublicExponent = rsaParams.getPublicExponent();189// XXX sanity check params190} else if (algorithm.equals("DSA")) {191if (params instanceof DSAParameterSpec == false) {192throw new InvalidAlgorithmParameterException193("DSAParameterSpec required for DSA");194}195DSAParameterSpec dsaParams = (DSAParameterSpec) params;196tmpKeySize = dsaParams.getP().bitLength();197checkKeySize(tmpKeySize, dsaParams);198// XXX sanity check params199} else if (algorithm.equals("EC")) {200ECParameterSpec ecParams;201if (params instanceof ECParameterSpec) {202ecParams = P11ECKeyFactory.getECParameterSpec(203(ECParameterSpec)params);204if (ecParams == null) {205throw new InvalidAlgorithmParameterException206("Unsupported curve: " + params);207}208} else if (params instanceof ECGenParameterSpec) {209String name = ((ECGenParameterSpec) params).getName();210ecParams = P11ECKeyFactory.getECParameterSpec(name);211if (ecParams == null) {212throw new InvalidAlgorithmParameterException213("Unknown curve name: " + name);214}215// override the supplied params with the derived one216params = ecParams;217} else {218throw new InvalidAlgorithmParameterException219("ECParameterSpec or ECGenParameterSpec required for EC");220}221tmpKeySize = ecParams.getCurve().getField().getFieldSize();222checkKeySize(tmpKeySize, ecParams);223} else {224throw new ProviderException("Unknown algorithm: " + algorithm);225}226this.keySize = tmpKeySize;227this.params = params;228this.random = random;229}230231private void checkKeySize(int keySize, AlgorithmParameterSpec params)232throws InvalidAlgorithmParameterException {233if (keySize <= 0) {234throw new InvalidAlgorithmParameterException235("key size must be positive, got " + keySize);236}237// check native range first238if (keySize < minKeySize) {239throw new InvalidAlgorithmParameterException(algorithm +240" key must be at least " + minKeySize + " bits. " +241"The specific key size " + keySize + " is not supported");242}243if (keySize > maxKeySize) {244throw new InvalidAlgorithmParameterException(algorithm +245" key must be at most " + maxKeySize + " bits. " +246"The specific key size " + keySize + " is not supported");247}248249// check our own algorithm-specific limits also250if (algorithm.equals("EC")) {251if (keySize < 112) {252throw new InvalidAlgorithmParameterException(253"EC key size must be at least 112 bit. " +254"The specific key size " + keySize + " is not supported");255}256if (keySize > 2048) {257// sanity check, nobody really wants keys this large258throw new InvalidAlgorithmParameterException(259"EC key size must be at most 2048 bit. " +260"The specific key size " + keySize + " is not supported");261}262} else {263// RSA, DH, DSA264if (keySize < 512) {265throw new InvalidAlgorithmParameterException(algorithm +266" key size must be at least 512 bit. " +267"The specific key size " + keySize + " is not supported");268}269if (algorithm.equals("RSA")) {270BigInteger tmpExponent = rsaPublicExponent;271if (params != null) {272tmpExponent =273((RSAKeyGenParameterSpec)params).getPublicExponent();274}275try {276RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,277minKeySize, maxKeySize);278} catch (InvalidKeyException e) {279throw new InvalidAlgorithmParameterException(e);280}281} else if (algorithm.equals("DH")) {282if (params != null) { // initialized with specified parameters283// sanity check, nobody really wants keys this large284if (keySize > 64 * 1024) {285throw new InvalidAlgorithmParameterException(286"DH key size must be at most 65536 bit. " +287"The specific key size " +288keySize + " is not supported");289}290} else { // default parameters will be used.291// Range is based on the values in292// sun.security.provider.ParameterCache class.293if ((keySize > 8192) || (keySize < 512) ||294((keySize & 0x3f) != 0)) {295throw new InvalidAlgorithmParameterException(296"DH key size must be multiple of 64, and can " +297"only range from 512 to 8192 (inclusive). " +298"The specific key size " +299keySize + " is not supported");300}301302DHParameterSpec cache =303ParameterCache.getCachedDHParameterSpec(keySize);304// Except 2048 and 3072, not yet support generation of305// parameters bigger than 1024 bits.306if ((cache == null) && (keySize > 1024)) {307throw new InvalidAlgorithmParameterException(308"Unsupported " + keySize +309"-bit DH parameter generation");310}311}312} else {313// this restriction is in the spec for DSA314if ((keySize != 3072) && (keySize != 2048) &&315((keySize > 1024) || ((keySize & 0x3f) != 0))) {316throw new InvalidAlgorithmParameterException(317"DSA key must be multiples of 64 if less than " +318"1024 bits, or 2048, 3072 bits. " +319"The specific key size " +320keySize + " is not supported");321}322}323}324}325326// see JCA spec327@Override328public KeyPair generateKeyPair() {329token.ensureValid();330CK_ATTRIBUTE[] publicKeyTemplate;331CK_ATTRIBUTE[] privateKeyTemplate;332long keyType;333if (algorithm.equals("RSA")) {334keyType = CKK_RSA;335publicKeyTemplate = new CK_ATTRIBUTE[] {336new CK_ATTRIBUTE(CKA_MODULUS_BITS, keySize),337new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, rsaPublicExponent),338};339privateKeyTemplate = new CK_ATTRIBUTE[] {340// empty341};342} else if (algorithm.equals("DSA")) {343keyType = CKK_DSA;344DSAParameterSpec dsaParams;345if (params == null) {346try {347dsaParams = ParameterCache.getDSAParameterSpec348(keySize, random);349} catch (GeneralSecurityException e) {350throw new ProviderException351("Could not generate DSA parameters", e);352}353} else {354dsaParams = (DSAParameterSpec)params;355}356publicKeyTemplate = new CK_ATTRIBUTE[] {357new CK_ATTRIBUTE(CKA_PRIME, dsaParams.getP()),358new CK_ATTRIBUTE(CKA_SUBPRIME, dsaParams.getQ()),359new CK_ATTRIBUTE(CKA_BASE, dsaParams.getG()),360};361privateKeyTemplate = new CK_ATTRIBUTE[] {362// empty363};364} else if (algorithm.equals("DH")) {365keyType = CKK_DH;366DHParameterSpec dhParams;367int privateBits;368if (params == null) {369try {370dhParams = ParameterCache.getDHParameterSpec371(keySize, random);372} catch (GeneralSecurityException e) {373throw new ProviderException374("Could not generate DH parameters", e);375}376privateBits = 0;377} else {378dhParams = (DHParameterSpec)params;379privateBits = dhParams.getL();380}381if (privateBits <= 0) {382// XXX find better defaults383privateBits = (keySize >= 1024) ? 768 : 512;384}385publicKeyTemplate = new CK_ATTRIBUTE[] {386new CK_ATTRIBUTE(CKA_PRIME, dhParams.getP()),387new CK_ATTRIBUTE(CKA_BASE, dhParams.getG())388};389privateKeyTemplate = new CK_ATTRIBUTE[] {390new CK_ATTRIBUTE(CKA_VALUE_BITS, privateBits),391};392} else if (algorithm.equals("EC")) {393keyType = CKK_EC;394byte[] encodedParams =395P11ECKeyFactory.encodeParameters((ECParameterSpec)params);396publicKeyTemplate = new CK_ATTRIBUTE[] {397new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams),398};399privateKeyTemplate = new CK_ATTRIBUTE[] {400// empty401};402} else {403throw new ProviderException("Unknown algorithm: " + algorithm);404}405Session session = null;406try {407session = token.getObjSession();408publicKeyTemplate = token.getAttributes409(O_GENERATE, CKO_PUBLIC_KEY, keyType, publicKeyTemplate);410privateKeyTemplate = token.getAttributes411(O_GENERATE, CKO_PRIVATE_KEY, keyType, privateKeyTemplate);412long[] keyIDs = token.p11.C_GenerateKeyPair413(session.id(), new CK_MECHANISM(mechanism),414publicKeyTemplate, privateKeyTemplate);415PublicKey publicKey = P11Key.publicKey416(session, keyIDs[0], algorithm, keySize, publicKeyTemplate);417PrivateKey privateKey = P11Key.privateKey418(session, keyIDs[1], algorithm, keySize, privateKeyTemplate);419return new KeyPair(publicKey, privateKey);420} catch (PKCS11Exception e) {421throw new ProviderException(e);422} finally {423token.releaseSession(session);424}425}426}427428429