提交 e8994463 编写于 作者: M mbalao

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
上级 28fc5783
......@@ -32,6 +32,8 @@ SUNWprivate_1.1 {
Java_sun_security_pkcs11_wrapper_PKCS11_finalizeLibrary;
Java_sun_security_pkcs11_wrapper_PKCS11_connect;
Java_sun_security_pkcs11_wrapper_PKCS11_disconnect;
Java_sun_security_pkcs11_wrapper_PKCS11_getNativeKeyInfo;
Java_sun_security_pkcs11_wrapper_PKCS11_createNativeKey;
Java_sun_security_pkcs11_wrapper_PKCS11_C_1Initialize;
Java_sun_security_pkcs11_wrapper_PKCS11_C_1Finalize;
Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetInfo;
......
/*
* 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 @@ final class P11Cipher extends CipherSpi {
}
}
private void cancelOperation() {
if (initialized == false) {
return;
}
if ((session == null) || (token.explicitCancel == 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;
}
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 @@ final class P11Cipher extends CipherSpi {
} 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 @@ final class P11Cipher extends CipherSpi {
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 {
......
/*
* 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 @@ final class P11DHKeyFactory extends P11KeyFactory {
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 @@ final class P11DHKeyFactory extends P11KeyFactory {
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(),
......
/*
* 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 @@ final class P11DSAKeyFactory extends P11KeyFactory {
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 @@ final class P11DSAKeyFactory extends P11KeyFactory {
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(),
......
/*
* 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
......@@ -140,7 +140,8 @@ final class P11Digest extends MessageDigestSpi implements Cloneable {
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);
......@@ -250,6 +251,7 @@ final class P11Digest extends MessageDigestSpi implements Cloneable {
}
fetchSession();
long p11KeyID = p11Key.getKeyID();
try {
if (state == S_BUFFERED) {
token.p11.C_DigestInit(session.id(), mechanism);
......@@ -260,10 +262,12 @@ final class P11Digest extends MessageDigestSpi implements Cloneable {
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();
}
}
......
/*
* 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 @@ final class P11ECDHKeyAgreement extends KeyAgreementSpi {
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 @@ final class P11ECDHKeyAgreement extends KeyAgreementSpi {
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 @@ final class P11ECDHKeyAgreement extends KeyAgreementSpi {
} catch (PKCS11Exception e) {
throw new ProviderException("Could not derive key", e);
} finally {
privateKey.releaseKeyID();
publicValue = null;
token.releaseSession(session);
}
......@@ -182,6 +184,7 @@ final class P11ECDHKeyAgreement extends KeyAgreementSpi {
}
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 @@ final class P11ECDHKeyAgreement extends KeyAgreementSpi {
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 @@ final class P11ECDHKeyAgreement extends KeyAgreementSpi {
} catch (PKCS11Exception e) {
throw new InvalidKeyException("Could not derive key", e);
} finally {
privateKey.releaseKeyID();
publicValue = null;
token.releaseSession(session);
}
......
/*
* 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 @@ final class P11ECKeyFactory extends P11KeyFactory {
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 @@ final class P11ECKeyFactory extends P11KeyFactory {
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 "
......
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2019, 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
......@@ -29,7 +29,6 @@ import java.io.*;
import java.lang.ref.*;
import java.math.BigInteger;
import java.util.*;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
......@@ -43,11 +42,15 @@ import sun.security.rsa.RSAPublicKeyImpl;
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.DerValue;
import sun.security.util.Length;
import sun.security.jca.JCAUtil;
/**
* Key implementation classes.
*
......@@ -79,23 +82,38 @@ abstract class P11Key implements Key, Length {
// 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;
......@@ -115,11 +133,21 @@ abstract class P11Key implements Key, Length {
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
......@@ -204,8 +232,7 @@ abstract class P11Key implements Key, Length {
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 {
......@@ -237,12 +264,15 @@ abstract class P11Key implements Key, Length {
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);
}
}
......@@ -289,7 +319,8 @@ abstract class P11Key implements Key, Length {
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,
......@@ -299,8 +330,9 @@ abstract class P11Key implements Key, Length {
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
......@@ -308,17 +340,17 @@ abstract class P11Key implements Key, Length {
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);
......@@ -355,21 +387,21 @@ abstract class P11Key implements Key, Length {
crtKey = false;
}
if (crtKey) {
return new P11RSAPrivateKey
(session, keyID, algorithm, keyLength, attributes);
return new P11RSAPrivateKey(session, keyID, algorithm,
keyLength, attributes);
} 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);
......@@ -423,17 +455,19 @@ abstract class P11Key implements Key, Length {
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;
......@@ -1091,6 +1125,153 @@ abstract class P11Key implements Key, Length {
}
}
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
......@@ -1115,35 +1296,42 @@ final class SessionKeyRef extends PhantomReference<P11Key>
}
}
// 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);
// TBD: run at some interval and not every time?
drainRefQueueBounded();
}
private void dispose() {
refList.remove(this);
if (session.token.isValid()) {
Session newSession = null;
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 {
newSession = session.token.getOpSession();
session.token.p11.C_DestroyObject(newSession.id(), keyID);
s = token.getOpSession();
token.p11.C_DestroyObject(s.id(), keyID);
} catch (PKCS11Exception e) {
// ignore
// best effort
} finally {
this.clear();
session.token.releaseSession(newSession);
session.removeObject();
token.releaseSession(s);
}
}
refList.remove(this);
this.clear();
session.removeObject();
return null;
}
public int compareTo(SessionKeyRef other) {
......
/*
* 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 @@ final class P11KeyAgreement extends KeyAgreementSpi {
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 @@ final class P11KeyAgreement extends KeyAgreementSpi {
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 @@ final class P11KeyAgreement extends KeyAgreementSpi {
} catch (PKCS11Exception e) {
throw new ProviderException("Could not derive key", e);
} finally {
privateKey.releaseKeyID();
publicValue = null;
token.releaseSession(session);
}
......@@ -325,6 +328,7 @@ final class P11KeyAgreement extends KeyAgreementSpi {
}
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 @@ final class P11KeyAgreement extends KeyAgreementSpi {
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 @@ final class P11KeyAgreement extends KeyAgreementSpi {
} catch (PKCS11Exception e) {
throw new InvalidKeyException("Could not derive key", e);
} finally {
privateKey.releaseKeyID();
publicValue = null;
token.releaseSession(session);
}
......
/*
* 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
......@@ -1486,6 +1486,7 @@ final class P11KeyStore extends KeyStoreSpi {
}
}
// 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 {
......@@ -1493,23 +1494,22 @@ final class P11KeyStore extends KeyStoreSpi {
// 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[] {
......@@ -1519,7 +1519,8 @@ final class P11KeyStore extends KeyStoreSpi {
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 [" +
......@@ -1529,6 +1530,7 @@ final class P11KeyStore extends KeyStoreSpi {
}
} finally {
token.releaseSession(session);
key.releaseKeyID();
}
}
......@@ -1895,10 +1897,12 @@ final class P11KeyStore extends KeyStoreSpi {
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) {
......
/*
* 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 @@ import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
*/
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 @@ final class P11Mac extends MacSpi {
// 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 @@ final class P11Mac extends MacSpi {
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 @@ final class P11Mac extends MacSpi {
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 @@ final class P11Mac extends MacSpi {
// 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 @@ final class P11Mac extends MacSpi {
throw new InvalidAlgorithmParameterException
("Parameters not supported");
}
cancelOperation();
reset(true);
p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm);
try {
initialize();
......@@ -215,13 +205,12 @@ final class P11Mac extends MacSpi {
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 @@ final class P11Mac extends MacSpi {
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 @@ final class P11Mac extends MacSpi {
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);
}
......
/*
* 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
......@@ -195,7 +195,7 @@ final class P11RSACipher extends CipherSpi {
}
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) {
......@@ -240,80 +240,105 @@ final class P11RSACipher extends CipherSpi {
}
}
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;
} 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
}
}
}
private void ensureInitialized() throws PKCS11Exception {
token.ensureValid();
if (!initialized) {
initialize();
}
}
private void initialize() throws PKCS11Exception {
if (p11Key == null) {
throw new ProviderException(
"Operation cannot be performed without " +
"calling engineInit first");
}
long keyID = p11Key.getKeyID();
try {
if (session == null) {
session = token.getOpSession();
}
PKCS11 p11 = token.p11;
int inLen = maxInputSize;
int outLen = buffer.length;
CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism);
switch (mode) {
case MODE_ENCRYPT:
p11.C_Encrypt
(session.id(), buffer, 0, inLen, buffer, 0, outLen);
p11.C_EncryptInit(session.id(), ckMechanism, keyID);
break;
case MODE_DECRYPT:
p11.C_Decrypt
(session.id(), buffer, 0, inLen, buffer, 0, outLen);
p11.C_DecryptInit(session.id(), ckMechanism, keyID);
break;
case MODE_SIGN:
byte[] tmpBuffer = new byte[maxInputSize];
p11.C_Sign
(session.id(), tmpBuffer);
p11.C_SignInit(session.id(), ckMechanism, keyID);
break;
case MODE_VERIFY:
p11.C_VerifyRecover
(session.id(), buffer, 0, inLen, buffer, 0, outLen);
p11.C_VerifyRecoverInit(session.id(), ckMechanism, keyID);
break;
default:
throw new ProviderException("internal error");
throw new AssertionError("internal error");
}
bufOfs = 0;
initialized = true;
} catch (PKCS11Exception e) {
// XXX ensure this always works, ignore error
}
}
private void ensureInitialized() throws PKCS11Exception {
token.ensureValid();
if (initialized == false) {
initialize();
}
}
private void initialize() throws PKCS11Exception {
if (session == null) {
session = token.getOpSession();
}
PKCS11 p11 = token.p11;
CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism);
switch (mode) {
case MODE_ENCRYPT:
p11.C_EncryptInit(session.id(), ckMechanism, p11Key.keyID);
break;
case MODE_DECRYPT:
p11.C_DecryptInit(session.id(), ckMechanism, p11Key.keyID);
break;
case MODE_SIGN:
p11.C_SignInit(session.id(), ckMechanism, p11Key.keyID);
break;
case MODE_VERIFY:
p11.C_VerifyRecoverInit(session.id(), ckMechanism, p11Key.keyID);
break;
default:
throw new AssertionError("internal error");
p11Key.releaseKeyID();
session = token.releaseSession(session);
throw e;
}
bufOfs = 0;
initialized = true;
}
private void implUpdate(byte[] in, int inOfs, int inLen) {
......@@ -376,8 +401,7 @@ final class P11RSACipher extends CipherSpi {
throw (BadPaddingException)new BadPaddingException
("doFinal() failed").initCause(e);
} finally {
initialized = false;
session = token.releaseSession(session);
reset(false);
}
}
......@@ -451,13 +475,17 @@ final class P11RSACipher extends CipherSpi {
}
}
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);
}
}
......@@ -516,6 +544,7 @@ final class P11RSACipher extends CipherSpi {
} else {
Session s = null;
SecretKey secretKey = null;
long p11KeyID = p11Key.getKeyID();
try {
try {
s = token.getObjSession();
......@@ -526,9 +555,10 @@ final class P11RSACipher extends CipherSpi {
};
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) {
......@@ -552,6 +582,7 @@ final class P11RSACipher extends CipherSpi {
return secretKey;
} finally {
p11Key.releaseKeyID();
token.releaseSession(s);
}
}
......
......@@ -262,7 +262,12 @@ final class P11RSAKeyFactory extends P11KeyFactory {
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()
......@@ -288,7 +293,13 @@ final class P11RSAKeyFactory extends P11KeyFactory {
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(),
......@@ -306,7 +317,13 @@ final class P11RSAKeyFactory extends P11KeyFactory {
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()
......
/*
* 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 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
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;
}
......
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2019, 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
......@@ -237,27 +237,33 @@ final class P11Signature extends SignatureSpi {
this.md = md;
}
private void ensureInitialized() {
token.ensureValid();
if (initialized == false) {
initialize();
}
}
// reset the states to the pre-initialized values
private void reset(boolean doCancel) {
private void cancelOperation() {
token.ensureValid();
if (initialized == false) {
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);
}
}
private void cancelOperation() {
token.ensureValid();
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) {
......@@ -277,8 +283,8 @@ final class P11Signature extends SignatureSpi {
throw new ProviderException("cancel failed", e);
}
} else { // M_VERIFY
byte[] signature;
try {
byte[] signature;
if (keyAlgorithm.equals("DSA")) {
signature = new byte[40];
} else {
......@@ -296,31 +302,48 @@ final class P11Signature extends SignatureSpi {
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);
}
......@@ -330,6 +353,7 @@ final class P11Signature extends SignatureSpi {
md.reset();
}
}
initialized = true;
}
private void checkKeySize(String keyAlgo, Key key)
......@@ -412,6 +436,7 @@ final class P11Signature extends SignatureSpi {
// see JCA spec
protected void engineInitVerify(PublicKey publicKey)
throws InvalidKeyException {
if (publicKey == null) {
throw new InvalidKeyException("Key must not be null");
}
......@@ -419,7 +444,7 @@ final class P11Signature extends SignatureSpi {
if (publicKey != p11Key) {
checkKeySize(keyAlgorithm, publicKey);
}
cancelOperation();
reset(true);
mode = M_VERIFY;
p11Key = P11KeyFactory.convertKey(token, publicKey, keyAlgorithm);
initialize();
......@@ -428,6 +453,7 @@ final class P11Signature extends SignatureSpi {
// see JCA spec
protected void engineInitSign(PrivateKey privateKey)
throws InvalidKeyException {
if (privateKey == null) {
throw new InvalidKeyException("Key must not be null");
}
......@@ -435,7 +461,7 @@ final class P11Signature extends SignatureSpi {
if (privateKey != p11Key) {
checkKeySize(keyAlgorithm, privateKey);
}
cancelOperation();
reset(true);
mode = M_SIGN;
p11Key = P11KeyFactory.convertKey(token, privateKey, keyAlgorithm);
initialize();
......@@ -468,6 +494,7 @@ final class P11Signature extends SignatureSpi {
// see JCA spec
protected void engineUpdate(byte[] b, int ofs, int len)
throws SignatureException {
ensureInitialized();
if (len == 0) {
return;
......@@ -486,8 +513,7 @@ final class P11Signature extends SignatureSpi {
}
bytesProcessed += len;
} catch (PKCS11Exception e) {
initialized = false;
session = token.releaseSession(session);
reset(false);
throw new ProviderException(e);
}
break;
......@@ -510,6 +536,7 @@ final class P11Signature extends SignatureSpi {
// see JCA spec
protected void engineUpdate(ByteBuffer byteBuffer) {
ensureInitialized();
int len = byteBuffer.remaining();
if (len <= 0) {
......@@ -535,8 +562,7 @@ final class P11Signature extends SignatureSpi {
bytesProcessed += len;
byteBuffer.position(ofs + len);
} catch (PKCS11Exception e) {
initialized = false;
session = token.releaseSession(session);
reset(false);
throw new ProviderException("Update failed", e);
}
break;
......@@ -553,13 +579,16 @@ final class P11Signature extends SignatureSpi {
bytesProcessed += len;
break;
default:
reset(false);
throw new ProviderException("Internal error");
}
}
// see JCA spec
protected byte[] engineSign() throws SignatureException {
ensureInitialized();
boolean doCancel = true;
try {
byte[] signature;
if (type == T_UPDATE) {
......@@ -596,22 +625,25 @@ final class P11Signature extends SignatureSpi {
signature = token.p11.C_Sign(session.id(), data);
}
}
doCancel = false;
if (keyAlgorithm.equals("RSA") == false) {
return dsaToASN1(signature);
} else {
return signature;
}
} catch (PKCS11Exception e) {
doCancel = false;
throw new ProviderException(e);
} finally {
initialized = false;
session = token.releaseSession(session);
reset(doCancel);
}
}
// see JCA spec
protected boolean engineVerify(byte[] signature) throws SignatureException {
ensureInitialized();
boolean doCancel = true;
try {
if (keyAlgorithm.equals("DSA")) {
signature = asn1ToDSA(signature);
......@@ -651,8 +683,10 @@ final class P11Signature extends SignatureSpi {
token.p11.C_Verify(session.id(), data, signature);
}
}
doCancel = false;
return true;
} catch (PKCS11Exception e) {
doCancel = false;
long errorCode = e.getErrorCode();
if (errorCode == CKR_SIGNATURE_INVALID) {
return false;
......@@ -667,10 +701,7 @@ final class P11Signature extends SignatureSpi {
}
throw new ProviderException(e);
} finally {
// XXX we should not release the session if we abort above
// before calling C_Verify
initialized = false;
session = token.releaseSession(session);
reset(doCancel);
}
}
......
......@@ -173,9 +173,13 @@ public final class P11TlsKeyMaterialGenerator extends KeyGeneratorSpi {
}
attributes = token.getAttributes
(O_GENERATE, CKO_SECRET_KEY, keyType, attributes);
// the returned keyID is a dummy, ignore
long keyID = token.p11.C_DeriveKey(session.id(),
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) {
......
......@@ -147,12 +147,13 @@ public final class P11TlsMasterSecretGenerator extends KeyGeneratorSpi {
}
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;
......@@ -161,12 +162,12 @@ public final class P11TlsMasterSecretGenerator extends KeyGeneratorSpi {
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);
}
}
......
......@@ -143,34 +143,36 @@ final class P11TlsPrfGenerator extends KeyGeneratorSpi {
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
......@@ -179,6 +181,7 @@ final class P11TlsPrfGenerator extends KeyGeneratorSpi {
} catch (PKCS11Exception e) {
throw new ProviderException("Could not calculate PRF", e);
} finally {
p11Key.releaseKeyID();
token.releaseSession(session);
}
}
......@@ -189,15 +192,16 @@ final class P11TlsPrfGenerator extends KeyGeneratorSpi {
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);
}
}
......
/*
* Copyright (c) 2003, 2013, 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.
......@@ -1287,6 +1287,46 @@ public class PKCS11 {
* Key management
******************************************************************************/
/**
* 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.
......
......@@ -45,5 +45,7 @@ grant {
permission java.util.PropertyPermission "java.vm.version", "read";
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";
permission java.util.PropertyPermission "sun.security.pkcs11.disableKeyExtraction", "read";
};
......@@ -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
......
......@@ -548,6 +548,7 @@ typedef CK_ULONG CK_ATTRIBUTE_TYPE;
#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
......
......@@ -148,6 +148,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"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册