Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java
41154 views
/*1* Copyright (c) 2003, 2020, 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.security.*;28import java.security.spec.AlgorithmParameterSpec;29import java.security.spec.*;3031import java.util.Locale;3233import javax.crypto.*;34import javax.crypto.spec.*;3536import static sun.security.pkcs11.TemplateManager.*;37import sun.security.pkcs11.wrapper.*;38import static sun.security.pkcs11.wrapper.PKCS11Constants.*;39import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;40import sun.security.util.KeyUtil;4142/**43* RSA Cipher implementation class. We currently only support44* PKCS#1 v1.5 padding on top of CKM_RSA_PKCS.45*46* @author Andreas Sterbenz47* @since 1.548*/49final class P11RSACipher extends CipherSpi {5051// minimum length of PKCS#1 v1.5 padding52private static final int PKCS1_MIN_PADDING_LENGTH = 11;5354// constant byte[] of length 055private static final byte[] B0 = new byte[0];5657// mode constant for public key encryption58private static final int MODE_ENCRYPT = 1;59// mode constant for private key decryption60private static final int MODE_DECRYPT = 2;61// mode constant for private key encryption (signing)62private static final int MODE_SIGN = 3;63// mode constant for public key decryption (verifying)64private static final int MODE_VERIFY = 4;6566// padding type constant for NoPadding67private static final int PAD_NONE = 1;68// padding type constant for PKCS1Padding69private static final int PAD_PKCS1 = 2;7071// token instance72private final Token token;7374// algorithm name (always "RSA")75private final String algorithm;7677// mechanism id78private final long mechanism;7980// associated session, if any81private Session session;8283// mode, one of MODE_* above84private int mode;8586// padding, one of PAD_* above87private int padType;8889private byte[] buffer;90private int bufOfs;9192// key, if init() was called93private P11Key p11Key;9495// flag indicating whether an operation is initialized96private boolean initialized;9798// maximum input data size allowed99// for decryption, this is the length of the key100// for encryption, length of the key minus minimum padding length101private int maxInputSize;102103// maximum output size. this is the length of the key104private int outputSize;105106// cipher parameter for TLS RSA premaster secret107private AlgorithmParameterSpec spec = null;108109// the source of randomness110private SecureRandom random;111112P11RSACipher(Token token, String algorithm, long mechanism)113throws PKCS11Exception {114super();115this.token = token;116this.algorithm = "RSA";117this.mechanism = mechanism;118}119120// modes do not make sense for RSA, but allow ECB121// see JCE spec122protected void engineSetMode(String mode) throws NoSuchAlgorithmException {123if (mode.equalsIgnoreCase("ECB") == false) {124throw new NoSuchAlgorithmException("Unsupported mode " + mode);125}126}127128protected void engineSetPadding(String padding)129throws NoSuchPaddingException {130String lowerPadding = padding.toLowerCase(Locale.ENGLISH);131if (lowerPadding.equals("pkcs1padding")) {132padType = PAD_PKCS1;133} else if (lowerPadding.equals("nopadding")) {134padType = PAD_NONE;135} else {136throw new NoSuchPaddingException("Unsupported padding " + padding);137}138}139140// return 0 as block size, we are not a block cipher141// see JCE spec142protected int engineGetBlockSize() {143return 0;144}145146// return the output size147// see JCE spec148protected int engineGetOutputSize(int inputLen) {149return outputSize;150}151152// no IV, return null153// see JCE spec154protected byte[] engineGetIV() {155return null;156}157158// no parameters, return null159// see JCE spec160protected AlgorithmParameters engineGetParameters() {161return null;162}163164// see JCE spec165protected void engineInit(int opmode, Key key, SecureRandom random)166throws InvalidKeyException {167implInit(opmode, key);168}169170// see JCE spec171@SuppressWarnings("deprecation")172protected void engineInit(int opmode, Key key,173AlgorithmParameterSpec params, SecureRandom random)174throws InvalidKeyException, InvalidAlgorithmParameterException {175if (params != null) {176if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {177throw new InvalidAlgorithmParameterException(178"Parameters not supported");179}180spec = params;181this.random = random; // for TLS RSA premaster secret182}183implInit(opmode, key);184}185186// see JCE spec187protected void engineInit(int opmode, Key key, AlgorithmParameters params,188SecureRandom random)189throws InvalidKeyException, InvalidAlgorithmParameterException {190if (params != null) {191throw new InvalidAlgorithmParameterException(192"Parameters not supported");193}194implInit(opmode, key);195}196197private void implInit(int opmode, Key key) throws InvalidKeyException {198reset(true);199p11Key = P11KeyFactory.convertKey(token, key, algorithm);200boolean encrypt;201if (opmode == Cipher.ENCRYPT_MODE) {202encrypt = true;203} else if (opmode == Cipher.DECRYPT_MODE) {204encrypt = false;205} else if (opmode == Cipher.WRAP_MODE) {206if (p11Key.isPublic() == false) {207throw new InvalidKeyException208("Wrap has to be used with public keys");209}210// No further setup needed for C_Wrap(). We'll initialize later if211// we can't use C_Wrap().212return;213} else if (opmode == Cipher.UNWRAP_MODE) {214if (p11Key.isPrivate() == false) {215throw new InvalidKeyException216("Unwrap has to be used with private keys");217}218// No further setup needed for C_Unwrap(). We'll initialize later219// if we can't use C_Unwrap().220return;221} else {222throw new InvalidKeyException("Unsupported mode: " + opmode);223}224if (p11Key.isPublic()) {225mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;226} else if (p11Key.isPrivate()) {227mode = encrypt ? MODE_SIGN : MODE_DECRYPT;228} else {229throw new InvalidKeyException("Unknown key type: " + p11Key);230}231int n = (p11Key.length() + 7) >> 3;232outputSize = n;233buffer = new byte[n];234maxInputSize = ((padType == PAD_PKCS1 && encrypt) ?235(n - PKCS1_MIN_PADDING_LENGTH) : n);236try {237initialize();238} catch (PKCS11Exception e) {239throw new InvalidKeyException("init() failed", e);240}241}242243// reset the states to the pre-initialized values244private void reset(boolean doCancel) {245if (!initialized) {246return;247}248initialized = false;249250try {251if (session == null) {252return;253}254255if (doCancel && token.explicitCancel) {256cancelOperation();257}258} finally {259p11Key.releaseKeyID();260session = token.releaseSession(session);261}262}263264// should only called by reset as this method does not update other265// state variables such as "initialized"266private void cancelOperation() {267token.ensureValid();268// cancel operation by finishing it; avoid killSession as some269// hardware vendors may require re-login270try {271PKCS11 p11 = token.p11;272int inLen = maxInputSize;273int outLen = buffer.length;274long sessId = session.id();275switch (mode) {276case MODE_ENCRYPT:277p11.C_Encrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);278break;279case MODE_DECRYPT:280p11.C_Decrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);281break;282case MODE_SIGN:283byte[] tmpBuffer = new byte[maxInputSize];284p11.C_Sign(sessId, tmpBuffer);285break;286case MODE_VERIFY:287p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer,2880, outLen);289break;290default:291throw new ProviderException("internal error");292}293} catch (PKCS11Exception e) {294// XXX ensure this always works, ignore error295}296}297298private void ensureInitialized() throws PKCS11Exception {299token.ensureValid();300if (!initialized) {301initialize();302}303}304305private void initialize() throws PKCS11Exception {306if (p11Key == null) {307throw new ProviderException(308"Operation cannot be performed without " +309"calling engineInit first");310}311long keyID = p11Key.getKeyID();312try {313if (session == null) {314session = token.getOpSession();315}316PKCS11 p11 = token.p11;317CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism);318switch (mode) {319case MODE_ENCRYPT:320p11.C_EncryptInit(session.id(), ckMechanism, keyID);321break;322case MODE_DECRYPT:323p11.C_DecryptInit(session.id(), ckMechanism, keyID);324break;325case MODE_SIGN:326p11.C_SignInit(session.id(), ckMechanism, keyID);327break;328case MODE_VERIFY:329p11.C_VerifyRecoverInit(session.id(), ckMechanism, keyID);330break;331default:332throw new AssertionError("internal error");333}334bufOfs = 0;335initialized = true;336} catch (PKCS11Exception e) {337p11Key.releaseKeyID();338session = token.releaseSession(session);339throw e;340}341}342343private void implUpdate(byte[] in, int inOfs, int inLen) {344try {345ensureInitialized();346} catch (PKCS11Exception e) {347throw new ProviderException("update() failed", e);348}349if ((inLen == 0) || (in == null)) {350return;351}352if (bufOfs + inLen > maxInputSize) {353bufOfs = maxInputSize + 1;354return;355}356System.arraycopy(in, inOfs, buffer, bufOfs, inLen);357bufOfs += inLen;358}359360private int implDoFinal(byte[] out, int outOfs, int outLen)361throws BadPaddingException, IllegalBlockSizeException {362if (bufOfs > maxInputSize) {363reset(true);364throw new IllegalBlockSizeException("Data must not be longer "365+ "than " + maxInputSize + " bytes");366}367try {368ensureInitialized();369PKCS11 p11 = token.p11;370int n;371switch (mode) {372case MODE_ENCRYPT:373n = p11.C_Encrypt374(session.id(), 0, buffer, 0, bufOfs, 0, out, outOfs, outLen);375break;376case MODE_DECRYPT:377n = p11.C_Decrypt378(session.id(), 0, buffer, 0, bufOfs, 0, out, outOfs, outLen);379break;380case MODE_SIGN:381byte[] tmpBuffer = new byte[bufOfs];382System.arraycopy(buffer, 0, tmpBuffer, 0, bufOfs);383tmpBuffer = p11.C_Sign(session.id(), tmpBuffer);384if (tmpBuffer.length > outLen) {385throw new BadPaddingException(386"Output buffer (" + outLen + ") is too small to " +387"hold the produced data (" + tmpBuffer.length + ")");388}389System.arraycopy(tmpBuffer, 0, out, outOfs, tmpBuffer.length);390n = tmpBuffer.length;391break;392case MODE_VERIFY:393n = p11.C_VerifyRecover394(session.id(), buffer, 0, bufOfs, out, outOfs, outLen);395break;396default:397throw new ProviderException("internal error");398}399return n;400} catch (PKCS11Exception e) {401throw (BadPaddingException)new BadPaddingException402("doFinal() failed").initCause(e);403} finally {404reset(false);405}406}407408// see JCE spec409protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {410implUpdate(in, inOfs, inLen);411return B0;412}413414// see JCE spec415protected int engineUpdate(byte[] in, int inOfs, int inLen,416byte[] out, int outOfs) throws ShortBufferException {417implUpdate(in, inOfs, inLen);418return 0;419}420421// see JCE spec422protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)423throws IllegalBlockSizeException, BadPaddingException {424implUpdate(in, inOfs, inLen);425int n = implDoFinal(buffer, 0, buffer.length);426byte[] out = new byte[n];427System.arraycopy(buffer, 0, out, 0, n);428return out;429}430431// see JCE spec432protected int engineDoFinal(byte[] in, int inOfs, int inLen,433byte[] out, int outOfs) throws ShortBufferException,434IllegalBlockSizeException, BadPaddingException {435implUpdate(in, inOfs, inLen);436return implDoFinal(out, outOfs, out.length - outOfs);437}438439private byte[] doFinal() throws BadPaddingException,440IllegalBlockSizeException {441byte[] t = new byte[2048];442int n = implDoFinal(t, 0, t.length);443byte[] out = new byte[n];444System.arraycopy(t, 0, out, 0, n);445return out;446}447448// see JCE spec449protected byte[] engineWrap(Key key) throws InvalidKeyException,450IllegalBlockSizeException {451String keyAlg = key.getAlgorithm();452P11Key sKey = null;453try {454// The conversion may fail, e.g. trying to wrap an AES key on455// a token that does not support AES, or when the key size is456// not within the range supported by the token.457sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);458} catch (InvalidKeyException ike) {459byte[] toBeWrappedKey = key.getEncoded();460if (toBeWrappedKey == null) {461throw new InvalidKeyException462("wrap() failed, no encoding available", ike);463}464// Directly encrypt the key encoding when key conversion failed465implInit(Cipher.ENCRYPT_MODE, p11Key);466implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length);467try {468return doFinal();469} catch (BadPaddingException bpe) {470// should not occur471throw new InvalidKeyException("wrap() failed", bpe);472} finally {473// Restore original mode474implInit(Cipher.WRAP_MODE, p11Key);475}476}477Session s = null;478long p11KeyID = p11Key.getKeyID();479long sKeyID = sKey.getKeyID();480try {481s = token.getOpSession();482return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),483p11KeyID, sKeyID);484} catch (PKCS11Exception e) {485throw new InvalidKeyException("wrap() failed", e);486} finally {487p11Key.releaseKeyID();488sKey.releaseKeyID();489token.releaseSession(s);490}491}492493// see JCE spec494@SuppressWarnings("deprecation")495protected Key engineUnwrap(byte[] wrappedKey, String algorithm,496int type) throws InvalidKeyException, NoSuchAlgorithmException {497498boolean isTlsRsaPremasterSecret =499algorithm.equals("TlsRsaPremasterSecret");500Exception failover = null;501502// Should C_Unwrap be preferred for non-TLS RSA premaster secret?503if (token.supportsRawSecretKeyImport()) {504// XXX implement unwrap using C_Unwrap() for all keys505implInit(Cipher.DECRYPT_MODE, p11Key);506try {507if (wrappedKey.length > maxInputSize) {508throw new InvalidKeyException("Key is too long for unwrapping");509}510511byte[] encoded = null;512implUpdate(wrappedKey, 0, wrappedKey.length);513try {514encoded = doFinal();515} catch (BadPaddingException e) {516if (isTlsRsaPremasterSecret) {517failover = e;518} else {519throw new InvalidKeyException("Unwrapping failed", e);520}521} catch (IllegalBlockSizeException e) {522// should not occur, handled with length check above523throw new InvalidKeyException("Unwrapping failed", e);524}525526if (isTlsRsaPremasterSecret) {527if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {528throw new IllegalStateException(529"No TlsRsaPremasterSecretParameterSpec specified");530}531532// polish the TLS premaster secret533TlsRsaPremasterSecretParameterSpec psps =534(TlsRsaPremasterSecretParameterSpec)spec;535encoded = KeyUtil.checkTlsPreMasterSecretKey(536psps.getClientVersion(), psps.getServerVersion(),537random, encoded, (failover != null));538}539540return ConstructKeys.constructKey(encoded, algorithm, type);541} finally {542// Restore original mode543implInit(Cipher.UNWRAP_MODE, p11Key);544}545} else {546Session s = null;547SecretKey secretKey = null;548long p11KeyID = p11Key.getKeyID();549try {550try {551s = token.getObjSession();552long p11KeyType =553P11SecretKeyFactory.getPKCS11KeyType(algorithm);554555CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {556new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),557new CK_ATTRIBUTE(CKA_KEY_TYPE, p11KeyType),558};559attributes = token.getAttributes(560O_IMPORT, CKO_SECRET_KEY, p11KeyType, attributes);561562long keyID = token.p11.C_UnwrapKey(s.id(),563new CK_MECHANISM(mechanism), p11KeyID,564wrappedKey, attributes);565secretKey = P11Key.secretKey(s, keyID,566algorithm, 48 << 3, attributes);567} catch (PKCS11Exception e) {568if (isTlsRsaPremasterSecret) {569failover = e;570} else {571throw new InvalidKeyException("unwrap() failed", e);572}573}574575if (isTlsRsaPremasterSecret) {576TlsRsaPremasterSecretParameterSpec psps =577(TlsRsaPremasterSecretParameterSpec)spec;578579// Please use the tricky failover as the parameter so that580// smart compiler won't dispose the unused variable.581secretKey = polishPreMasterSecretKey(token, s,582failover, secretKey,583psps.getClientVersion(), psps.getServerVersion());584}585586return secretKey;587} finally {588p11Key.releaseKeyID();589token.releaseSession(s);590}591}592}593594// see JCE spec595protected int engineGetKeySize(Key key) throws InvalidKeyException {596int n = P11KeyFactory.convertKey(token, key, algorithm).length();597return n;598}599600private static SecretKey polishPreMasterSecretKey(601Token token, Session session,602Exception failover, SecretKey unwrappedKey,603int clientVersion, int serverVersion) {604605SecretKey newKey;606CK_VERSION version = new CK_VERSION(607(clientVersion >>> 8) & 0xFF, clientVersion & 0xFF);608try {609CK_ATTRIBUTE[] attributes = token.getAttributes(610O_GENERATE, CKO_SECRET_KEY,611CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]);612long keyID = token.p11.C_GenerateKey(session.id(),613new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version),614attributes);615newKey = P11Key.secretKey(session,616keyID, "TlsRsaPremasterSecret", 48 << 3, attributes);617} catch (PKCS11Exception e) {618throw new ProviderException(619"Could not generate premaster secret", e);620}621622return (failover == null) ? unwrappedKey : newKey;623}624625}626627final class ConstructKeys {628/**629* Construct a public key from its encoding.630*631* @param encodedKey the encoding of a public key.632*633* @param encodedKeyAlgorithm the algorithm the encodedKey is for.634*635* @return a public key constructed from the encodedKey.636*/637private static final PublicKey constructPublicKey(byte[] encodedKey,638String encodedKeyAlgorithm)639throws InvalidKeyException, NoSuchAlgorithmException {640try {641KeyFactory keyFactory =642KeyFactory.getInstance(encodedKeyAlgorithm);643X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);644return keyFactory.generatePublic(keySpec);645} catch (NoSuchAlgorithmException nsae) {646throw new NoSuchAlgorithmException("No installed providers " +647"can create keys for the " +648encodedKeyAlgorithm +649"algorithm", nsae);650} catch (InvalidKeySpecException ike) {651throw new InvalidKeyException("Cannot construct public key", ike);652}653}654655/**656* Construct a private key from its encoding.657*658* @param encodedKey the encoding of a private key.659*660* @param encodedKeyAlgorithm the algorithm the wrapped key is for.661*662* @return a private key constructed from the encodedKey.663*/664private static final PrivateKey constructPrivateKey(byte[] encodedKey,665String encodedKeyAlgorithm) throws InvalidKeyException,666NoSuchAlgorithmException {667try {668KeyFactory keyFactory =669KeyFactory.getInstance(encodedKeyAlgorithm);670PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);671return keyFactory.generatePrivate(keySpec);672} catch (NoSuchAlgorithmException nsae) {673throw new NoSuchAlgorithmException("No installed providers " +674"can create keys for the " +675encodedKeyAlgorithm +676"algorithm", nsae);677} catch (InvalidKeySpecException ike) {678throw new InvalidKeyException("Cannot construct private key", ike);679}680}681682/**683* Construct a secret key from its encoding.684*685* @param encodedKey the encoding of a secret key.686*687* @param encodedKeyAlgorithm the algorithm the secret key is for.688*689* @return a secret key constructed from the encodedKey.690*/691private static final SecretKey constructSecretKey(byte[] encodedKey,692String encodedKeyAlgorithm) {693return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);694}695696static final Key constructKey(byte[] encoding, String keyAlgorithm,697int keyType) throws InvalidKeyException, NoSuchAlgorithmException {698switch (keyType) {699case Cipher.SECRET_KEY:700return constructSecretKey(encoding, keyAlgorithm);701case Cipher.PRIVATE_KEY:702return constructPrivateKey(encoding, keyAlgorithm);703case Cipher.PUBLIC_KEY:704return constructPublicKey(encoding, keyAlgorithm);705default:706throw new InvalidKeyException("Unknown keytype " + keyType);707}708}709}710711712