# HG changeset patch # User mbalao # Date 1543509383 10800 # Node ID 5170dc2bcf64f280f9bcb2ca16eb3451c07fdd8f # Parent bd8df96decba78b3ff07bde6dc2c155e26a78d48 6913047: Long term memory leak when using PKCS11 and JCE exceeds 32 bit process address space Summary: Extract cryptographic keys within NSS PKCS11 software tokens for memory management purposes. Reviewed-by: valeriep diff -r bd8df96decba -r 5170dc2bcf64 src/java.base/share/lib/security/default.policy --- a/src/java.base/share/lib/security/default.policy Fri Jan 11 14:48:19 2019 +0000 +++ b/src/java.base/share/lib/security/default.policy Thu Nov 29 13:36:23 2018 -0300 @@ -127,6 +127,7 @@ permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; permission java.lang.RuntimePermission "loadLibrary.j2pkcs11"; permission java.util.PropertyPermission "sun.security.pkcs11.allowSingleThreadedModules", "read"; + permission java.util.PropertyPermission "sun.security.pkcs11.disableKeyExtraction", "read"; permission java.util.PropertyPermission "os.name", "read"; permission java.util.PropertyPermission "os.arch", "read"; permission java.util.PropertyPermission "jdk.crypto.KeyAgreement.legacyKDF", "read"; diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -400,19 +400,35 @@ } } - private void cancelOperation() { - if (initialized == false) { + // reset the states to the pre-initialized values + // need to be called after doFinal or prior to re-init + private void reset(boolean doCancel) { + if (!initialized) { return; } - - if ((session == null) || (token.explicitCancel == false)) { - return; - } + initialized = false; try { - if (session.hasObjects() == false) { - session = token.killSession(session); + if (session == null) { return; - } else { + } + if (doCancel && token.explicitCancel) { + cancelOperation(); + } + } finally { + p11Key.releaseKeyID(); + 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 +437,46 @@ } 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) { + if (!initialized) { initialize(); } } 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(); + long p11KeyID = p11Key.getKeyID(); 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); + token.p11.C_EncryptInit(session.id(), mechParams, p11KeyID); } else { - token.p11.C_DecryptInit(session.id(), mechParams, p11Key.keyID); + token.p11.C_DecryptInit(session.id(), mechParams, p11KeyID); } - } catch (PKCS11Exception ex) { - // release session when initialization failed + } catch (PKCS11Exception e) { + p11Key.releaseKeyID(); session = token.releaseSession(session); - throw ex; + throw e; } + initialized = true; bytesBuffered = 0; padBufferLen = 0; - initialized = true; } // if update(inLen) is called, how big does the output buffer have to be? @@ -485,18 +507,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 { diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DHKeyFactory.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DHKeyFactory.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DHKeyFactory.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,7 +221,12 @@ new CK_ATTRIBUTE(CKA_PRIME), new CK_ATTRIBUTE(CKA_BASE), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } 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); + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } KeySpec spec = new DHPrivateKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger(), diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11DSAKeyFactory.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -218,7 +218,12 @@ new CK_ATTRIBUTE(CKA_SUBPRIME), new CK_ATTRIBUTE(CKA_BASE), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } 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); + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } KeySpec spec = new DSAPrivateKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger(), diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Digest.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Digest.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Digest.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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); @@ -254,6 +255,7 @@ } fetchSession(); + long p11KeyID = p11Key.getKeyID(); try { if (state == S_BUFFERED) { token.p11.C_DigestInit(session.id(), mechanism); @@ -264,10 +266,12 @@ token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs); bufOfs = 0; } - token.p11.C_DigestKey(session.id(), p11Key.keyID); + token.p11.C_DigestKey(session.id(), p11KeyID); } catch (PKCS11Exception e) { engineReset(); throw new ProviderException("update(SecretKey) failed", e); + } finally { + p11Key.releaseKeyID(); } } diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,6 +120,7 @@ throw new IllegalStateException("Not initialized correctly"); } Session session = null; + long privKeyID = privateKey.getKeyID(); try { session = token.getOpSession(); CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { @@ -131,8 +132,8 @@ 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, - attributes); + new CK_MECHANISM(mechanism, ckParams), privKeyID, + attributes); attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE) }; @@ -143,6 +144,7 @@ } catch (PKCS11Exception e) { throw new ProviderException("Could not derive key", e); } finally { + privateKey.releaseKeyID(); publicValue = null; token.releaseSession(session); } @@ -182,6 +184,7 @@ } long keyType = CKK_GENERIC_SECRET; Session session = null; + long privKeyID = privateKey.getKeyID(); try { session = token.getObjSession(); CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { @@ -193,8 +196,8 @@ 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, - attributes); + new CK_MECHANISM(mechanism, ckParams), privKeyID, + attributes); CK_ATTRIBUTE[] lenAttributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE_LEN), }; @@ -206,6 +209,7 @@ } catch (PKCS11Exception e) { throw new InvalidKeyException("Could not derive key", e); } finally { + privateKey.releaseKeyID(); publicValue = null; token.releaseSession(session); } diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -290,13 +290,16 @@ new CK_ATTRIBUTE(CKA_EC_POINT), new CK_ATTRIBUTE(CKA_EC_PARAMS), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + long keyID = key.getKeyID(); try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); ECPoint point = decodePoint(attributes[0].getByteArray(), params.getCurve()); return keySpec.cast(new ECPublicKeySpec(point, params)); } catch (IOException e) { throw new InvalidKeySpecException("Could not parse key", e); + } finally { + key.releaseKeyID(); } } else { // X.509 handled in superclass throw new InvalidKeySpecException("Only ECPublicKeySpec and " @@ -312,13 +315,16 @@ new CK_ATTRIBUTE(CKA_VALUE), new CK_ATTRIBUTE(CKA_EC_PARAMS), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + long keyID = key.getKeyID(); try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); ECParameterSpec params = decodeParameters(attributes[1].getByteArray()); return keySpec.cast( new ECPrivateKeySpec(attributes[0].getBigInteger(), params)); } catch (IOException e) { throw new InvalidKeySpecException("Could not parse key", e); + } finally { + key.releaseKeyID(); } } else { // PKCS#8 handled in superclass throw new InvalidKeySpecException("Only ECPrivateKeySpec " diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java Thu Nov 29 13:36:23 2018 -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,12 +44,15 @@ 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; import sun.security.util.DerValue; import sun.security.util.Length; import sun.security.util.ECUtil; +import sun.security.jca.JCAUtil; /** * Key implementation classes. @@ -83,23 +85,38 @@ // algorithm name, returned by getAlgorithm(), etc. final String algorithm; - // key id - final long keyID; - // effective key length of the key, e.g. 56 for a DES key final int keyLength; // flags indicating whether the key is a token object, sensitive, extractable final boolean tokenObject, sensitive, extractable; - // phantom reference notification clean up for session keys - private final SessionKeyRef sessionKeyRef; + private final NativeKeyHolder keyIDHolder; + + private static final boolean DISABLE_NATIVE_KEYS_EXTRACTION; + + /** + * {@systemProperty sun.security.pkcs11.disableKeyExtraction} property + * indicating whether or not cryptographic keys within tokens are + * extracted to a Java byte array for memory management purposes. + * + * Key extraction affects NSS PKCS11 library only. + * + */ + static { + PrivilegedAction getKeyExtractionProp = + () -> System.getProperty( + "sun.security.pkcs11.disableKeyExtraction", "false"); + String disableKeyExtraction = + AccessController.doPrivileged(getKeyExtractionProp); + DISABLE_NATIVE_KEYS_EXTRACTION = + "true".equalsIgnoreCase(disableKeyExtraction); + } P11Key(String type, Session session, long keyID, String algorithm, int keyLength, CK_ATTRIBUTE[] attributes) { this.type = type; this.token = session.token; - this.keyID = keyID; this.algorithm = algorithm; this.keyLength = keyLength; boolean tokenObject = false; @@ -119,11 +136,21 @@ this.tokenObject = tokenObject; this.sensitive = sensitive; this.extractable = extractable; - if (tokenObject == false) { - sessionKeyRef = new SessionKeyRef(this, keyID, session); - } else { - sessionKeyRef = null; - } + char[] tokenLabel = this.token.tokenInfo.label; + boolean isNSS = (tokenLabel[0] == 'N' && tokenLabel[1] == 'S' + && tokenLabel[2] == 'S'); + boolean extractKeyInfo = (!DISABLE_NATIVE_KEYS_EXTRACTION && isNSS && + extractable && !tokenObject); + this.keyIDHolder = new NativeKeyHolder(this, keyID, session, extractKeyInfo, + tokenObject); + } + + public long getKeyID() { + return keyIDHolder.getKeyID(); + } + + public void releaseKeyID() { + keyIDHolder.releaseKeyID(); } // see JCA spec @@ -208,8 +235,7 @@ token.ensureValid(); String s1 = token.provider.getName() + " " + algorithm + " " + type + " key, " + keyLength + " bits"; - s1 += " (id " + keyID + ", " - + (tokenObject ? "token" : "session") + " object"; + s1 += (tokenObject ? "token" : "session") + " object"; if (isPublic()) { s1 += ")"; } else { @@ -241,12 +267,15 @@ void fetchAttributes(CK_ATTRIBUTE[] attributes) { Session tempSession = null; + long keyID = this.getKeyID(); try { tempSession = token.getOpSession(); - token.p11.C_GetAttributeValue(tempSession.id(), keyID, attributes); + token.p11.C_GetAttributeValue(tempSession.id(), keyID, + attributes); } catch (PKCS11Exception e) { throw new ProviderException(e); } finally { + this.releaseKeyID(); token.releaseSession(tempSession); } } @@ -293,7 +322,8 @@ 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); } static SecretKey masterSecretKey(Session session, long keyID, String algorithm, @@ -303,8 +333,9 @@ new CK_ATTRIBUTE(CKA_SENSITIVE), new CK_ATTRIBUTE(CKA_EXTRACTABLE), }); - return new P11TlsMasterSecretKey - (session, keyID, algorithm, keyLength, attributes, major, minor); + return new P11TlsMasterSecretKey( + session, keyID, algorithm, keyLength, attributes, major, + minor); } // we assume that all components of public keys are always accessible @@ -312,17 +343,17 @@ int keyLength, CK_ATTRIBUTE[] attributes) { switch (algorithm) { case "RSA": - return new P11RSAPublicKey - (session, keyID, algorithm, keyLength, attributes); + return new P11RSAPublicKey(session, keyID, algorithm, + keyLength, attributes); case "DSA": - return new P11DSAPublicKey - (session, keyID, algorithm, keyLength, attributes); + return new P11DSAPublicKey(session, keyID, algorithm, + keyLength, attributes); case "DH": - return new P11DHPublicKey - (session, keyID, algorithm, keyLength, attributes); + return new P11DHPublicKey(session, keyID, algorithm, + keyLength, attributes); case "EC": - return new P11ECPublicKey - (session, keyID, algorithm, keyLength, attributes); + return new P11ECPublicKey(session, keyID, algorithm, + keyLength, attributes); default: throw new ProviderException ("Unknown public key algorithm " + algorithm); @@ -367,21 +398,21 @@ crtKey = false; } if (crtKey) { - return new P11RSAPrivateKey - (session, keyID, algorithm, keyLength, attributes, attrs2); + return new P11RSAPrivateKey(session, keyID, algorithm, + keyLength, attributes, attrs2); } else { - return new P11RSAPrivateNonCRTKey - (session, keyID, algorithm, keyLength, attributes); + return new P11RSAPrivateNonCRTKey(session, keyID, + algorithm, keyLength, attributes); } case "DSA": - return new P11DSAPrivateKey - (session, keyID, algorithm, keyLength, attributes); + return new P11DSAPrivateKey(session, keyID, algorithm, + keyLength, attributes); case "DH": - return new P11DHPrivateKey - (session, keyID, algorithm, keyLength, attributes); + return new P11DHPrivateKey(session, keyID, algorithm, + keyLength, attributes); case "EC": - return new P11ECPrivateKey - (session, keyID, algorithm, keyLength, attributes); + return new P11ECPrivateKey(session, keyID, algorithm, + keyLength, attributes); default: throw new ProviderException ("Unknown private key algorithm " + algorithm); @@ -435,17 +466,19 @@ b = encoded; if (b == null) { Session tempSession = null; + long keyID = this.getKeyID(); try { tempSession = token.getOpSession(); CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE), }; token.p11.C_GetAttributeValue - (tempSession.id(), keyID, attributes); + (tempSession.id(), keyID, attributes); b = attributes[0].getByteArray(); } catch (PKCS11Exception e) { throw new ProviderException(e); } finally { + this.releaseKeyID(); token.releaseSession(tempSession); } encoded = b; @@ -1100,6 +1133,153 @@ } } +final class NativeKeyHolder { + + private static long nativeKeyWrapperKeyID = 0; + private static CK_MECHANISM nativeKeyWrapperMechanism = null; + + private final P11Key p11Key; + private final byte[] nativeKeyInfo; + + // destroyed and recreated when refCount toggles to 1 + private long keyID; + + private boolean isTokenObject; + + // phantom reference notification clean up for session keys + private SessionKeyRef ref; + + private int refCount; + + NativeKeyHolder(P11Key p11Key, long keyID, Session keySession, + boolean extractKeyInfo, boolean isTokenObject) { + this.p11Key = p11Key; + this.keyID = keyID; + this.refCount = -1; + byte[] ki = null; + if (isTokenObject) { + this.ref = null; + } else { + this.ref = new SessionKeyRef(p11Key, keyID, keySession); + + // Try extracting key info, if any error, disable it + Token token = p11Key.token; + if (extractKeyInfo) { + try { + if (p11Key.sensitive && nativeKeyWrapperKeyID == 0) { + synchronized(NativeKeyHolder.class) { + // 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); + byte[] iv = new byte[16]; + JCAUtil.getSecureRandom().nextBytes(iv); + nativeKeyWrapperMechanism = new CK_MECHANISM + (CKM_AES_CBC_PAD, iv); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(wrappingSession); + } + } + } + Session opSession = null; + try { + opSession = token.getOpSession(); + ki = p11Key.token.p11.getNativeKeyInfo(opSession.id(), + keyID, nativeKeyWrapperKeyID, nativeKeyWrapperMechanism); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(opSession); + } + } catch (PKCS11Exception e) { + // best effort + } + } + } + this.nativeKeyInfo = ((ki == null || ki.length == 0)? null : ki); + } + + long getKeyID() throws ProviderException { + if (this.nativeKeyInfo != null) { + synchronized(this.nativeKeyInfo) { + if (this.refCount == -1) { + this.refCount = 0; + } + int cnt = (this.refCount)++; + if (keyID == 0) { + if (cnt != 0) { + throw new RuntimeException( + "Error: null keyID with non-zero refCount " + cnt); + } + if (this.ref != null) { + throw new RuntimeException( + "Error: null keyID with non-null session ref"); + } + Token token = p11Key.token; + // Create keyID using nativeKeyInfo + Session session = null; + try { + session = token.getObjSession(); + this.keyID = token.p11.createNativeKey(session.id(), + nativeKeyInfo, nativeKeyWrapperKeyID, nativeKeyWrapperMechanism); + this.ref = new SessionKeyRef(p11Key, this.keyID, session); + } catch (PKCS11Exception e) { + this.refCount--; + throw new ProviderException("Error recreating native key", e); + } finally { + token.releaseSession(session); + } + } else { + if (cnt < 0) { + throw new RuntimeException("ERROR: negative refCount"); + } + } + } + } + return keyID; + } + + void releaseKeyID() { + if (this.nativeKeyInfo != null) { + synchronized(this.nativeKeyInfo) { + if (this.refCount == -1) { + throw new RuntimeException("Error: miss match getKeyID call"); + } + int cnt = --(this.refCount); + if (cnt == 0) { + // destroy + if (this.keyID == 0) { + throw new RuntimeException("ERROR: null keyID can't be destroyed"); + } + + if (this.ref == null) { + throw new RuntimeException("ERROR: null session ref can't be disposed"); + } + // destroy + this.keyID = 0; + this.ref = this.ref.dispose(); + } else { + if (cnt < 0) { + // should never happen as we start count at 1 and pair get/release calls + throw new RuntimeException("wrong refCount value: " + cnt); + } + } + } + } + } +} + /* * NOTE: Must use PhantomReference here and not WeakReference * otherwise the key maybe cleared before other objects which @@ -1117,64 +1297,50 @@ } private static void drainRefQueueBounded() { - Session sess = null; - Token tkn = null; while (true) { SessionKeyRef next = (SessionKeyRef) refQueue.poll(); if (next == null) { break; } - - // If the token is still valid, try to remove the object - if (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 { - if (next.session.token != tkn || sess == null) { - // Release session if not using previous token - if (tkn != null && sess != null) { - tkn.releaseSession(sess); - sess = null; - } - - tkn = next.session.token; - sess = tkn.getOpSession(); - } - next.disposeNative(sess); - } catch (PKCS11Exception e) { - // ignore - } - } - // Regardless of native results, dispose of java references next.dispose(); } - - if (tkn != null && sess != null) { - tkn.releaseSession(sess); - } } - // handle to the native key - private long keyID; - private Session session; + // handle to the native key and the session it is generated under + private final long keyID; + private final Session session; - SessionKeyRef(P11Key key , long keyID, Session session) { - super(key, refQueue); + SessionKeyRef(P11Key p11Key, long keyID, Session session) { + super(p11Key, refQueue); + if (session == null) { + throw new ProviderException("key must be associated with a session"); + } this.keyID = keyID; this.session = session; this.session.addObject(); + refList.add(this); drainRefQueueBounded(); } - private void disposeNative(Session s) throws PKCS11Exception { - session.token.p11.C_DestroyObject(s.id(), keyID); - } - - private void dispose() { + SessionKeyRef dispose() { + Token token = session.token; + // If the token is still valid, try to remove the key object + if (token.isValid()) { + Session s = null; + try { + s = token.getOpSession(); + token.p11.C_DestroyObject(s.id(), keyID); + } catch (PKCS11Exception e) { + // best effort + } finally { + token.releaseSession(s); + } + } refList.remove(this); this.clear(); session.removeObject(); + return null; } public int compareTo(SessionKeyRef other) { diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -201,6 +201,7 @@ throw new IllegalStateException("Not initialized correctly"); } Session session = null; + long privKeyID = privateKey.getKeyID(); try { session = token.getOpSession(); CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { @@ -210,8 +211,9 @@ 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); + new CK_MECHANISM(mechanism, publicValue), privKeyID, + attributes); + attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE) }; @@ -237,6 +239,7 @@ } catch (PKCS11Exception e) { throw new ProviderException("Could not derive key", e); } finally { + privateKey.releaseKeyID(); publicValue = null; token.releaseSession(session); } @@ -325,6 +328,7 @@ } long keyType = CKK_GENERIC_SECRET; Session session = null; + long privKeyID = privateKey.getKeyID(); try { session = token.getObjSession(); CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { @@ -334,8 +338,8 @@ 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); + new CK_MECHANISM(mechanism, publicValue), privKeyID, + attributes); CK_ATTRIBUTE[] lenAttributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE_LEN), }; @@ -359,6 +363,7 @@ } catch (PKCS11Exception e) { throw new InvalidKeyException("Could not derive key", e); } finally { + privateKey.releaseKeyID(); publicValue = null; token.releaseSession(session); } diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1485,6 +1485,7 @@ } } + // retrieves the native key handle and either update it directly or make a copy private void updateP11Pkey(String alias, CK_ATTRIBUTE attribute, P11Key key) throws PKCS11Exception { @@ -1492,23 +1493,22 @@ // if session key, convert to token key. Session session = null; + long keyID = key.getKeyID(); try { session = token.getOpSession(); if (key.tokenObject == true) { - // token key - set new CKA_ID CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_ID, alias) }; token.p11.C_SetAttributeValue - (session.id(), key.keyID, attrs); + (session.id(), keyID, attrs); if (debug != null) { debug.println("updateP11Pkey set new alias [" + alias + "] for key entry"); } } else { - // session key - convert to token key and set CKA_ID CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { @@ -1518,7 +1518,8 @@ if (attribute != null) { attrs = addAttribute(attrs, attribute); } - token.p11.C_CopyObject(session.id(), key.keyID, attrs); + // creates a new token key with the desired CKA_ID + token.p11.C_CopyObject(session.id(), keyID, attrs); if (debug != null) { debug.println("updateP11Pkey copied private session key " + "for [" + @@ -1528,6 +1529,7 @@ } } finally { token.releaseSession(session); + key.releaseKeyID(); } } @@ -1894,10 +1896,12 @@ return attrs; } String alg = privateKey.getAlgorithm(); - if (id && alg.equals("RSA") && (publicKey instanceof RSAPublicKey)) { + if (alg.equals("RSA") && (publicKey instanceof RSAPublicKey)) { + if (id) { + BigInteger n = ((RSAPublicKey)publicKey).getModulus(); + attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(getMagnitude(n))); + } // CKA_NETSCAPE_DB not needed for RSA public keys - BigInteger n = ((RSAPublicKey)publicKey).getModulus(); - attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(getMagnitude(n))); } else if (alg.equals("DSA") && (publicKey instanceof DSAPublicKey)) { BigInteger y = ((DSAPublicKey)publicKey).getY(); if (id) { diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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,65 @@ 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.releaseKeyID(); + 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; + } else { + try { + token.p11.C_SignFinal(session.id(), 0); + } catch (PKCS11Exception e) { + throw new ProviderException("Cancel failed", e); + } } - try { - token.p11.C_SignFinal(session.id(), 0); - } catch (PKCS11Exception e) { - throw new ProviderException("Cancel failed", e); + } + + private void ensureInitialized() throws PKCS11Exception { + if (!initialized) { + initialize(); } } private void initialize() throws PKCS11Exception { - if (state == S_RESET) { - 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.p11.C_SignInit - (session.id(), ckMechanism, p11Key.keyID); - state = S_RESET; - } else { - state = S_UNINIT; + token.ensureValid(); + long p11KeyID = p11Key.getKeyID(); + try { + if (session == null) { + session = token.getOpSession(); + } + token.p11.C_SignInit(session.id(), ckMechanism, p11KeyID); + } catch (PKCS11Exception e) { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + throw e; } + initialized = true; } // see JCE spec @@ -181,18 +182,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,7 +192,7 @@ throw new InvalidAlgorithmParameterException ("Parameters not supported"); } - cancelOperation(); + reset(true); p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm); try { initialize(); @@ -215,13 +205,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 +228,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 +249,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); } diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -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) { @@ -241,80 +241,105 @@ } } - 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.releaseKeyID(); + session = token.releaseSession(session); } + } + + // should only called by reset as this method does not update other + // state variables such as "initialized" + private void cancelOperation() { + token.ensureValid(); if (session.hasObjects() == false) { session = token.killSession(session); return; - } - 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"); + } else { + try { + PKCS11 p11 = token.p11; + int inLen = maxInputSize; + int outLen = buffer.length; + long sessId = session.id(); + switch (mode) { + case MODE_ENCRYPT: + p11.C_Encrypt(sessId, buffer, 0, inLen, buffer, 0, outLen); + break; + case MODE_DECRYPT: + p11.C_Decrypt(sessId, buffer, 0, inLen, buffer, 0, outLen); + break; + case MODE_SIGN: + byte[] tmpBuffer = new byte[maxInputSize]; + p11.C_Sign(sessId, tmpBuffer); + break; + case MODE_VERIFY: + p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer, + 0, outLen); + break; + default: + throw new ProviderException("internal error"); + } + } catch (PKCS11Exception e) { + // XXX ensure this always works, ignore error } - } catch (PKCS11Exception e) { - // XXX ensure this always works, ignore error } } private void ensureInitialized() throws PKCS11Exception { token.ensureValid(); - if (initialized == false) { + if (!initialized) { initialize(); } } 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"); } - 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"); + long keyID = p11Key.getKeyID(); + try { + 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, keyID); + break; + case MODE_DECRYPT: + p11.C_DecryptInit(session.id(), ckMechanism, keyID); + break; + case MODE_SIGN: + p11.C_SignInit(session.id(), ckMechanism, keyID); + break; + case MODE_VERIFY: + p11.C_VerifyRecoverInit(session.id(), ckMechanism, keyID); + break; + default: + throw new AssertionError("internal error"); + } + bufOfs = 0; + initialized = true; + } catch (PKCS11Exception e) { + p11Key.releaseKeyID(); + session = token.releaseSession(session); + throw e; } - bufOfs = 0; - initialized = true; } private void implUpdate(byte[] in, int inOfs, int inLen) { @@ -377,8 +402,7 @@ throw (BadPaddingException)new BadPaddingException ("doFinal() failed").initCause(e); } finally { - initialized = false; - session = token.releaseSession(session); + reset(false); } } @@ -452,13 +476,17 @@ } } Session s = null; + long p11KeyID = p11Key.getKeyID(); + long sKeyID = sKey.getKeyID(); try { s = token.getOpSession(); return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism), - p11Key.keyID, sKey.keyID); + p11KeyID, sKeyID); } catch (PKCS11Exception e) { throw new InvalidKeyException("wrap() failed", e); } finally { + p11Key.releaseKeyID(); + sKey.releaseKeyID(); token.releaseSession(s); } } @@ -518,6 +546,7 @@ } else { Session s = null; SecretKey secretKey = null; + long p11KeyID = p11Key.getKeyID(); try { try { s = token.getObjSession(); @@ -528,9 +557,10 @@ }; attributes = token.getAttributes( O_IMPORT, CKO_SECRET_KEY, keyType, attributes); + long keyID = token.p11.C_UnwrapKey(s.id(), - new CK_MECHANISM(mechanism), p11Key.keyID, - wrappedKey, attributes); + new CK_MECHANISM(mechanism), p11KeyID, + wrappedKey, attributes); secretKey = P11Key.secretKey(s, keyID, algorithm, 48 << 3, attributes); } catch (PKCS11Exception e) { @@ -554,6 +584,7 @@ return secretKey; } finally { + p11Key.releaseKeyID(); token.releaseSession(s); } } diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java Thu Nov 29 13:36:23 2018 -0300 @@ -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); + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } KeySpec spec = new RSAPublicKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger() @@ -289,7 +294,13 @@ new CK_ATTRIBUTE(CKA_EXPONENT_2), new CK_ATTRIBUTE(CKA_COEFFICIENT), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } + KeySpec spec = new RSAPrivateCrtKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger(), @@ -307,7 +318,13 @@ new CK_ATTRIBUTE(CKA_MODULUS), new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT), }; - token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); + long keyID = key.getKeyID(); + try { + token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes); + } finally { + key.releaseKeyID(); + } + KeySpec spec = new RSAPrivateKeySpec( attributes[0].getBigInteger(), attributes[1].getBigInteger() diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,20 +146,24 @@ P11Key p11Key = (P11Key)key; if (p11Key.token == token) { if (extraAttrs != null) { + P11Key newP11Key = null; Session session = null; + long p11KeyID = p11Key.getKeyID(); try { session = token.getObjSession(); long newKeyID = token.p11.C_CopyObject(session.id(), - p11Key.keyID, extraAttrs); - p11Key = (P11Key) (P11Key.secretKey(session, + p11KeyID, extraAttrs); + newP11Key = (P11Key) (P11Key.secretKey(session, newKeyID, p11Key.algorithm, p11Key.keyLength, extraAttrs)); } catch (PKCS11Exception p11e) { throw new InvalidKeyException ("Cannot duplicate the PKCS11 key", p11e); } finally { + p11Key.releaseKeyID(); token.releaseSession(session); } + p11Key = newP11Key; } return p11Key; } diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java Thu Nov 29 13:36:23 2018 -0300 @@ -263,27 +263,33 @@ } } - 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.releaseKeyID(); + 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) { @@ -303,8 +309,8 @@ throw new ProviderException("cancel failed", e); } } else { // M_VERIFY + byte[] signature; try { - byte[] signature; if (keyAlgorithm.equals("DSA")) { signature = new byte[40]; } else { @@ -322,31 +328,48 @@ token.p11.C_Verify(session.id(), digest, signature); } } catch (PKCS11Exception e) { - // will fail since the signature is incorrect - // XXX check error code + long errorCode = e.getErrorCode(); + if ((errorCode == CKR_SIGNATURE_INVALID) || + (errorCode == CKR_SIGNATURE_LEN_RANGE)) { + // expected since signature is incorrect + return; + } + throw new ProviderException("cancel failed", e); } } - } finally { - session = token.releaseSession(session); + } + } + + private void ensureInitialized() { + + if (!initialized) { + initialize(); } } // assumes current state is initialized == false private void initialize() { + + if (p11Key == null) { + throw new ProviderException( + "Operation cannot be performed without " + + "calling engineInit first"); + } + long keyID = p11Key.getKeyID(); try { + token.ensureValid(); if (session == null) { session = token.getOpSession(); } if (mode == M_SIGN) { token.p11.C_SignInit(session.id(), - new CK_MECHANISM(mechanism), p11Key.keyID); + new CK_MECHANISM(mechanism), keyID); } else { token.p11.C_VerifyInit(session.id(), - new CK_MECHANISM(mechanism), p11Key.keyID); + new CK_MECHANISM(mechanism), keyID); } - initialized = true; } catch (PKCS11Exception e) { - // release session when initialization failed + p11Key.releaseKeyID(); session = token.releaseSession(session); throw new ProviderException("Initialization failed", e); } @@ -356,6 +379,7 @@ md.reset(); } } + initialized = true; } private void checkKeySize(String keyAlgo, Key key) @@ -444,6 +468,7 @@ @Override protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { + if (publicKey == null) { throw new InvalidKeyException("Key must not be null"); } @@ -451,7 +476,7 @@ if (publicKey != p11Key) { checkKeySize(keyAlgorithm, publicKey); } - cancelOperation(); + reset(true); mode = M_VERIFY; p11Key = P11KeyFactory.convertKey(token, publicKey, keyAlgorithm); initialize(); @@ -461,6 +486,7 @@ @Override protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { + if (privateKey == null) { throw new InvalidKeyException("Key must not be null"); } @@ -468,7 +494,7 @@ if (privateKey != p11Key) { checkKeySize(keyAlgorithm, privateKey); } - cancelOperation(); + reset(true); mode = M_SIGN; p11Key = P11KeyFactory.convertKey(token, privateKey, keyAlgorithm); initialize(); @@ -503,6 +529,7 @@ @Override protected void engineUpdate(byte[] b, int ofs, int len) throws SignatureException { + ensureInitialized(); if (len == 0) { return; @@ -521,8 +548,7 @@ } bytesProcessed += len; } catch (PKCS11Exception e) { - initialized = false; - session = token.releaseSession(session); + reset(false); throw new ProviderException(e); } break; @@ -546,6 +572,7 @@ // see JCA spec @Override protected void engineUpdate(ByteBuffer byteBuffer) { + ensureInitialized(); int len = byteBuffer.remaining(); if (len <= 0) { @@ -571,8 +598,7 @@ bytesProcessed += len; byteBuffer.position(ofs + len); } catch (PKCS11Exception e) { - initialized = false; - session = token.releaseSession(session); + reset(false); throw new ProviderException("Update failed", e); } break; @@ -589,6 +615,7 @@ bytesProcessed += len; break; default: + reset(false); throw new ProviderException("Internal error"); } } @@ -596,7 +623,9 @@ // see JCA spec @Override protected byte[] engineSign() throws SignatureException { + ensureInitialized(); + boolean doCancel = true; try { byte[] signature; if (type == T_UPDATE) { @@ -633,6 +662,8 @@ signature = token.p11.C_Sign(session.id(), data); } } + doCancel = false; + if (keyAlgorithm.equals("RSA")) { return signature; } else { @@ -643,20 +674,21 @@ } } } catch (PKCS11Exception pe) { + doCancel = false; throw new ProviderException(pe); } catch (SignatureException | ProviderException e) { - cancelOperation(); throw e; } finally { - initialized = false; - session = token.releaseSession(session); + reset(doCancel); } } // see JCA spec @Override protected boolean engineVerify(byte[] signature) throws SignatureException { + ensureInitialized(); + boolean doCancel = true; try { if (!p1363Format) { if (keyAlgorithm.equals("DSA")) { @@ -698,8 +730,10 @@ token.p11.C_Verify(session.id(), data, signature); } } + doCancel = false; return true; } catch (PKCS11Exception pe) { + doCancel = false; long errorCode = pe.getErrorCode(); if (errorCode == CKR_SIGNATURE_INVALID) { return false; @@ -714,11 +748,9 @@ } throw new ProviderException(pe); } catch (SignatureException | ProviderException e) { - cancelOperation(); throw e; } finally { - initialized = false; - session = token.releaseSession(session); + reset(doCancel); } } diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java Thu Nov 29 13:36:23 2018 -0300 @@ -189,8 +189,13 @@ attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); // the returned keyID is a dummy, ignore - token.p11.C_DeriveKey(session.id(), - ckMechanism, p11Key.keyID, attributes); + long p11KeyID = p11Key.getKeyID(); + try { + token.p11.C_DeriveKey(session.id(), + ckMechanism, p11KeyID, attributes); + } finally { + p11Key.releaseKeyID(); + } CK_SSL3_KEY_MAT_OUT out = null; if (params instanceof CK_SSL3_KEY_MAT_PARAMS) { diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsMasterSecretGenerator.java Thu Nov 29 13:36:23 2018 -0300 @@ -160,12 +160,13 @@ ckMechanism = new CK_MECHANISM(mechanism, params); } Session session = null; + long p11KeyID = p11Key.getKeyID(); try { 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(), - ckMechanism, p11Key.keyID, attributes); + ckMechanism, p11KeyID, attributes); int major, minor; if (ckVersion == null) { major = -1; @@ -174,12 +175,12 @@ major = ckVersion.major; minor = ckVersion.minor; } - SecretKey key = P11Key.masterSecretKey(session, keyID, + return P11Key.masterSecretKey(session, keyID, "TlsMasterSecret", 48 << 3, attributes, major, minor); - return key; } catch (Exception e) { throw new ProviderException("Could not generate key", e); } finally { + p11Key.releaseKeyID(); token.releaseSession(session); } } diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsPrfGenerator.java Thu Nov 29 13:36:23 2018 -0300 @@ -146,34 +146,36 @@ Functions.getHashMechId(spec.getPRFHashAlg()), spec.getOutputLength(), ulServerOrClient); Session session = null; + long keyID = p11Key.getKeyID(); try { session = token.getOpSession(); token.p11.C_SignInit(session.id(), - new CK_MECHANISM(mechanism, params), p11Key.keyID); + new CK_MECHANISM(mechanism, params), keyID); token.p11.C_SignUpdate(session.id(), 0, seed, 0, seed.length); byte[] out = token.p11.C_SignFinal (session.id(), spec.getOutputLength()); - k = new SecretKeySpec(out, "TlsPrf"); + return new SecretKeySpec(out, "TlsPrf"); } catch (PKCS11Exception e) { throw new ProviderException("Could not calculate PRF", e); } finally { + p11Key.releaseKeyID(); token.releaseSession(session); } } else { throw new ProviderException("Only Finished message authentication code"+ " generation supported for TLS 1.2."); } - return k; } byte[] label = P11Util.getBytesUTF8(spec.getLabel()); if (mechanism == CKM_NSS_TLS_PRF_GENERAL) { Session session = null; + long keyID = p11Key.getKeyID(); try { session = token.getOpSession(); token.p11.C_SignInit - (session.id(), new CK_MECHANISM(mechanism), p11Key.keyID); + (session.id(), new CK_MECHANISM(mechanism), 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 @@ -182,6 +184,7 @@ } catch (PKCS11Exception e) { throw new ProviderException("Could not calculate PRF", e); } finally { + p11Key.releaseKeyID(); token.releaseSession(session); } } @@ -192,15 +195,16 @@ CK_TLS_PRF_PARAMS params = new CK_TLS_PRF_PARAMS(seed, label, out); Session session = null; + long keyID = p11Key.getKeyID(); try { session = token.getOpSession(); - long keyID = token.p11.C_DeriveKey(session.id(), - new CK_MECHANISM(mechanism, params), p11Key.keyID, null); - // ignore keyID, returned PRF bytes are in 'out' + token.p11.C_DeriveKey(session.id(), + new CK_MECHANISM(mechanism, params), keyID, null); return new SecretKeySpec(out, "TlsPrf"); } catch (PKCS11Exception e) { throw new ProviderException("Could not calculate PRF", e); } finally { + p11Key.releaseKeyID(); token.releaseSession(session); } } diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java Thu Nov 29 13:36:23 2018 -0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -1291,6 +1291,46 @@ ******************************************************************************/ /** + * 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 key handle for wrapping the extracted sensitive keys. + * -1 if not used. + * @param pWrappingMech mechanism for wrapping the extracted sensitive keys + * @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, CK_MECHANISM pWrappingMech) 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 key handle for unwrapping the extracted sensitive keys. + * -1 if not used. + * @param pWrappingMech mechanism for unwrapping the extracted sensitive keys + * @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, CK_MECHANISM pWrappingMech) throws PKCS11Exception; + + /** * C_GenerateKey generates a secret key, creating a new key * object. * (Key management) diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_keymgmt.c Thu Nov 29 13:36:23 2018 -0300 @@ -54,6 +54,444 @@ #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: (JJJLsun/security/pkcs11/wrapper/CK_MECHANISM;)[B + * Parametermapping: *PKCS11* + * @param jlong jSessionHandle CK_SESSION_HANDLE hSession + * @param jlong jKeyHandle CK_OBJECT_HANDLE hObject + * @param jlong jWrappingKeyHandle CK_OBJECT_HANDLE hObject + * @param jobject jWrappingMech CK_MECHANISM_PTR pMechanism + * @return jbyteArray jNativeKeyInfo - + */ +JNIEXPORT jbyteArray JNICALL +Java_sun_security_pkcs11_wrapper_PKCS11_getNativeKeyInfo + (JNIEnv *env, jobject obj, jlong jSessionHandle, jlong jKeyHandle, + jlong jWrappingKeyHandle, jobject jWrappingMech) +{ + 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; + unsigned long totalDataSize = 0UL, attributesCount = 0UL; + unsigned long totalCkAttributesSize = 0UL, totalNativeKeyInfoArraySize = 0UL; + unsigned long* wrappedKeySizePtr = NULL; + jbyte* nativeKeyInfoArrayRawCkAttributes = NULL; + jbyte* nativeKeyInfoArrayRawCkAttributesPtr = NULL; + jbyte* nativeKeyInfoArrayRawDataPtr = NULL; + CK_MECHANISM ckMechanism; + 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); + CK_OBJECT_CLASS class; + CK_KEY_TYPE keyType; + CK_BBOOL sensitive; + CK_BBOOL netscapeAttributeValueNeeded = CK_FALSE; + CK_ATTRIBUTE ckNetscapeAttributesTemplate[4]; + ckNetscapeAttributesTemplate[0].type = CKA_CLASS; + ckNetscapeAttributesTemplate[1].type = CKA_KEY_TYPE; + ckNetscapeAttributesTemplate[2].type = CKA_SENSITIVE; + ckNetscapeAttributesTemplate[3].type = CKA_NETSCAPE_DB; + ckNetscapeAttributesTemplate[0].pValue = &class; + ckNetscapeAttributesTemplate[1].pValue = &keyType; + ckNetscapeAttributesTemplate[2].pValue = &sensitive; + ckNetscapeAttributesTemplate[3].pValue = 0; + ckNetscapeAttributesTemplate[0].ulValueLen = sizeof(class); + ckNetscapeAttributesTemplate[1].ulValueLen = sizeof(keyType); + ckNetscapeAttributesTemplate[2].ulValueLen = sizeof(sensitive); + ckNetscapeAttributesTemplate[3].ulValueLen = 0; + + if (ckpFunctions == NULL) { goto cleanup; } + + // If key is private and of DSA or EC type, NSS may require CKA_NETSCAPE_DB + // attribute to unwrap it. + rv = (*ckpFunctions->C_GetAttributeValue)(ckSessionHandle, ckObjectHandle, + ckNetscapeAttributesTemplate, + sizeof(ckNetscapeAttributesTemplate)/sizeof(CK_ATTRIBUTE)); + + if (rv == CKR_OK && class == CKO_PRIVATE_KEY && + (keyType == CKK_EC || keyType == CKK_DSA) && + sensitive == CK_TRUE && + ckNetscapeAttributesTemplate[3].ulValueLen == CK_UNAVAILABLE_INFORMATION) { + // We cannot set the attribute through C_SetAttributeValue here + // because it might be read-only. However, we can add it to + // the extracted buffer. + netscapeAttributeValueNeeded = CK_TRUE; + TRACE0("DEBUG: override CKA_NETSCAPE_DB attr value to TRUE\n"); + } + + 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 + // NOTE: may return an error code but length values are filled anyways + (*ckpFunctions->C_GetAttributeValue)(ckSessionHandle, ckObjectHandle, + ckpAttributes, CK_ATTRIBUTES_TEMPLATE_LENGTH); + + for (i = 0; i < CK_ATTRIBUTES_TEMPLATE_LENGTH; i++) { + if ((ckpAttributes+i)->ulValueLen != CK_UNAVAILABLE_INFORMATION) { + totalDataSize += (ckpAttributes+i)->ulValueLen; + if ((ckpAttributes+i)->type == CKA_SENSITIVE) { + sensitiveAttributePosition = attributesCount; + TRACE0("DEBUG: GetNativeKeyInfo key is sensitive"); + } + attributesCount++; + } + } + + if (netscapeAttributeValueNeeded) { + 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); + TRACE1("DEBUG: GetNativeKeyInfo attributesCount = %lu\n", attributesCount); + TRACE1("DEBUG: GetNativeKeyInfo sizeof CK_ATTRIBUTE = %lu\n", sizeof(CK_ATTRIBUTE)); + TRACE1("DEBUG: GetNativeKeyInfo totalCkAttributesSize = %lu\n", totalCkAttributesSize); + TRACE1("DEBUG: GetNativeKeyInfo totalDataSize = %lu\n", totalDataSize); + + totalNativeKeyInfoArraySize = + totalCkAttributesSize + sizeof(unsigned long) * 3 + totalDataSize; + + TRACE1("DEBUG: GetNativeKeyInfo totalNativeKeyInfoArraySize = %lu\n", totalNativeKeyInfoArraySize); + + 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); + memcpy(nativeKeyInfoArrayRaw, &totalCkAttributesSize, sizeof(unsigned long)); + + memcpy(nativeKeyInfoArrayRaw + sizeof(unsigned long) + totalCkAttributesSize, + &totalDataSize, sizeof(unsigned long)); + + memset(wrappedKeySizePtr, 0, sizeof(unsigned long)); + + 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 != CK_UNAVAILABLE_INFORMATION) { + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).type = + (ckpAttributes+i)->type; + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).ulValueLen = + (ckpAttributes+i)->ulValueLen; + if ((ckpAttributes+i)->ulValueLen != 0) { + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).pValue = + nativeKeyInfoArrayRawDataPtr; + } else { + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).pValue = 0; + } + nativeKeyInfoArrayRawDataPtr += + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).ulValueLen; + nativeKeyInfoArrayRawCkAttributesPtr += sizeof(CK_ATTRIBUTE); + } + } + + TRACE0("DEBUG: GetNativeKeyInfo finished prepping nativeKeyInfoArray\n"); + + // Get attribute's values + rv = (*ckpFunctions->C_GetAttributeValue)(ckSessionHandle, ckObjectHandle, + (CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributes, + attributesCount); + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + goto cleanup; + } + + TRACE0("DEBUG: GetNativeKeyInfo 1st C_GetAttributeValue call passed\n"); + + if (netscapeAttributeValueNeeded) { + (*(CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributesPtr).type = CKA_NETSCAPE_DB; + // Value is not needed, public key is not used + } + + 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) { + + jMechanismToCKMechanism(env, jWrappingMech, &ckMechanism); + 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); + memcpy(wrappedKeySizeWrappedKeyArrayPtr, &ckWrappedKeyLength, sizeof(unsigned long)); + TRACE1("DEBUG: GetNativeKeyInfo 1st C_WrapKey wrappedKeyLength = %lu\n", 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; + } + memcpy(wrappedKeySizeWrappedKeyArrayPtr, &ckWrappedKeyLength, sizeof(unsigned long)); + TRACE1("DEBUG: GetNativeKeyInfo 2nd C_WrapKey wrappedKeyLength = %lu\n", 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[BJLsun/security/pkcs11/wrapper/CK_MECHANISM;)J + * Parametermapping: *PKCS11* + * @param jlong jSessionHandle CK_SESSION_HANDLE hSession + * @param jbyteArray jNativeKeyInfo - + * @param jlong jWrappingKeyHandle CK_OBJECT_HANDLE hObject + * @param jobject jWrappingMech CK_MECHANISM_PTR pMechanism + * @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, jobject jWrappingMech) +{ + CK_OBJECT_HANDLE ckObjectHandle; + CK_RV rv; + CK_SESSION_HANDLE ckSessionHandle = jLongToCKULong(jSessionHandle); + jbyte* nativeKeyInfoArrayRaw = NULL; + jlong jObjectHandle = 0L; + unsigned long totalCkAttributesSize = 0UL; + unsigned long 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; + 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; + } + + memcpy(&totalCkAttributesSize, nativeKeyInfoArrayRaw, sizeof(unsigned long)); + TRACE1("DEBUG: createNativeKey totalCkAttributesSize = %lu\n", totalCkAttributesSize); + nativeKeyInfoCkAttributesCount = totalCkAttributesSize/sizeof(CK_ATTRIBUTE); + TRACE1("DEBUG: createNativeKey nativeKeyInfoCkAttributesCount = %lu\n", nativeKeyInfoCkAttributesCount); + + nativeKeyInfoArrayRawCkAttributes = nativeKeyInfoArrayRaw + + sizeof(unsigned long); + nativeKeyInfoArrayRawCkAttributesPtr = nativeKeyInfoArrayRawCkAttributes; + nativeKeyInfoArrayRawDataPtr = nativeKeyInfoArrayRaw + + totalCkAttributesSize + sizeof(unsigned long) * 2; + memcpy(&totalDataSize, (nativeKeyInfoArrayRaw + totalCkAttributesSize + sizeof(unsigned long)), + sizeof(unsigned long)); + TRACE1("DEBUG: createNativeKey totalDataSize = %lu\n", totalDataSize); + + wrappedKeySizePtr = (unsigned long*)(nativeKeyInfoArrayRaw + + sizeof(unsigned long)*2 + totalCkAttributesSize + totalDataSize); + + memcpy(&ckWrappedKeyLength, wrappedKeySizePtr, sizeof(unsigned long)); + TRACE1("DEBUG: createNativeKey wrappedKeyLength = %lu\n", ckWrappedKeyLength); + + 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 (ckWrappedKeyLength == 0) { + // Not a wrapped key + rv = (*ckpFunctions->C_CreateObject)(ckSessionHandle, + (CK_ATTRIBUTE_PTR)nativeKeyInfoArrayRawCkAttributes, + jLongToCKULong(nativeKeyInfoCkAttributesCount), &ckObjectHandle); + } else { + // Wrapped key + jMechanismToCKMechanism(env, jWrappingMech, &ckMechanism); + rv = (*ckpFunctions->C_UnwrapKey)(ckSessionHandle, &ckMechanism, + jLongToCKULong(jWrappingKeyHandle), + (CK_BYTE_PTR)(wrappedKeySizePtr + 1), ckWrappedKeyLength, + (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 diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11t.h Thu Nov 29 13:36:23 2018 -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 diff -r bd8df96decba -r 5170dc2bcf64 src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h Fri Jan 11 14:48:19 2019 +0000 +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h Thu Nov 29 13:36:23 2018 -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" @@ -204,6 +206,8 @@ #define ckULongToJSize(x) ((jsize) x) #define unsignedIntToCKULong(x) ((CK_ULONG) x) +//#define P11_DEBUG + #ifdef P11_DEBUG #define TRACE0(s) { printf(s); fflush(stdout); } #define TRACE1(s, p1) { printf(s, p1); fflush(stdout); }