--- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java 2018-06-04 19:27:17.718659724 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java 2018-06-04 19:27:17.452657833 -0300 @@ -394,25 +394,40 @@ this.iv = iv; p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm); try { - initialize(); + ensureInitialized(); } catch (PKCS11Exception e) { throw new InvalidKeyException("Could not initialize cipher", e); } } - private void cancelOperation() { - if (initialized == false) { - return; - } - - if ((session == null) || (token.explicitCancel == false)) { + // reset the states to the pre-initialized values + private void reset(boolean doCancel) { + if (!initialized) { return; } + initialized = false; try { - if (session.hasObjects() == false) { - session = token.killSession(session); + if (session == null) { return; - } else { + } + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.decNativeKeyRef(); + session = token.releaseSession(session); + bytesBuffered = 0; + padBufferLen = 0; + } + } + + private void cancelOperation() { + token.ensureValid(); + if (session.hasObjects() == false) { + session = token.killSession(session); + return; + } else { + try { // cancel operation by finishing it int bufLen = doFinalLength(0); byte[] buffer = new byte[bufLen]; @@ -421,40 +436,42 @@ } else { token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen); } + } catch (PKCS11Exception e) { + throw new ProviderException("Cancel failed", e); } - } catch (PKCS11Exception e) { - throw new ProviderException("Cancel failed", e); } } private void ensureInitialized() throws PKCS11Exception { - if (initialized == false) { - initialize(); + if (initialized) { + return; } - } - - private void initialize() throws PKCS11Exception { - if (session == null) { - session = token.getOpSession(); + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without calling engineInit first"); } - CK_MECHANISM mechParams = (blockMode == MODE_CTR? - new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) : - new CK_MECHANISM(mechanism, iv)); - + token.ensureValid(); + p11Key.incNativeKeyRef(); try { + if (session == null) { + session = token.getOpSession(); + } + CK_MECHANISM mechParams = (blockMode == MODE_CTR? + new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) : + new CK_MECHANISM(mechanism, iv)); if (encrypt) { token.p11.C_EncryptInit(session.id(), mechParams, p11Key.keyID); } else { token.p11.C_DecryptInit(session.id(), mechParams, p11Key.keyID); } - } catch (PKCS11Exception ex) { - // release session when initialization failed + } catch (Throwable t) { + p11Key.decNativeKeyRef(); session = token.releaseSession(session); - throw ex; + throw t; } + initialized = true; bytesBuffered = 0; padBufferLen = 0; - initialized = true; } // if update(inLen) is called, how big does the output buffer have to be? @@ -485,18 +502,6 @@ return result; } - // reset the states to the pre-initialized values - private void reset(boolean doCancel) { - if (doCancel) cancelOperation(); - - initialized = false; - bytesBuffered = 0; - padBufferLen = 0; - if (session != null) { - session = token.releaseSession(session); - } - } - // see JCE spec protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { try { --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DHKeyFactory.java 2018-06-04 19:27:18.547665617 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DHKeyFactory.java 2018-06-04 19:27:18.313663954 -0300 @@ -184,7 +184,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); return P11Key.publicKey - (session, keyID, "DH", p.bitLength(), attributes); + (session, keyID, "DH", p.bitLength(), attributes, true); } finally { token.releaseSession(session); } @@ -206,7 +206,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); return P11Key.privateKey - (session, keyID, "DH", p.bitLength(), attributes); + (session, keyID, "DH", p.bitLength(), attributes, true); } finally { token.releaseSession(session); } @@ -221,7 +221,12 @@ new CK_ATTRIBUTE(CKA_PRIME), new CK_ATTRIBUTE(CKA_BASE), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + key.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + } finally { + key.decNativeKeyRef(); + } KeySpec spec = new DHPublicKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger(), @@ -243,7 +248,12 @@ new CK_ATTRIBUTE(CKA_PRIME), new CK_ATTRIBUTE(CKA_BASE), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + key.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + } finally { + key.decNativeKeyRef(); + } KeySpec spec = new DHPrivateKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger(), --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java 2018-06-04 19:27:19.174670075 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java 2018-06-04 19:27:18.964668582 -0300 @@ -179,7 +179,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); return P11Key.publicKey - (session, keyID, "DSA", p.bitLength(), attributes); + (session, keyID, "DSA", p.bitLength(), attributes, true); } finally { token.releaseSession(session); } @@ -202,7 +202,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); return P11Key.privateKey - (session, keyID, "DSA", p.bitLength(), attributes); + (session, keyID, "DSA", p.bitLength(), attributes, true); } finally { token.releaseSession(session); } @@ -218,7 +218,12 @@ new CK_ATTRIBUTE(CKA_SUBPRIME), new CK_ATTRIBUTE(CKA_BASE), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + key.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + } finally { + key.decNativeKeyRef(); + } KeySpec spec = new DSAPublicKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger(), @@ -242,7 +247,12 @@ new CK_ATTRIBUTE(CKA_SUBPRIME), new CK_ATTRIBUTE(CKA_BASE), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + key.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + } finally { + key.decNativeKeyRef(); + } KeySpec spec = new DSAPrivateKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger(), --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Digest.java 2018-06-04 19:27:19.828674724 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Digest.java 2018-06-04 19:27:19.599673096 -0300 @@ -143,7 +143,8 @@ token.ensureValid(); if (session != null) { - if (state == S_INIT && token.explicitCancel == true) { + if (state == S_INIT && token.explicitCancel == true + && session.hasObjects() == false) { session = token.killSession(session); } else { session = token.releaseSession(session); @@ -264,7 +265,12 @@ token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs); bufOfs = 0; } - token.p11.C_DigestKey(session.id(), p11Key.keyID); + p11Key.incNativeKeyRef(); + try { + token.p11.C_DigestKey(session.id(), p11Key.keyID); + } finally { + p11Key.decNativeKeyRef(); + } } catch (PKCS11Exception e) { engineReset(); throw new ProviderException("update(SecretKey) failed", e); --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java 2018-06-04 19:27:20.412678876 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java 2018-06-04 19:27:20.222677525 -0300 @@ -130,9 +130,15 @@ new CK_ECDH1_DERIVE_PARAMS(CKD_NULL, null, publicValue); attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes); - long keyID = token.p11.C_DeriveKey(session.id(), - new CK_MECHANISM(mechanism, ckParams), privateKey.keyID, + privateKey.incNativeKeyRef(); + long keyID; + try { + keyID = token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, ckParams), privateKey.keyID, attributes); + } finally { + privateKey.decNativeKeyRef(); + } attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE) }; @@ -192,16 +198,22 @@ new CK_ECDH1_DERIVE_PARAMS(CKD_NULL, null, publicValue); attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); - long keyID = token.p11.C_DeriveKey(session.id(), - new CK_MECHANISM(mechanism, ckParams), privateKey.keyID, + privateKey.incNativeKeyRef(); + long keyID; + try { + keyID = token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, ckParams), privateKey.keyID, attributes); + } finally { + privateKey.decNativeKeyRef(); + } CK_ATTRIBUTE[] lenAttributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE_LEN), }; token.p11.C_GetAttributeValue(session.id(), keyID, lenAttributes); int keyLen = (int)lenAttributes[0].getLong(); SecretKey key = P11Key.secretKey - (session, keyID, algorithm, keyLen << 3, attributes); + (session, keyID, algorithm, keyLen << 3, attributes, true); return key; } catch (PKCS11Exception e) { throw new InvalidKeyException("Could not derive key", e); --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java 2018-06-04 19:27:20.889682267 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java 2018-06-04 19:27:20.734681165 -0300 @@ -253,7 +253,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); return P11Key.publicKey - (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes); + (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes, true); } finally { token.releaseSession(session); } @@ -276,7 +276,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); return P11Key.privateKey - (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes); + (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes, true); } finally { token.releaseSession(session); } @@ -290,7 +290,12 @@ new CK_ATTRIBUTE(CKA_EC_POINT), new CK_ATTRIBUTE(CKA_EC_PARAMS), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + key.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + } finally { + key.decNativeKeyRef(); + } try { ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); ECPoint point = decodePoint(attributes[0].getByteArray(), params.getCurve()); @@ -312,7 +317,12 @@ new CK_ATTRIBUTE(CKA_VALUE), new CK_ATTRIBUTE(CKA_EC_PARAMS), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + key.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + } finally { + key.decNativeKeyRef(); + } try { ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); return keySpec.cast( --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java 2018-06-04 19:27:21.338685458 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java 2018-06-04 19:27:21.189684399 -0300 @@ -29,7 +29,6 @@ import java.lang.ref.*; import java.math.BigInteger; import java.util.*; - import java.security.*; import java.security.interfaces.*; import java.security.spec.*; @@ -45,6 +44,8 @@ import sun.security.internal.interfaces.TlsMasterSecret; import sun.security.pkcs11.wrapper.*; + +import static sun.security.pkcs11.TemplateManager.O_GENERATE; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; import sun.security.util.Debug; @@ -84,7 +85,7 @@ final String algorithm; // key id - final long keyID; + long keyID; // effective key length of the key, e.g. 56 for a DES key final int keyLength; @@ -95,8 +96,19 @@ // phantom reference notification clean up for session keys private final SessionKeyRef sessionKeyRef; + // Native key objects may be temporal: only exist if in use. + private boolean tmpNativeKey; + + private int nativeKeyRefCounting; + + private static long nativeKeyWrapperKeyID = -1; + + // Buffer to hold native key objects info in Java heap in order to + // re-create them if needed. + private byte[] nativeKeyInfo; + P11Key(String type, Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { this.type = type; this.token = session.token; this.keyID = keyID; @@ -119,13 +131,143 @@ this.tokenObject = tokenObject; this.sensitive = sensitive; this.extractable = extractable; + if (token.tokenInfo.label[0] == 'N' + && token.tokenInfo.label[1] == 'S' + && token.tokenInfo.label[2] == 'S') { + this.tmpNativeKey = tmpNativeKey; + } else { + // Disabled if token is not NSS + this.tmpNativeKey = false; + } + // Disable temporary native keys if the key is not extractable or sensitive + // (when key is a token "secret"). + // The foundation for extracting wrapped sensitive keys is in + // place but it's currently disabled for token secrets because: + // 1) there is a bug in NSSDB for persisting CKO_SECRET_KEY + // in legacy DB (key3.db) which corrupts the key; and, + // 2) sqlite DB (key4.db) is still not supported by SunPKCS11 (see JDK-8165996). + if (!extractable || (sensitive && type.equals(SECRET) && tokenObject)) { + this.tmpNativeKey = false; + } + if (this.tmpNativeKey) { + nativeKeyRefCounting = 0; + try { + if (sensitive && nativeKeyWrapperKeyID == -1) { + synchronized(this) { + if (nativeKeyWrapperKeyID == -1) { + // Create a global wrapping/unwrapping key + CK_ATTRIBUTE[] wrappingAttributes = token.getAttributes + (O_GENERATE, CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3), + }); + Session wrappingSession = null; + try { + wrappingSession = token.getObjSession(); + nativeKeyWrapperKeyID = token.p11.C_GenerateKey + (wrappingSession.id(), new CK_MECHANISM(CKM_AES_KEY_GEN), wrappingAttributes); + } finally { + token.releaseSession(wrappingSession); + } + } + } + } + nativeKeyInfo = token.p11.getNativeKeyInfo(session.id(), keyID, nativeKeyWrapperKeyID); + if (nativeKeyInfo != null && nativeKeyInfo.length > 0) { + destroyNativeKey(); + // If extracted, it's not a token object anymore + tokenObject = false; + } else { + this.tmpNativeKey = false; + } + } catch (PKCS11Exception e) { + // Unexpected behaviour when trying to manage the key life-time. + // Don't manage the native key. + this.tmpNativeKey = false; + } + } if (tokenObject == false) { - sessionKeyRef = new SessionKeyRef(this, keyID, session); + sessionKeyRef = new SessionKeyRef(this, this.keyID, session); } else { sessionKeyRef = null; } } + public void incNativeKeyRef() throws PKCS11Exception { + if (tmpNativeKey) { + synchronized(this) { + if (++nativeKeyRefCounting == 1 && nativeKeyInfo != null) { + // Create a Native Key + Session session = null; + try { + session = token.getObjSession(); + keyID = token.p11.createNativeKey(session.id(), nativeKeyInfo, nativeKeyWrapperKeyID); + if (sessionKeyRef != null) { + sessionKeyRef.setKeyIDAndSession(keyID, session); + } + } catch (PKCS11Exception e) { + nativeKeyRefCounting--; + throw e; + } finally { + token.releaseSession(session); + } + } + } + } + } + + public void makeNativeKeyPersistent() throws PKCS11Exception { + if (tmpNativeKey) { + synchronized(this) { + if (nativeKeyRefCounting == 0) { + this.incNativeKeyRef(); + } + + // This write is not sync protected because reads are done out of the + // synchronization block. It's just a best-effort. + tmpNativeKey = false; + + // This write is sync protected and provides the real guarantee to avoid + // native key creation or destruction. + nativeKeyInfo = null; + } + } + } + + public void decNativeKeyRef() { + if (tmpNativeKey) { + synchronized(this) { + if(--nativeKeyRefCounting == 0 && nativeKeyInfo != null) { + try { + destroyNativeKey(); + } catch (PKCS11Exception e) { + // This is a best-effort. + } + } + if (nativeKeyRefCounting < 0) { + nativeKeyRefCounting = 0; + } + } + } + } + + private void destroyNativeKey() throws PKCS11Exception { + // There is no synchronization needed between SessionKeyRef.disposeNative and + // this method. When SessionKeyRef.disposeNative method is executed, no P11Key + // object exists. + Session session = null; + try { + session = token.getObjSession(); + token.p11.C_DestroyObject(session.id(), keyID); + } finally { + if (sessionKeyRef != null) { + sessionKeyRef.setKeyIDAndSession(0, null); + } + keyID = 0; + token.releaseSession(session); + } + } + // see JCA spec public final String getAlgorithm() { token.ensureValid(); @@ -243,7 +385,12 @@ Session tempSession = null; try { tempSession = token.getOpSession(); - token.p11.C_GetAttributeValue(tempSession.id(), keyID, attributes); + this.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(tempSession.id(), keyID, attributes); + } finally { + this.decNativeKeyRef(); + } } catch (PKCS11Exception e) { throw new ProviderException(e); } finally { @@ -287,42 +434,44 @@ } static SecretKey secretKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_TOKEN), new CK_ATTRIBUTE(CKA_SENSITIVE), new CK_ATTRIBUTE(CKA_EXTRACTABLE), }); - return new P11SecretKey(session, keyID, algorithm, keyLength, attributes); + return new P11SecretKey(session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } static SecretKey masterSecretKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) { + int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor, + boolean tmpNativeKey) { attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_TOKEN), new CK_ATTRIBUTE(CKA_SENSITIVE), new CK_ATTRIBUTE(CKA_EXTRACTABLE), }); return new P11TlsMasterSecretKey - (session, keyID, algorithm, keyLength, attributes, major, minor); + (session, keyID, algorithm, keyLength, attributes, major, minor, + tmpNativeKey); } // we assume that all components of public keys are always accessible static PublicKey publicKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { switch (algorithm) { case "RSA": return new P11RSAPublicKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, tmpNativeKey); case "DSA": return new P11DSAPublicKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, tmpNativeKey); case "DH": return new P11DHPublicKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, tmpNativeKey); case "EC": return new P11ECPublicKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, tmpNativeKey); default: throw new ProviderException ("Unknown public key algorithm " + algorithm); @@ -330,7 +479,7 @@ } static PrivateKey privateKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_TOKEN), new CK_ATTRIBUTE(CKA_SENSITIVE), @@ -338,7 +487,7 @@ }); if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) { return new P11PrivateKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } else { switch (algorithm) { case "RSA": @@ -368,20 +517,20 @@ } if (crtKey) { return new P11RSAPrivateKey - (session, keyID, algorithm, keyLength, attributes, attrs2); + (session, keyID, algorithm, keyLength, attributes, attrs2, tmpNativeKey); } else { return new P11RSAPrivateNonCRTKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } case "DSA": return new P11DSAPrivateKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, tmpNativeKey); case "DH": return new P11DHPrivateKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, tmpNativeKey); case "EC": return new P11ECPrivateKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, tmpNativeKey); default: throw new ProviderException ("Unknown private key algorithm " + algorithm); @@ -395,8 +544,8 @@ private static final long serialVersionUID = -2138581185214187615L; P11PrivateKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } // XXX temporary encoding for serialization purposes public String getFormat() { @@ -413,8 +562,8 @@ private static final long serialVersionUID = -7828241727014329084L; private volatile byte[] encoded; P11SecretKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(SECRET, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(SECRET, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } public String getFormat() { token.ensureValid(); @@ -440,8 +589,13 @@ CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE), }; - token.p11.C_GetAttributeValue - (tempSession.id(), keyID, attributes); + this.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue + (tempSession.id(), keyID, attributes); + } finally { + this.decNativeKeyRef(); + } b = attributes[0].getByteArray(); } catch (PKCS11Exception e) { throw new ProviderException(e); @@ -463,8 +617,9 @@ private final int majorVersion, minorVersion; P11TlsMasterSecretKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) { - super(session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor, + boolean tmpNativeKey) { + super(session, keyID, algorithm, keyLength, attributes, tmpNativeKey); this.majorVersion = major; this.minorVersion = minor; } @@ -485,8 +640,8 @@ private BigInteger n, e, d, p, q, pe, qe, coeff; private byte[] encoded; P11RSAPrivateKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE[] crtAttrs) { - super(PRIVATE, session, keyID, algorithm, keyLength, attrs); + int keyLength, CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE[] crtAttrs, boolean tmpNativeKey) { + super(PRIVATE, session, keyID, algorithm, keyLength, attrs, tmpNativeKey); for (CK_ATTRIBUTE a : crtAttrs) { if (a.type == CKA_PUBLIC_EXPONENT) { @@ -572,8 +727,8 @@ private BigInteger n, d; private byte[] encoded; P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } private synchronized void fetchValues() { token.ensureValid(); @@ -625,8 +780,8 @@ private BigInteger n, e; private byte[] encoded; P11RSAPublicKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(PUBLIC, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(PUBLIC, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } private synchronized void fetchValues() { token.ensureValid(); @@ -681,8 +836,8 @@ private DSAParams params; private byte[] encoded; P11DSAPublicKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(PUBLIC, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(PUBLIC, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } private synchronized void fetchValues() { token.ensureValid(); @@ -744,8 +899,8 @@ private DSAParams params; private byte[] encoded; P11DSAPrivateKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } private synchronized void fetchValues() { token.ensureValid(); @@ -802,8 +957,8 @@ private DHParameterSpec params; private byte[] encoded; P11DHPrivateKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } private synchronized void fetchValues() { token.ensureValid(); @@ -884,8 +1039,8 @@ private DHParameterSpec params; private byte[] encoded; P11DHPublicKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(PUBLIC, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(PUBLIC, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } private synchronized void fetchValues() { token.ensureValid(); @@ -971,8 +1126,8 @@ private ECParameterSpec params; private byte[] encoded; P11ECPrivateKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(PRIVATE, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } private synchronized void fetchValues() { token.ensureValid(); @@ -1027,8 +1182,8 @@ private ECParameterSpec params; private byte[] encoded; P11ECPublicKey(Session session, long keyID, String algorithm, - int keyLength, CK_ATTRIBUTE[] attributes) { - super(PUBLIC, session, keyID, algorithm, keyLength, attributes); + int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) { + super(PUBLIC, session, keyID, algorithm, keyLength, attributes, tmpNativeKey); } private synchronized void fetchValues() { token.ensureValid(); @@ -1126,7 +1281,7 @@ } // If the token is still valid, try to remove the object - if (next.session.token.isValid()) { + if (next.session != null && next.session.token.isValid()) { // If this key's token is the same as the previous key, the // same session can be used for C_DestroyObject. try { @@ -1160,21 +1315,32 @@ SessionKeyRef(P11Key key , long keyID, Session session) { super(key, refQueue); - this.keyID = keyID; - this.session = session; - this.session.addObject(); + setKeyIDAndSession(keyID, session); refList.add(this); drainRefQueueBounded(); } + public void setKeyIDAndSession(long keyID, Session session) { + if (this.session != null) { + this.session.removeObject(); + } + this.keyID = keyID; + this.session = session; + if (this.session != null) { + this.session.addObject(); + } + } + private void disposeNative(Session s) throws PKCS11Exception { - session.token.p11.C_DestroyObject(s.id(), keyID); + if(this.session != null) { + session.token.p11.C_DestroyObject(s.id(), keyID); + } } private void dispose() { refList.remove(this); this.clear(); - session.removeObject(); + setKeyIDAndSession(0, null); } public int compareTo(SessionKeyRef other) { --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java 2018-06-04 19:27:21.849689091 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java 2018-06-04 19:27:21.690687961 -0300 @@ -209,9 +209,15 @@ }; attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes); - long keyID = token.p11.C_DeriveKey(session.id(), - new CK_MECHANISM(mechanism, publicValue), privateKey.keyID, - attributes); + privateKey.incNativeKeyRef(); + long keyID; + try { + keyID = token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, publicValue), privateKey.keyID, + attributes); + } finally { + privateKey.decNativeKeyRef(); + } attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE) }; @@ -333,16 +339,22 @@ }; attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); - long keyID = token.p11.C_DeriveKey(session.id(), - new CK_MECHANISM(mechanism, publicValue), privateKey.keyID, - attributes); + privateKey.incNativeKeyRef(); + long keyID; + try { + keyID = token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, publicValue), privateKey.keyID, + attributes); + } finally { + privateKey.decNativeKeyRef(); + } CK_ATTRIBUTE[] lenAttributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE_LEN), }; token.p11.C_GetAttributeValue(session.id(), keyID, lenAttributes); int keyLen = (int)lenAttributes[0].getLong(); SecretKey key = P11Key.secretKey - (session, keyID, algorithm, keyLen << 3, attributes); + (session, keyID, algorithm, keyLen << 3, attributes, true); if ("RAW".equals(key.getFormat())) { // Workaround for Solaris bug 6318543. // Strip leading zeroes ourselves if possible (key not sensitive). --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java 2018-06-04 19:27:22.487693627 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java 2018-06-04 19:27:22.273692105 -0300 @@ -273,7 +273,7 @@ long keyID = token.p11.C_GenerateKey (session.id(), new CK_MECHANISM(mechanism), attributes); return P11Key.secretKey - (session, keyID, algorithm, significantKeySize, attributes); + (session, keyID, algorithm, significantKeySize, attributes, true); } catch (PKCS11Exception e) { throw new ProviderException("Could not generate key", e); } finally { --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java 2018-06-04 19:27:23.116698098 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java 2018-06-04 19:27:22.894696520 -0300 @@ -416,9 +416,9 @@ (session.id(), new CK_MECHANISM(mechanism), publicKeyTemplate, privateKeyTemplate); PublicKey publicKey = P11Key.publicKey - (session, keyIDs[0], algorithm, keySize, publicKeyTemplate); + (session, keyIDs[0], algorithm, keySize, publicKeyTemplate, true); PrivateKey privateKey = P11Key.privateKey - (session, keyIDs[1], algorithm, keySize, privateKeyTemplate); + (session, keyIDs[1], algorithm, keySize, privateKeyTemplate, true); return new KeyPair(publicKey, privateKey); } catch (PKCS11Exception e) { throw new ProviderException(e); --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java 2018-06-04 19:27:23.742702548 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java 2018-06-04 19:27:23.587701447 -0300 @@ -1291,7 +1291,7 @@ } } - return P11Key.secretKey(session, oHandle, keyType, keyLength, null); + return P11Key.secretKey(session, oHandle, keyType, keyLength, null, false); } private PrivateKey loadPkey(Session session, long oHandle) @@ -1326,7 +1326,8 @@ oHandle, keyType, keyLength, - null); + null, + false); } else if (kType == CKK_DSA) { @@ -1341,7 +1342,8 @@ oHandle, keyType, keyLength, - null); + null, + false); } else if (kType == CKK_DH) { @@ -1356,7 +1358,8 @@ oHandle, keyType, keyLength, - null); + null, + false); } else if (kType == CKK_EC) { @@ -1374,7 +1377,7 @@ throw new KeyStoreException("Unsupported parameters", e); } - return P11Key.privateKey(session, oHandle, "EC", keyLength, null); + return P11Key.privateKey(session, oHandle, "EC", keyLength, null, false); } else { if (debug != null) { @@ -1500,6 +1503,7 @@ CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_ID, alias) }; + key.makeNativeKeyPersistent(); token.p11.C_SetAttributeValue (session.id(), key.keyID, attrs); if (debug != null) { @@ -1518,7 +1522,12 @@ if (attribute != null) { attrs = addAttribute(attrs, attribute); } - token.p11.C_CopyObject(session.id(), key.keyID, attrs); + key.incNativeKeyRef(); + try { + token.p11.C_CopyObject(session.id(), key.keyID, attrs); + } finally { + key.decNativeKeyRef(); + } if (debug != null) { debug.println("updateP11Pkey copied private session key " + "for [" + @@ -1626,7 +1635,8 @@ new CK_ATTRIBUTE(CKA_LABEL, alias), }; try { - P11SecretKeyFactory.convertKey(token, skey, null, attrs); + P11Key k = P11SecretKeyFactory.convertKey(token, skey, null, attrs); + k.makeNativeKeyPersistent(); } catch (InvalidKeyException ike) { // re-throw KeyStoreException to match javadoc throw new KeyStoreException("Cannot convert to PKCS11 keys", ike); --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java 2018-06-04 19:27:24.357706920 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java 2018-06-04 19:27:24.163705541 -0300 @@ -25,7 +25,6 @@ package sun.security.pkcs11; -import java.util.*; import java.nio.ByteBuffer; import java.security.*; @@ -54,27 +53,12 @@ */ final class P11Mac extends MacSpi { - /* unitialized, all fields except session have arbitrary values */ - private final static int S_UNINIT = 1; - - /* session initialized, no data processed yet */ - private final static int S_RESET = 2; - - /* session initialized, data processed */ - private final static int S_UPDATE = 3; - - /* transitional state after doFinal() before we go to S_UNINIT */ - private final static int S_DOFINAL = 4; - // token instance private final Token token; // algorithm name private final String algorithm; - // mechanism id - private final long mechanism; - // mechanism object private final CK_MECHANISM ckMechanism; @@ -87,8 +71,8 @@ // associated session, if any private Session session; - // state, one of S_* above - private int state; + // initialization status + private boolean initialized; // one byte buffer for the update(byte) method, initialized on demand private byte[] oneByte; @@ -98,7 +82,6 @@ super(); this.token = token; this.algorithm = algorithm; - this.mechanism = mechanism; Long params = null; switch ((int)mechanism) { case (int)CKM_MD5_HMAC: @@ -131,47 +114,63 @@ throw new ProviderException("Unknown mechanism: " + mechanism); } ckMechanism = new CK_MECHANISM(mechanism, params); - state = S_UNINIT; - initialize(); } - private void ensureInitialized() throws PKCS11Exception { - token.ensureValid(); - if (state == S_UNINIT) { - initialize(); + // reset the states to the pre-initialized values + private void reset(boolean doCancel) { + if (!initialized) { + return; + } + initialized = false; + try { + if (session == null) { + return; + } + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.decNativeKeyRef(); + session = token.releaseSession(session); } } private void cancelOperation() { token.ensureValid(); - if (state == S_UNINIT) { - return; - } - state = S_UNINIT; - if ((session == null) || (token.explicitCancel == false)) { + if (session.hasObjects() == false) { + session = token.killSession(session); return; - } - try { - token.p11.C_SignFinal(session.id(), 0); - } catch (PKCS11Exception e) { - throw new ProviderException("Cancel failed", e); + } else { + try { + token.p11.C_SignFinal(session.id(), 0); + } catch (PKCS11Exception e) { + throw new ProviderException("Cancel failed", e); + } } } - private void initialize() throws PKCS11Exception { - if (state == S_RESET) { + private void ensureInitialized() throws PKCS11Exception { + if (initialized) { return; } - if (session == null) { - session = token.getOpSession(); + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without calling engineInit first"); } - if (p11Key != null) { + token.ensureValid(); + p11Key.incNativeKeyRef(); + try { + if (session == null) { + session = token.getOpSession(); + } token.p11.C_SignInit (session.id(), ckMechanism, p11Key.keyID); - state = S_RESET; - } else { - state = S_UNINIT; + } catch (Throwable t) { + p11Key.decNativeKeyRef(); + session = token.releaseSession(session); + throw t; } + initialized = true; } // see JCE spec @@ -181,18 +180,7 @@ // see JCE spec protected void engineReset() { - // the framework insists on calling reset() after doFinal(), - // but we prefer to take care of reinitialization ourselves - if (state == S_DOFINAL) { - state = S_UNINIT; - return; - } - cancelOperation(); - try { - initialize(); - } catch (PKCS11Exception e) { - throw new ProviderException("reset() failed, ", e); - } + reset(true); } // see JCE spec @@ -202,10 +190,10 @@ throw new InvalidAlgorithmParameterException ("Parameters not supported"); } - cancelOperation(); + reset(true); p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm); try { - initialize(); + ensureInitialized(); } catch (PKCS11Exception e) { throw new InvalidKeyException("init() failed", e); } @@ -215,13 +203,12 @@ protected byte[] engineDoFinal() { try { ensureInitialized(); - byte[] mac = token.p11.C_SignFinal(session.id(), 0); - state = S_DOFINAL; - return mac; + return token.p11.C_SignFinal(session.id(), 0); } catch (PKCS11Exception e) { + reset(true); throw new ProviderException("doFinal() failed", e); } finally { - session = token.releaseSession(session); + reset(false); } } @@ -239,7 +226,6 @@ try { ensureInitialized(); token.p11.C_SignUpdate(session.id(), 0, b, ofs, len); - state = S_UPDATE; } catch (PKCS11Exception e) { throw new ProviderException("update() failed", e); } @@ -261,7 +247,6 @@ int ofs = byteBuffer.position(); token.p11.C_SignUpdate(session.id(), addr + ofs, null, 0, len); byteBuffer.position(ofs + len); - state = S_UPDATE; } catch (PKCS11Exception e) { throw new ProviderException("update() failed", e); } --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java 2018-06-04 19:27:24.961711214 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java 2018-06-04 19:27:24.736709615 -0300 @@ -196,7 +196,7 @@ } private void implInit(int opmode, Key key) throws InvalidKeyException { - cancelOperation(); + reset(true); p11Key = P11KeyFactory.convertKey(token, key, algorithm); boolean encrypt; if (opmode == Cipher.ENCRYPT_MODE) { @@ -235,86 +235,107 @@ maxInputSize = ((padType == PAD_PKCS1 && encrypt) ? (n - PKCS1_MIN_PADDING_LENGTH) : n); try { - initialize(); + ensureInitialized(); } catch (PKCS11Exception e) { throw new InvalidKeyException("init() failed", e); } } - private void cancelOperation() { - token.ensureValid(); - if (initialized == false) { + // reset the states to the pre-initialized values + private void reset(boolean doCancel) { + if (!initialized) { return; } initialized = false; - if ((session == null) || (token.explicitCancel == false)) { - return; + try { + if (session == null) { + return; + } + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.decNativeKeyRef(); + session = token.releaseSession(session); } + } + + private void cancelOperation() { + token.ensureValid(); if (session.hasObjects() == false) { session = token.killSession(session); return; + } else { + try { + PKCS11 p11 = token.p11; + int inLen = maxInputSize; + int outLen = buffer.length; + switch (mode) { + case MODE_ENCRYPT: + p11.C_Encrypt + (session.id(), buffer, 0, inLen, buffer, 0, outLen); + break; + case MODE_DECRYPT: + p11.C_Decrypt + (session.id(), buffer, 0, inLen, buffer, 0, outLen); + break; + case MODE_SIGN: + byte[] tmpBuffer = new byte[maxInputSize]; + p11.C_Sign + (session.id(), tmpBuffer); + break; + case MODE_VERIFY: + p11.C_VerifyRecover + (session.id(), buffer, 0, inLen, buffer, 0, outLen); + break; + default: + throw new ProviderException("internal error"); + } + } catch (PKCS11Exception e) { + // XXX ensure this always works, ignore error + } } + } + + private void ensureInitialized() throws PKCS11Exception { + if (initialized) { + return; + } + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without calling engineInit first"); + } + token.ensureValid(); + p11Key.incNativeKeyRef(); try { + if (session == null) { + session = token.getOpSession(); + } PKCS11 p11 = token.p11; - int inLen = maxInputSize; - int outLen = buffer.length; + CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism); switch (mode) { case MODE_ENCRYPT: - p11.C_Encrypt - (session.id(), buffer, 0, inLen, buffer, 0, outLen); + p11.C_EncryptInit(session.id(), ckMechanism, p11Key.keyID); break; case MODE_DECRYPT: - p11.C_Decrypt - (session.id(), buffer, 0, inLen, buffer, 0, outLen); + p11.C_DecryptInit(session.id(), ckMechanism, p11Key.keyID); break; case MODE_SIGN: - byte[] tmpBuffer = new byte[maxInputSize]; - p11.C_Sign - (session.id(), tmpBuffer); + p11.C_SignInit(session.id(), ckMechanism, p11Key.keyID); break; case MODE_VERIFY: - p11.C_VerifyRecover - (session.id(), buffer, 0, inLen, buffer, 0, outLen); + p11.C_VerifyRecoverInit(session.id(), ckMechanism, p11Key.keyID); break; default: - throw new ProviderException("internal error"); + throw new AssertionError("internal error"); } - } catch (PKCS11Exception e) { - // XXX ensure this always works, ignore error - } - } - - private void ensureInitialized() throws PKCS11Exception { - token.ensureValid(); - if (initialized == false) { - initialize(); - } - } - - private void initialize() throws PKCS11Exception { - if (session == null) { - session = token.getOpSession(); - } - PKCS11 p11 = token.p11; - CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism); - switch (mode) { - case MODE_ENCRYPT: - p11.C_EncryptInit(session.id(), ckMechanism, p11Key.keyID); - break; - case MODE_DECRYPT: - p11.C_DecryptInit(session.id(), ckMechanism, p11Key.keyID); - break; - case MODE_SIGN: - p11.C_SignInit(session.id(), ckMechanism, p11Key.keyID); - break; - case MODE_VERIFY: - p11.C_VerifyRecoverInit(session.id(), ckMechanism, p11Key.keyID); - break; - default: - throw new AssertionError("internal error"); + } catch (Throwable t) { + p11Key.decNativeKeyRef(); + session = token.releaseSession(session); + throw t; } - bufOfs = 0; initialized = true; + bufOfs = 0; } private void implUpdate(byte[] in, int inOfs, int inLen) { @@ -377,8 +398,7 @@ throw (BadPaddingException)new BadPaddingException ("doFinal() failed").initCause(e); } finally { - initialized = false; - session = token.releaseSession(session); + reset(false); } } @@ -454,11 +474,15 @@ Session s = null; try { s = token.getOpSession(); + p11Key.incNativeKeyRef(); + sKey.incNativeKeyRef(); return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism), p11Key.keyID, sKey.keyID); } catch (PKCS11Exception e) { throw new InvalidKeyException("wrap() failed", e); } finally { + p11Key.decNativeKeyRef(); + sKey.decNativeKeyRef(); token.releaseSession(s); } } @@ -528,11 +552,17 @@ }; attributes = token.getAttributes( O_IMPORT, CKO_SECRET_KEY, keyType, attributes); - long keyID = token.p11.C_UnwrapKey(s.id(), - new CK_MECHANISM(mechanism), p11Key.keyID, + p11Key.incNativeKeyRef(); + long keyID; + try { + keyID = token.p11.C_UnwrapKey(s.id(), + new CK_MECHANISM(mechanism), p11Key.keyID, wrappedKey, attributes); + } finally { + p11Key.decNativeKeyRef(); + } secretKey = P11Key.secretKey(s, keyID, - algorithm, 48 << 3, attributes); + algorithm, 48 << 3, attributes, true); } catch (PKCS11Exception e) { if (isTlsRsaPremasterSecret) { failover = e; @@ -581,7 +611,7 @@ new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version), attributes); newKey = P11Key.secretKey(session, - keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); + keyID, "TlsRsaPremasterSecret", 48 << 3, attributes, true); } catch (PKCS11Exception e) { throw new ProviderException( "Could not generate premaster secret", e); --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java 2018-06-04 19:27:25.496715017 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java 2018-06-04 19:27:25.344713937 -0300 @@ -197,7 +197,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); return P11Key.publicKey - (session, keyID, "RSA", n.bitLength(), attributes); + (session, keyID, "RSA", n.bitLength(), attributes, true); } finally { token.releaseSession(session); } @@ -219,7 +219,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); return P11Key.privateKey - (session, keyID, "RSA", n.bitLength(), attributes); + (session, keyID, "RSA", n.bitLength(), attributes, true); } finally { token.releaseSession(session); } @@ -249,7 +249,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); return P11Key.privateKey - (session, keyID, "RSA", n.bitLength(), attributes); + (session, keyID, "RSA", n.bitLength(), attributes, true); } finally { token.releaseSession(session); } @@ -263,7 +263,12 @@ new CK_ATTRIBUTE(CKA_MODULUS), new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + key.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + } finally { + key.decNativeKeyRef(); + } KeySpec spec = new RSAPublicKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger() @@ -289,7 +294,12 @@ new CK_ATTRIBUTE(CKA_EXPONENT_2), new CK_ATTRIBUTE(CKA_COEFFICIENT), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + key.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + } finally { + key.decNativeKeyRef(); + } KeySpec spec = new RSAPrivateCrtKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger(), @@ -307,7 +317,12 @@ new CK_ATTRIBUTE(CKA_MODULUS), new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + key.incNativeKeyRef(); + try { + token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + } finally { + key.decNativeKeyRef(); + } KeySpec spec = new RSAPrivateKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger() --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java 2018-06-04 19:27:25.962718330 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java 2018-06-04 19:27:25.805717214 -0300 @@ -149,11 +149,17 @@ Session session = null; try { session = token.getObjSession(); - long newKeyID = token.p11.C_CopyObject(session.id(), + p11Key.incNativeKeyRef(); + long newKeyID; + try { + newKeyID = token.p11.C_CopyObject(session.id(), p11Key.keyID, extraAttrs); + } finally { + p11Key.decNativeKeyRef(); + } p11Key = (P11Key) (P11Key.secretKey(session, newKeyID, p11Key.algorithm, p11Key.keyLength, - extraAttrs)); + extraAttrs, true)); } catch (PKCS11Exception p11e) { throw new InvalidKeyException ("Cannot duplicate the PKCS11 key", p11e); @@ -264,7 +270,7 @@ session = token.getObjSession(); long keyID = token.p11.C_CreateObject(session.id(), attributes); P11Key p11Key = (P11Key)P11Key.secretKey - (session, keyID, algorithm, keyLength, attributes); + (session, keyID, algorithm, keyLength, attributes, true); return p11Key; } catch (PKCS11Exception e) { throw new InvalidKeyException("Could not create key", e); --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java 2018-06-04 19:27:26.467721920 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java 2018-06-04 19:27:26.269720513 -0300 @@ -263,31 +263,35 @@ } } - private void ensureInitialized() { - token.ensureValid(); - if (initialized == false) { - initialize(); + // reset the states to the pre-initialized values + private void reset(boolean doCancel) { + if (!initialized) { + return; + } + initialized = false; + try { + if (session == null) { + return; + } + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.decNativeKeyRef(); + session = token.releaseSession(session); } } private void cancelOperation() { token.ensureValid(); - if (initialized == false) { - return; - } - initialized = false; - if ((session == null) || (token.explicitCancel == false)) { - return; - } if (session.hasObjects() == false) { session = token.killSession(session); return; - } - try { + } else { // "cancel" operation by finishing it // XXX make sure all this always works correctly - if (mode == M_SIGN) { - try { + try { + if (mode == M_SIGN) { if (type == T_UPDATE) { token.p11.C_SignFinal(session.id(), 0); } else { @@ -299,11 +303,7 @@ } token.p11.C_Sign(session.id(), digest); } - } catch (PKCS11Exception e) { - throw new ProviderException("cancel failed", e); - } - } else { // M_VERIFY - try { + } else { // M_VERIFY byte[] signature; if (keyAlgorithm.equals("DSA")) { signature = new byte[40]; @@ -321,40 +321,48 @@ } token.p11.C_Verify(session.id(), digest, signature); } - } catch (PKCS11Exception e) { - // will fail since the signature is incorrect - // XXX check error code } + } catch (PKCS11Exception e) { + throw new ProviderException("cancel failed", e); } - } finally { - session = token.releaseSession(session); } } // assumes current state is initialized == false - private void initialize() { + private void ensureInitialized() { + if (initialized) { + return; + } + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without calling engineInit first"); + } try { - if (session == null) { - session = token.getOpSession(); - } - if (mode == M_SIGN) { - token.p11.C_SignInit(session.id(), - new CK_MECHANISM(mechanism), p11Key.keyID); - } else { - token.p11.C_VerifyInit(session.id(), - new CK_MECHANISM(mechanism), p11Key.keyID); + token.ensureValid(); + p11Key.incNativeKeyRef(); + try { + if (session == null) { + session = token.getOpSession(); + } + if (mode == M_SIGN) { + token.p11.C_SignInit(session.id(), + new CK_MECHANISM(mechanism), p11Key.keyID); + } else { + token.p11.C_VerifyInit(session.id(), + new CK_MECHANISM(mechanism), p11Key.keyID); + } + } catch (Throwable t) { + p11Key.decNativeKeyRef(); + session = token.releaseSession(session); + throw t; } initialized = true; - } catch (PKCS11Exception e) { - // release session when initialization failed - session = token.releaseSession(session); - throw new ProviderException("Initialization failed", e); - } - if (bytesProcessed != 0) { - bytesProcessed = 0; - if (md != null) { + if (bytesProcessed != 0 && md != null) { md.reset(); } + bytesProcessed = 0; + } catch (PKCS11Exception e) { + throw new ProviderException("Initialization failed", e); } } @@ -451,10 +459,10 @@ if (publicKey != p11Key) { checkKeySize(keyAlgorithm, publicKey); } - cancelOperation(); + reset(true); mode = M_VERIFY; p11Key = P11KeyFactory.convertKey(token, publicKey, keyAlgorithm); - initialize(); + ensureInitialized(); } // see JCA spec @@ -468,10 +476,10 @@ if (privateKey != p11Key) { checkKeySize(keyAlgorithm, privateKey); } - cancelOperation(); + reset(true); mode = M_SIGN; p11Key = P11KeyFactory.convertKey(token, privateKey, keyAlgorithm); - initialize(); + ensureInitialized(); } // see JCA spec @@ -517,8 +525,7 @@ } bytesProcessed += len; } catch (PKCS11Exception e) { - initialized = false; - session = token.releaseSession(session); + reset(true); throw new ProviderException(e); } break; @@ -641,11 +648,10 @@ } catch (PKCS11Exception pe) { throw new ProviderException(pe); } catch (SignatureException | ProviderException e) { - cancelOperation(); + reset(true); throw e; } finally { - initialized = false; - session = token.releaseSession(session); + reset(false); } } @@ -710,11 +716,10 @@ } throw new ProviderException(pe); } catch (SignatureException | ProviderException e) { - cancelOperation(); + reset(true); throw e; } finally { - initialized = false; - session = token.releaseSession(session); + reset(false); } } --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java 2018-06-04 19:27:27.073726228 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java 2018-06-04 19:27:26.892724942 -0300 @@ -173,8 +173,14 @@ attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); // the returned keyID is a dummy, ignore - long keyID = token.p11.C_DeriveKey(session.id(), - new CK_MECHANISM(mechanism, params), p11Key.keyID, attributes); + + p11Key.incNativeKeyRef(); + try { + token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, params), p11Key.keyID, attributes); + } finally { + p11Key.decNativeKeyRef(); + } CK_SSL3_KEY_MAT_OUT out = params.pReturnedKeyMaterial; // Note that the MAC keys do not inherit all attributes from the @@ -188,9 +194,9 @@ // so the macBits is unlikely to be zero. It's only a place holder. if (macBits != 0) { clientMacKey = P11Key.secretKey - (session, out.hClientMacSecret, "MAC", macBits, attributes); + (session, out.hClientMacSecret, "MAC", macBits, attributes, true); serverMacKey = P11Key.secretKey - (session, out.hServerMacSecret, "MAC", macBits, attributes); + (session, out.hServerMacSecret, "MAC", macBits, attributes, true); } else { clientMacKey = null; serverMacKey = null; @@ -199,9 +205,9 @@ SecretKey clientCipherKey, serverCipherKey; if (keyBits != 0) { clientCipherKey = P11Key.secretKey(session, out.hClientKey, - cipherAlgorithm, expandedKeyBits, attributes); + cipherAlgorithm, expandedKeyBits, attributes, true); serverCipherKey = P11Key.secretKey(session, out.hServerKey, - cipherAlgorithm, expandedKeyBits, attributes); + cipherAlgorithm, expandedKeyBits, attributes, true); } else { clientCipherKey = null; serverCipherKey = null; --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java 2018-06-04 19:27:27.571729769 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java 2018-06-04 19:27:27.388728468 -0300 @@ -147,8 +147,14 @@ session = token.getObjSession(); CK_ATTRIBUTE[] attributes = token.getAttributes(O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); - long keyID = token.p11.C_DeriveKey(session.id(), - new CK_MECHANISM(mechanism, params), p11Key.keyID, attributes); + p11Key.incNativeKeyRef(); + long keyID; + try { + keyID = token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, params), p11Key.keyID, attributes); + } finally { + p11Key.decNativeKeyRef(); + } int major, minor; if (params.pVersion == null) { major = -1; @@ -158,7 +164,7 @@ minor = params.pVersion.minor; } SecretKey key = P11Key.masterSecretKey(session, keyID, - "TlsMasterSecret", 48 << 3, attributes, major, minor); + "TlsMasterSecret", 48 << 3, attributes, major, minor, true); return key; } catch (Exception e) { throw new ProviderException("Could not generate key", e); --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java 2018-06-04 19:27:28.083733408 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java 2018-06-04 19:27:27.921732257 -0300 @@ -133,12 +133,18 @@ Session session = null; try { session = token.getOpSession(); - token.p11.C_SignInit - (session.id(), new CK_MECHANISM(mechanism), p11Key.keyID); - token.p11.C_SignUpdate(session.id(), 0, label, 0, label.length); - token.p11.C_SignUpdate(session.id(), 0, seed, 0, seed.length); - byte[] out = token.p11.C_SignFinal - (session.id(), spec.getOutputLength()); + byte[] out; + p11Key.incNativeKeyRef(); + try { + token.p11.C_SignInit + (session.id(), new CK_MECHANISM(mechanism), p11Key.keyID); + token.p11.C_SignUpdate(session.id(), 0, label, 0, label.length); + token.p11.C_SignUpdate(session.id(), 0, seed, 0, seed.length); + out = token.p11.C_SignFinal + (session.id(), spec.getOutputLength()); + } finally { + p11Key.decNativeKeyRef(); + } return new SecretKeySpec(out, "TlsPrf"); } catch (PKCS11Exception e) { throw new ProviderException("Could not calculate PRF", e); @@ -155,8 +161,13 @@ Session session = null; try { session = token.getOpSession(); - long keyID = token.p11.C_DeriveKey(session.id(), - new CK_MECHANISM(mechanism, params), p11Key.keyID, null); + p11Key.incNativeKeyRef(); + try { + token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, params), p11Key.keyID, null); + } finally { + p11Key.decNativeKeyRef(); + } // ignore keyID, returned PRF bytes are in 'out' return new SecretKeySpec(out, "TlsPrf"); } catch (PKCS11Exception e) { --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java 2018-06-04 19:27:28.722737951 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java 2018-06-04 19:27:28.511736451 -0300 @@ -124,7 +124,7 @@ long keyID = token.p11.C_GenerateKey(session.id(), new CK_MECHANISM(mechanism, version), attributes); SecretKey key = P11Key.secretKey(session, - keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); + keyID, "TlsRsaPremasterSecret", 48 << 3, attributes, true); return key; } catch (PKCS11Exception e) { throw new ProviderException( --- old/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java 2018-06-04 19:27:29.222741506 -0300 +++ new/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java 2018-06-04 19:27:29.063740375 -0300 @@ -1291,6 +1291,38 @@ ******************************************************************************/ /** + * getNativeKeyInfo gets the key object attributes and values as an opaque + * byte array to be used in createNativeKey method. + * (Key management) + * + * @param hSession the session's handle + * @param hKey key's handle + * @param hWrappingKey wrapping key's handle to extract sensible keys. -1 if not used. + * @return an opaque byte array containing the key object attributes and values + * @exception PKCS11Exception If an internal PKCS#11 function returns other + * value than CKR_OK. + * @preconditions + * @postconditions + */ + public native byte[] getNativeKeyInfo(long hSession, long hKey, long hWrappingKey) throws PKCS11Exception; + + /** + * createNativeKey creates a key object with attributes and values specified + * by parameter as an opaque byte array. + * (Key management) + * + * @param hSession the session's handle + * @param keyInfo opaque byte array containing key object attributes and values + * @param hWrappingKey wrapping key's handle for extracted sensible keys. -1 if not used. + * @return key object handle + * @exception PKCS11Exception If an internal PKCS#11 function returns other + * value than CKR_OK. + * @preconditions + * @postconditions + */ + public native long createNativeKey(long hSession, byte[] keyInfo, long hWrappingKey) throws PKCS11Exception; + + /** * C_GenerateKey generates a secret key, creating a new key * object. * (Key management) --- old/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c 2018-06-04 19:27:29.798745600 -0300 +++ new/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c 2018-06-04 19:27:29.608744250 -0300 @@ -54,6 +54,333 @@ #include "sun_security_pkcs11_wrapper_PKCS11.h" +#ifdef P11_ENABLE_GETNATIVEKEYINFO + +#define CK_ATTRIBUTES_TEMPLATE_LENGTH (CK_ULONG)61U + +static CK_ATTRIBUTE ckpAttributesTemplate[CK_ATTRIBUTES_TEMPLATE_LENGTH] = { + {CKA_CLASS, 0, 0}, + {CKA_TOKEN, 0, 0}, + {CKA_PRIVATE, 0, 0}, + {CKA_LABEL, 0, 0}, + {CKA_APPLICATION, 0, 0}, + {CKA_VALUE, 0, 0}, + {CKA_OBJECT_ID, 0, 0}, + {CKA_CERTIFICATE_TYPE, 0, 0}, + {CKA_ISSUER, 0, 0}, + {CKA_SERIAL_NUMBER, 0, 0}, + {CKA_AC_ISSUER, 0, 0}, + {CKA_OWNER, 0, 0}, + {CKA_ATTR_TYPES, 0, 0}, + {CKA_TRUSTED, 0, 0}, + {CKA_KEY_TYPE, 0, 0}, + {CKA_SUBJECT, 0, 0}, + {CKA_ID, 0, 0}, + {CKA_SENSITIVE, 0, 0}, + {CKA_ENCRYPT, 0, 0}, + {CKA_DECRYPT, 0, 0}, + {CKA_WRAP, 0, 0}, + {CKA_UNWRAP, 0, 0}, + {CKA_SIGN, 0, 0}, + {CKA_SIGN_RECOVER, 0, 0}, + {CKA_VERIFY, 0, 0}, + {CKA_VERIFY_RECOVER, 0, 0}, + {CKA_DERIVE, 0, 0}, + {CKA_START_DATE, 0, 0}, + {CKA_END_DATE, 0, 0}, + {CKA_MODULUS, 0, 0}, + {CKA_MODULUS_BITS, 0, 0}, + {CKA_PUBLIC_EXPONENT, 0, 0}, + {CKA_PRIVATE_EXPONENT, 0, 0}, + {CKA_PRIME_1, 0, 0}, + {CKA_PRIME_2, 0, 0}, + {CKA_EXPONENT_1, 0, 0}, + {CKA_EXPONENT_2, 0, 0}, + {CKA_COEFFICIENT, 0, 0}, + {CKA_PRIME, 0, 0}, + {CKA_SUBPRIME, 0, 0}, + {CKA_BASE, 0, 0}, + {CKA_PRIME_BITS, 0, 0}, + {CKA_SUB_PRIME_BITS, 0, 0}, + {CKA_VALUE_BITS, 0, 0}, + {CKA_VALUE_LEN, 0, 0}, + {CKA_EXTRACTABLE, 0, 0}, + {CKA_LOCAL, 0, 0}, + {CKA_NEVER_EXTRACTABLE, 0, 0}, + {CKA_ALWAYS_SENSITIVE, 0, 0}, + {CKA_KEY_GEN_MECHANISM, 0, 0}, + {CKA_MODIFIABLE, 0, 0}, + {CKA_ECDSA_PARAMS, 0, 0}, + {CKA_EC_PARAMS, 0, 0}, + {CKA_EC_POINT, 0, 0}, + {CKA_SECONDARY_AUTH, 0, 0}, + {CKA_AUTH_PIN_FLAGS, 0, 0}, + {CKA_HW_FEATURE_TYPE, 0, 0}, + {CKA_RESET_ON_INIT, 0, 0}, + {CKA_HAS_RESET, 0, 0}, + {CKA_VENDOR_DEFINED, 0, 0}, + {CKA_NETSCAPE_DB, 0, 0}, +}; + +/* + * Class: sun_security_pkcs11_wrapper_PKCS11 + * Method: getNativeKeyInfo + * Signature: (JJJ)[B + * Parametermapping: *PKCS11* + * @param jlong jSessionHandle CK_SESSION_HANDLE hSession + * @param jlong jKeyHandle CK_OBJECT_HANDLE hObject + * @param jlong jWrappingKeyHandle CK_OBJECT_HANDLE hObject + * @return jbyteArray jNativeKeyInfo - + */ +JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_getNativeKeyInfo + (JNIEnv *env, jobject obj, jlong jSessionHandle, jlong jKeyHandle, jlong jWrappingKeyHandle) +{ + jbyteArray returnValue = NULL; + CK_SESSION_HANDLE ckSessionHandle = jLongToCKULong(jSessionHandle); + CK_OBJECT_HANDLE ckObjectHandle = jLongToCKULong(jKeyHandle); + CK_ATTRIBUTE_PTR ckpAttributes = NULL; + CK_RV rv; + jbyteArray nativeKeyInfoArray = NULL; + jbyteArray nativeKeyInfoWrappedKeyArray = NULL; + jbyte* nativeKeyInfoArrayRaw = NULL; + jbyte* nativeKeyInfoWrappedKeyArrayRaw = NULL; + unsigned int sensitiveAttributePosition = (unsigned int)-1; + unsigned int i = 0U, totalDataSize = 0U, attributesCount = 0U; + unsigned int totalCkAttributesSize = 0U, totalNativeKeyInfoArraySize = 0U; + unsigned long* wrappedKeySizePtr = NULL; + jbyte* nativeKeyInfoArrayRawCkAttributes = NULL; + jbyte* nativeKeyInfoArrayRawCkAttributesPtr = NULL; + jbyte* nativeKeyInfoArrayRawDataPtr = NULL; + CK_MECHANISM ckMechanism = {0x0}; + char iv[16] = {0x0}; + CK_ULONG ckWrappedKeyLength = 0U; + unsigned long* wrappedKeySizeWrappedKeyArrayPtr = NULL; + CK_BYTE_PTR wrappedKeyBufferPtr = NULL; + CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); + + if (ckpFunctions == NULL) { goto cleanup; } + + ckpAttributes = (CK_ATTRIBUTE_PTR) malloc(CK_ATTRIBUTES_TEMPLATE_LENGTH * sizeof(CK_ATTRIBUTE)); + if (ckpAttributes == NULL) { + throwOutOfMemoryError(env, 0); + goto cleanup; + } + memcpy(ckpAttributes, ckpAttributesTemplate, CK_ATTRIBUTES_TEMPLATE_LENGTH * sizeof(CK_ATTRIBUTE)); + + // Get sizes for value buffers + (*ckpFunctions->C_GetAttributeValue)(ckSessionHandle, ckObjectHandle, + ckpAttributes, CK_ATTRIBUTES_TEMPLATE_LENGTH); + + for (i = 0; i < CK_ATTRIBUTES_TEMPLATE_LENGTH; i++) { + if ((ckpAttributes+i)->ulValueLen != (unsigned long)-1) { + totalDataSize += (ckpAttributes+i)->ulValueLen; + if ((ckpAttributes+i)->type == CKA_SENSITIVE) { + sensitiveAttributePosition = attributesCount; + } + attributesCount++; + } + } + + // Allocate a single buffer to hold valid attributes and attribute's values + // Buffer structure: [ attributes-size, [ ... attributes ... ], values-size, [ ... values ... ], + // wrapped-key-size, [ ... wrapped-key ... ] ] + // * sizes are expressed in bytes and data type is unsigned long + totalCkAttributesSize = attributesCount * sizeof(CK_ATTRIBUTE); + totalNativeKeyInfoArraySize = totalCkAttributesSize + sizeof(unsigned long) * 3 + totalDataSize; + + nativeKeyInfoArray = (*env)->NewByteArray(env, totalNativeKeyInfoArraySize); + if (nativeKeyInfoArray == NULL) { + goto cleanup; + } + + nativeKeyInfoArrayRaw = (*env)->GetByteArrayElements(env, nativeKeyInfoArray, NULL); + if (nativeKeyInfoArrayRaw == NULL) { + goto cleanup; + } + + wrappedKeySizePtr = (unsigned long*)(nativeKeyInfoArrayRaw + sizeof(unsigned long)*2 + + totalCkAttributesSize + totalDataSize); + (*(unsigned long*)nativeKeyInfoArrayRaw) = totalCkAttributesSize; + (*(unsigned long*)(nativeKeyInfoArrayRaw + sizeof(unsigned long) + totalCkAttributesSize)) = totalDataSize; + *wrappedKeySizePtr = 0; + + nativeKeyInfoArrayRawCkAttributes = nativeKeyInfoArrayRaw + sizeof(unsigned long); + nativeKeyInfoArrayRawCkAttributesPtr = nativeKeyInfoArrayRawCkAttributes; + nativeKeyInfoArrayRawDataPtr = nativeKeyInfoArrayRaw + totalCkAttributesSize + sizeof(unsigned long) * 2; + + for (i = 0; i < CK_ATTRIBUTES_TEMPLATE_LENGTH; i++) { + if ((ckpAttributes+i)->ulValueLen != (unsigned long)-1) { + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).type = (ckpAttributes+i)->type; + if ((ckpAttributes+i)->ulValueLen != 0) { + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).pValue = nativeKeyInfoArrayRawDataPtr; + } else { + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).pValue = 0; + } + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).ulValueLen = (ckpAttributes+i)->ulValueLen; + nativeKeyInfoArrayRawDataPtr += (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).ulValueLen; + nativeKeyInfoArrayRawCkAttributesPtr += sizeof(CK_ATTRIBUTE); + } + } + + // Get attribute's values + rv = (*ckpFunctions->C_GetAttributeValue)(ckSessionHandle, ckObjectHandle, + (CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributes, attributesCount); + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + goto cleanup; + } + + if ((sensitiveAttributePosition != (unsigned int)-1) && + *(CK_BBOOL*)(((CK_ATTRIBUTE_PTR)(((CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributes) + +sensitiveAttributePosition))->pValue) == CK_TRUE) { + // Key is sensitive. Need to extract it wrapped. + if (jWrappingKeyHandle != -1) { + ckMechanism.mechanism = CKM_AES_CBC_PAD; + ckMechanism.pParameter = &iv; + ckMechanism.ulParameterLen = 16; + rv = (*ckpFunctions->C_WrapKey)(ckSessionHandle, &ckMechanism, jLongToCKULong(jWrappingKeyHandle), + ckObjectHandle, NULL_PTR, &ckWrappedKeyLength); + if (ckWrappedKeyLength != 0) { + // Allocate space for getting the wrapped key + nativeKeyInfoWrappedKeyArray = (*env)->NewByteArray(env, + totalNativeKeyInfoArraySize + ckWrappedKeyLength); + if (nativeKeyInfoWrappedKeyArray == NULL) { + goto cleanup; + } + nativeKeyInfoWrappedKeyArrayRaw = (*env)->GetByteArrayElements(env, nativeKeyInfoWrappedKeyArray, NULL); + if (nativeKeyInfoWrappedKeyArrayRaw == NULL) { + goto cleanup; + } + memcpy(nativeKeyInfoWrappedKeyArrayRaw, nativeKeyInfoArrayRaw, totalNativeKeyInfoArraySize); + wrappedKeySizeWrappedKeyArrayPtr = (unsigned long*)(nativeKeyInfoWrappedKeyArrayRaw + + sizeof(unsigned long)*2 + totalCkAttributesSize + totalDataSize); + *wrappedKeySizeWrappedKeyArrayPtr = (unsigned long)ckWrappedKeyLength; + wrappedKeyBufferPtr = (unsigned char*)wrappedKeySizeWrappedKeyArrayPtr + sizeof(unsigned long); + rv = (*ckpFunctions->C_WrapKey)(ckSessionHandle, &ckMechanism, jLongToCKULong(jWrappingKeyHandle), + ckObjectHandle, wrappedKeyBufferPtr, &ckWrappedKeyLength); + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + goto cleanup; + } + *wrappedKeySizeWrappedKeyArrayPtr = (unsigned long)ckWrappedKeyLength; + } else { + goto cleanup; + } + } else { + goto cleanup; + } + returnValue = nativeKeyInfoWrappedKeyArray; + } else { + returnValue = nativeKeyInfoArray; + } + +cleanup: + if (ckpAttributes != NULL) { + free(ckpAttributes); + } + + if (nativeKeyInfoArrayRaw != NULL) { + (*env)->ReleaseByteArrayElements(env, nativeKeyInfoArray, nativeKeyInfoArrayRaw, 0); + } + + if (nativeKeyInfoWrappedKeyArrayRaw != NULL) { + (*env)->ReleaseByteArrayElements(env, nativeKeyInfoWrappedKeyArray, nativeKeyInfoWrappedKeyArrayRaw, 0); + } + + if (nativeKeyInfoArray != NULL && returnValue != nativeKeyInfoArray) { + (*env)->DeleteLocalRef(env, nativeKeyInfoArray); + } + + if (nativeKeyInfoWrappedKeyArray != NULL && returnValue != nativeKeyInfoWrappedKeyArray) { + (*env)->DeleteLocalRef(env, nativeKeyInfoWrappedKeyArray); + } + + return returnValue; +} +#endif + +#ifdef P11_ENABLE_CREATENATIVEKEY +/* + * Class: sun_security_pkcs11_wrapper_PKCS11 + * Method: createNativeKey + * Signature: (J[BJ)J + * Parametermapping: *PKCS11* + * @param jlong jSessionHandle CK_SESSION_HANDLE hSession + * @param jbyteArray jNativeKeyInfo - + * @param jlong jWrappingKeyHandle CK_OBJECT_HANDLE hObject + * @return jlong jKeyHandle CK_OBJECT_HANDLE hObject + */ +JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_createNativeKey + (JNIEnv *env, jobject obj, jlong jSessionHandle, jbyteArray jNativeKeyInfo, jlong jWrappingKeyHandle) +{ + CK_OBJECT_HANDLE ckObjectHandle; + CK_RV rv; + CK_SESSION_HANDLE ckSessionHandle = jLongToCKULong(jSessionHandle); + jbyte* nativeKeyInfoArrayRaw = NULL; + jlong jObjectHandle = 0L; + unsigned long totalCkAttributesSize = 0UL, nativeKeyInfoCkAttributesCount = 0UL; + jbyte* nativeKeyInfoArrayRawCkAttributes = NULL; + jbyte* nativeKeyInfoArrayRawCkAttributesPtr = NULL; + jbyte* nativeKeyInfoArrayRawDataPtr = NULL; + unsigned long totalDataSize = 0UL; + unsigned long* wrappedKeySizePtr = NULL; + unsigned int i = 0U; + CK_MECHANISM ckMechanism = {0x0}; + char iv[16] = {0x0}; + CK_ULONG ckWrappedKeyLength = 0UL; + CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj); + + if (ckpFunctions == NULL) { goto cleanup; } + + nativeKeyInfoArrayRaw = (*env)->GetByteArrayElements(env, jNativeKeyInfo, NULL); + if (nativeKeyInfoArrayRaw == NULL) { + goto cleanup; + } + + totalCkAttributesSize = *(unsigned long*)nativeKeyInfoArrayRaw; + nativeKeyInfoCkAttributesCount = totalCkAttributesSize/sizeof(CK_ATTRIBUTE); + nativeKeyInfoArrayRawCkAttributes = nativeKeyInfoArrayRaw + sizeof(unsigned long); + nativeKeyInfoArrayRawCkAttributesPtr = nativeKeyInfoArrayRawCkAttributes; + nativeKeyInfoArrayRawDataPtr = nativeKeyInfoArrayRaw + totalCkAttributesSize + sizeof(unsigned long) * 2; + totalDataSize = *(unsigned long*)(nativeKeyInfoArrayRaw + totalCkAttributesSize + sizeof(unsigned long)); + wrappedKeySizePtr = (unsigned long*)(nativeKeyInfoArrayRaw + sizeof(unsigned long)*2 + + totalCkAttributesSize + totalDataSize); + + for (i = 0; i < nativeKeyInfoCkAttributesCount; i++) { + if ((*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).ulValueLen > 0) { + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).pValue = nativeKeyInfoArrayRawDataPtr; + } + nativeKeyInfoArrayRawDataPtr += (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).ulValueLen; + nativeKeyInfoArrayRawCkAttributesPtr += sizeof(CK_ATTRIBUTE); + } + + if (*wrappedKeySizePtr == 0) { + // Not a wrapped key + rv = (*ckpFunctions->C_CreateObject)(ckSessionHandle, (CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributes, + jLongToCKULong(nativeKeyInfoCkAttributesCount), &ckObjectHandle); + } else { + // Wrapped key + ckMechanism.mechanism = CKM_AES_CBC_PAD; + ckMechanism.pParameter = &iv; + ckMechanism.ulParameterLen = 16; + rv = (*ckpFunctions->C_UnwrapKey)(ckSessionHandle, &ckMechanism, jLongToCKULong(jWrappingKeyHandle), + (CK_BYTE_PTR)(wrappedKeySizePtr + 1), *wrappedKeySizePtr, (CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributes, + jLongToCKULong(nativeKeyInfoCkAttributesCount), &ckObjectHandle); + } + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + goto cleanup; + } + + jObjectHandle = ckULongToJLong(ckObjectHandle); + +cleanup: + + if (nativeKeyInfoArrayRaw != NULL) { + (*env)->ReleaseByteArrayElements(env, jNativeKeyInfo, nativeKeyInfoArrayRaw, JNI_ABORT); + } + + return jObjectHandle; +} +#endif + #ifdef P11_ENABLE_C_GENERATEKEY /* * Class: sun_security_pkcs11_wrapper_PKCS11 --- old/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h 2018-06-04 19:27:30.372749681 -0300 +++ new/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h 2018-06-04 19:27:30.143748053 -0300 @@ -548,6 +548,7 @@ #define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600) #define CKA_VENDOR_DEFINED 0x80000000 +#define CKA_NETSCAPE_DB 0xD5A0DB00 /* CK_ATTRIBUTE is a structure that includes the type, length --- old/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h 2018-06-04 19:27:30.936753690 -0300 +++ new/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h 2018-06-04 19:27:30.766752482 -0300 @@ -151,6 +151,8 @@ #undef P11_ENABLE_C_GETFUNCTIONSTATUS #undef P11_ENABLE_C_CANCELFUNCTION #undef P11_ENABLE_C_WAITFORSLOTEVENT +#define P11_ENABLE_GETNATIVEKEYINFO +#define P11_ENABLE_CREATENATIVEKEY /* include the platform dependent part of the header */ #include "p11_md.h"