Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java
38919 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 final static int PKCS1_MIN_PADDING_LENGTH = 11;5354// constant byte[] of length 055private final static byte[] B0 = new byte[0];5657// mode constant for public key encryption58private final static int MODE_ENCRYPT = 1;59// mode constant for private key decryption60private final static int MODE_DECRYPT = 2;61// mode constant for private key encryption (signing)62private final static int MODE_SIGN = 3;63// mode constant for public key decryption (verifying)64private final static int MODE_VERIFY = 4;6566// padding type constant for NoPadding67private final static int PAD_NONE = 1;68// padding type constant for PKCS1Padding69private final static 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 spec171protected void engineInit(int opmode, Key key,172AlgorithmParameterSpec params, SecureRandom random)173throws InvalidKeyException, InvalidAlgorithmParameterException {174if (params != null) {175if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {176throw new InvalidAlgorithmParameterException(177"Parameters not supported");178}179spec = params;180this.random = random; // for TLS RSA premaster secret181}182implInit(opmode, key);183}184185// see JCE spec186protected void engineInit(int opmode, Key key, AlgorithmParameters params,187SecureRandom random)188throws InvalidKeyException, InvalidAlgorithmParameterException {189if (params != null) {190throw new InvalidAlgorithmParameterException(191"Parameters not supported");192}193implInit(opmode, key);194}195196private void implInit(int opmode, Key key) throws InvalidKeyException {197reset(true);198p11Key = P11KeyFactory.convertKey(token, key, algorithm);199boolean encrypt;200if (opmode == Cipher.ENCRYPT_MODE) {201encrypt = true;202} else if (opmode == Cipher.DECRYPT_MODE) {203encrypt = false;204} else if (opmode == Cipher.WRAP_MODE) {205if (p11Key.isPublic() == false) {206throw new InvalidKeyException207("Wrap has to be used with public keys");208}209// No further setup needed for C_Wrap(). We'll initialize later if210// we can't use C_Wrap().211return;212} else if (opmode == Cipher.UNWRAP_MODE) {213if (p11Key.isPrivate() == false) {214throw new InvalidKeyException215("Unwrap has to be used with private keys");216}217// No further setup needed for C_Unwrap(). We'll initialize later218// if we can't use C_Unwrap().219return;220} else {221throw new InvalidKeyException("Unsupported mode: " + opmode);222}223if (p11Key.isPublic()) {224mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;225} else if (p11Key.isPrivate()) {226mode = encrypt ? MODE_SIGN : MODE_DECRYPT;227} else {228throw new InvalidKeyException("Unknown key type: " + p11Key);229}230int n = (p11Key.length() + 7) >> 3;231outputSize = n;232buffer = new byte[n];233maxInputSize = ((padType == PAD_PKCS1 && encrypt) ?234(n - PKCS1_MIN_PADDING_LENGTH) : n);235try {236initialize();237} catch (PKCS11Exception e) {238throw new InvalidKeyException("init() failed", e);239}240}241242// reset the states to the pre-initialized values243private void reset(boolean doCancel) {244if (!initialized) {245return;246}247initialized = false;248249try {250if (session == null) {251return;252}253254if (doCancel && token.explicitCancel) {255cancelOperation();256}257} finally {258p11Key.releaseKeyID();259session = token.releaseSession(session);260}261}262263// should only called by reset as this method does not update other264// state variables such as "initialized"265private void cancelOperation() {266token.ensureValid();267// cancel operation by finishing it; avoid killSession as some268// hardware vendors may require re-login269try {270PKCS11 p11 = token.p11;271int inLen = maxInputSize;272int outLen = buffer.length;273long sessId = session.id();274switch (mode) {275case MODE_ENCRYPT:276p11.C_Encrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);277break;278case MODE_DECRYPT:279p11.C_Decrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);280break;281case MODE_SIGN:282byte[] tmpBuffer = new byte[maxInputSize];283p11.C_Sign(sessId, tmpBuffer);284break;285case MODE_VERIFY:286p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer,2870, outLen);288break;289default:290throw new ProviderException("internal error");291}292} catch (PKCS11Exception e) {293// XXX ensure this always works, ignore error294}295}296297private void ensureInitialized() throws PKCS11Exception {298token.ensureValid();299if (!initialized) {300initialize();301}302}303304private void initialize() throws PKCS11Exception {305if (p11Key == null) {306throw new ProviderException(307"Operation cannot be performed without " +308"calling engineInit first");309}310long keyID = p11Key.getKeyID();311try {312if (session == null) {313session = token.getOpSession();314}315PKCS11 p11 = token.p11;316CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism);317switch (mode) {318case MODE_ENCRYPT:319p11.C_EncryptInit(session.id(), ckMechanism, keyID);320break;321case MODE_DECRYPT:322p11.C_DecryptInit(session.id(), ckMechanism, keyID);323break;324case MODE_SIGN:325p11.C_SignInit(session.id(), ckMechanism, keyID);326break;327case MODE_VERIFY:328p11.C_VerifyRecoverInit(session.id(), ckMechanism, keyID);329break;330default:331throw new AssertionError("internal error");332}333bufOfs = 0;334initialized = true;335} catch (PKCS11Exception e) {336p11Key.releaseKeyID();337session = token.releaseSession(session);338throw e;339}340}341342private void implUpdate(byte[] in, int inOfs, int inLen) {343try {344ensureInitialized();345} catch (PKCS11Exception e) {346throw new ProviderException("update() failed", e);347}348if ((inLen == 0) || (in == null)) {349return;350}351if (bufOfs + inLen > maxInputSize) {352bufOfs = maxInputSize + 1;353return;354}355System.arraycopy(in, inOfs, buffer, bufOfs, inLen);356bufOfs += inLen;357}358359private int implDoFinal(byte[] out, int outOfs, int outLen)360throws BadPaddingException, IllegalBlockSizeException {361if (bufOfs > maxInputSize) {362reset(true);363throw new IllegalBlockSizeException("Data must not be longer "364+ "than " + maxInputSize + " bytes");365}366try {367ensureInitialized();368PKCS11 p11 = token.p11;369int n;370switch (mode) {371case MODE_ENCRYPT:372n = p11.C_Encrypt373(session.id(), 0, buffer, 0, bufOfs, 0, out, outOfs, outLen);374break;375case MODE_DECRYPT:376n = p11.C_Decrypt377(session.id(), 0, buffer, 0, bufOfs, 0, out, outOfs, outLen);378break;379case MODE_SIGN:380byte[] tmpBuffer = new byte[bufOfs];381System.arraycopy(buffer, 0, tmpBuffer, 0, bufOfs);382tmpBuffer = p11.C_Sign(session.id(), tmpBuffer);383if (tmpBuffer.length > outLen) {384throw new BadPaddingException(385"Output buffer (" + outLen + ") is too small to " +386"hold the produced data (" + tmpBuffer.length + ")");387}388System.arraycopy(tmpBuffer, 0, out, outOfs, tmpBuffer.length);389n = tmpBuffer.length;390break;391case MODE_VERIFY:392n = p11.C_VerifyRecover393(session.id(), buffer, 0, bufOfs, out, outOfs, outLen);394break;395default:396throw new ProviderException("internal error");397}398return n;399} catch (PKCS11Exception e) {400throw (BadPaddingException)new BadPaddingException401("doFinal() failed").initCause(e);402} finally {403reset(false);404}405}406407// see JCE spec408protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {409implUpdate(in, inOfs, inLen);410return B0;411}412413// see JCE spec414protected int engineUpdate(byte[] in, int inOfs, int inLen,415byte[] out, int outOfs) throws ShortBufferException {416implUpdate(in, inOfs, inLen);417return 0;418}419420// see JCE spec421protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)422throws IllegalBlockSizeException, BadPaddingException {423implUpdate(in, inOfs, inLen);424int n = implDoFinal(buffer, 0, buffer.length);425byte[] out = new byte[n];426System.arraycopy(buffer, 0, out, 0, n);427return out;428}429430// see JCE spec431protected int engineDoFinal(byte[] in, int inOfs, int inLen,432byte[] out, int outOfs) throws ShortBufferException,433IllegalBlockSizeException, BadPaddingException {434implUpdate(in, inOfs, inLen);435return implDoFinal(out, outOfs, out.length - outOfs);436}437438private byte[] doFinal() throws BadPaddingException,439IllegalBlockSizeException {440byte[] t = new byte[2048];441int n = implDoFinal(t, 0, t.length);442byte[] out = new byte[n];443System.arraycopy(t, 0, out, 0, n);444return out;445}446447// see JCE spec448protected byte[] engineWrap(Key key) throws InvalidKeyException,449IllegalBlockSizeException {450String keyAlg = key.getAlgorithm();451P11Key sKey = null;452try {453// The conversion may fail, e.g. trying to wrap an AES key on454// a token that does not support AES, or when the key size is455// not within the range supported by the token.456sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);457} catch (InvalidKeyException ike) {458byte[] toBeWrappedKey = key.getEncoded();459if (toBeWrappedKey == null) {460throw new InvalidKeyException461("wrap() failed, no encoding available", ike);462}463// Directly encrypt the key encoding when key conversion failed464implInit(Cipher.ENCRYPT_MODE, p11Key);465implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length);466try {467return doFinal();468} catch (BadPaddingException bpe) {469// should not occur470throw new InvalidKeyException("wrap() failed", bpe);471} finally {472// Restore original mode473implInit(Cipher.WRAP_MODE, p11Key);474}475}476Session s = null;477long p11KeyID = p11Key.getKeyID();478long sKeyID = sKey.getKeyID();479try {480s = token.getOpSession();481return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),482p11KeyID, sKeyID);483} catch (PKCS11Exception e) {484throw new InvalidKeyException("wrap() failed", e);485} finally {486p11Key.releaseKeyID();487sKey.releaseKeyID();488token.releaseSession(s);489}490}491492// see JCE spec493protected Key engineUnwrap(byte[] wrappedKey, String algorithm,494int type) throws InvalidKeyException, NoSuchAlgorithmException {495496boolean isTlsRsaPremasterSecret =497algorithm.equals("TlsRsaPremasterSecret");498Exception failover = null;499500// Should C_Unwrap be preferred for non-TLS RSA premaster secret?501if (token.supportsRawSecretKeyImport()) {502// XXX implement unwrap using C_Unwrap() for all keys503implInit(Cipher.DECRYPT_MODE, p11Key);504try {505if (wrappedKey.length > maxInputSize) {506throw new InvalidKeyException("Key is too long for unwrapping");507}508509byte[] encoded = null;510implUpdate(wrappedKey, 0, wrappedKey.length);511try {512encoded = doFinal();513} catch (BadPaddingException e) {514if (isTlsRsaPremasterSecret) {515failover = e;516} else {517throw new InvalidKeyException("Unwrapping failed", e);518}519} catch (IllegalBlockSizeException e) {520// should not occur, handled with length check above521throw new InvalidKeyException("Unwrapping failed", e);522}523524if (isTlsRsaPremasterSecret) {525if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {526throw new IllegalStateException(527"No TlsRsaPremasterSecretParameterSpec specified");528}529530// polish the TLS premaster secret531TlsRsaPremasterSecretParameterSpec psps =532(TlsRsaPremasterSecretParameterSpec)spec;533encoded = KeyUtil.checkTlsPreMasterSecretKey(534psps.getClientVersion(), psps.getServerVersion(),535random, encoded, (failover != null));536}537538return ConstructKeys.constructKey(encoded, algorithm, type);539} finally {540// Restore original mode541implInit(Cipher.UNWRAP_MODE, p11Key);542}543} else {544Session s = null;545SecretKey secretKey = null;546long p11KeyID = p11Key.getKeyID();547try {548try {549s = token.getObjSession();550long keyType = CKK_GENERIC_SECRET;551CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {552new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),553new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),554};555attributes = token.getAttributes(556O_IMPORT, CKO_SECRET_KEY, keyType, attributes);557558long keyID = token.p11.C_UnwrapKey(s.id(),559new CK_MECHANISM(mechanism), p11KeyID,560wrappedKey, attributes);561secretKey = P11Key.secretKey(s, keyID,562algorithm, 48 << 3, attributes);563} catch (PKCS11Exception e) {564if (isTlsRsaPremasterSecret) {565failover = e;566} else {567throw new InvalidKeyException("unwrap() failed", e);568}569}570571if (isTlsRsaPremasterSecret) {572TlsRsaPremasterSecretParameterSpec psps =573(TlsRsaPremasterSecretParameterSpec)spec;574575// Please use the tricky failover as the parameter so that576// smart compiler won't dispose the unused variable.577secretKey = polishPreMasterSecretKey(token, s,578failover, secretKey,579psps.getClientVersion(), psps.getServerVersion());580}581582return secretKey;583} finally {584p11Key.releaseKeyID();585token.releaseSession(s);586}587}588}589590// see JCE spec591protected int engineGetKeySize(Key key) throws InvalidKeyException {592int n = P11KeyFactory.convertKey(token, key, algorithm).length();593return n;594}595596private static SecretKey polishPreMasterSecretKey(597Token token, Session session,598Exception failover, SecretKey unwrappedKey,599int clientVersion, int serverVersion) {600601SecretKey newKey;602CK_VERSION version = new CK_VERSION(603(clientVersion >>> 8) & 0xFF, clientVersion & 0xFF);604try {605CK_ATTRIBUTE[] attributes = token.getAttributes(606O_GENERATE, CKO_SECRET_KEY,607CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]);608long keyID = token.p11.C_GenerateKey(session.id(),609new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version),610attributes);611newKey = P11Key.secretKey(session,612keyID, "TlsRsaPremasterSecret", 48 << 3, attributes);613} catch (PKCS11Exception e) {614throw new ProviderException(615"Could not generate premaster secret", e);616}617618return (failover == null) ? unwrappedKey : newKey;619}620621}622623final class ConstructKeys {624/**625* Construct a public key from its encoding.626*627* @param encodedKey the encoding of a public key.628*629* @param encodedKeyAlgorithm the algorithm the encodedKey is for.630*631* @return a public key constructed from the encodedKey.632*/633private static final PublicKey constructPublicKey(byte[] encodedKey,634String encodedKeyAlgorithm)635throws InvalidKeyException, NoSuchAlgorithmException {636try {637KeyFactory keyFactory =638KeyFactory.getInstance(encodedKeyAlgorithm);639X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);640return keyFactory.generatePublic(keySpec);641} catch (NoSuchAlgorithmException nsae) {642throw new NoSuchAlgorithmException("No installed providers " +643"can create keys for the " +644encodedKeyAlgorithm +645"algorithm", nsae);646} catch (InvalidKeySpecException ike) {647throw new InvalidKeyException("Cannot construct public key", ike);648}649}650651/**652* Construct a private key from its encoding.653*654* @param encodedKey the encoding of a private key.655*656* @param encodedKeyAlgorithm the algorithm the wrapped key is for.657*658* @return a private key constructed from the encodedKey.659*/660private static final PrivateKey constructPrivateKey(byte[] encodedKey,661String encodedKeyAlgorithm) throws InvalidKeyException,662NoSuchAlgorithmException {663try {664KeyFactory keyFactory =665KeyFactory.getInstance(encodedKeyAlgorithm);666PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);667return keyFactory.generatePrivate(keySpec);668} catch (NoSuchAlgorithmException nsae) {669throw new NoSuchAlgorithmException("No installed providers " +670"can create keys for the " +671encodedKeyAlgorithm +672"algorithm", nsae);673} catch (InvalidKeySpecException ike) {674throw new InvalidKeyException("Cannot construct private key", ike);675}676}677678/**679* Construct a secret key from its encoding.680*681* @param encodedKey the encoding of a secret key.682*683* @param encodedKeyAlgorithm the algorithm the secret key is for.684*685* @return a secret key constructed from the encodedKey.686*/687private static final SecretKey constructSecretKey(byte[] encodedKey,688String encodedKeyAlgorithm) {689return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);690}691692static final Key constructKey(byte[] encoding, String keyAlgorithm,693int keyType) throws InvalidKeyException, NoSuchAlgorithmException {694switch (keyType) {695case Cipher.SECRET_KEY:696return constructSecretKey(encoding, keyAlgorithm);697case Cipher.PRIVATE_KEY:698return constructPrivateKey(encoding, keyAlgorithm);699case Cipher.PUBLIC_KEY:700return constructPublicKey(encoding, keyAlgorithm);701default:702throw new InvalidKeyException("Unknown keytype " + keyType);703}704}705}706707708