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
--- 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";
--- 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 {
--- 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(),
--- 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(),
--- 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();
}
}
--- 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);
}
--- 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 "
--- 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<String> 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) {
--- 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);
}
--- 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) {
--- 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);
}
--- 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);
}
}
--- 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()
--- 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;
}
--- 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);
}
}
--- 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) {
--- 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);
}
}
--- 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);
}
}
--- 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)
--- 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
--- 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
--- 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); }