8240256: Better resource cleaning for SunPKCS11 Provider
Reviewed-by: valeriep
This commit is contained in:
parent
06f87cf441
commit
bdeaeb47d0
@ -144,7 +144,15 @@ final class Config {
|
|||||||
// how often to test for token insertion, if no token is present
|
// how often to test for token insertion, if no token is present
|
||||||
private int insertionCheckInterval = 2000;
|
private int insertionCheckInterval = 2000;
|
||||||
|
|
||||||
// flag inidicating whether to omit the call to C_Initialize()
|
// short ms value to indicate how often native cleaner thread is called
|
||||||
|
private int resourceCleanerShortInterval = 2_000;
|
||||||
|
// long ms value to indicate how often native cleaner thread is called
|
||||||
|
private int resourceCleanerLongInterval = 60_000;
|
||||||
|
|
||||||
|
// should Token be destroyed after logout()
|
||||||
|
private boolean destroyTokenAfterLogout;
|
||||||
|
|
||||||
|
// flag indicating whether to omit the call to C_Initialize()
|
||||||
// should be used only if we are running within a process that
|
// should be used only if we are running within a process that
|
||||||
// has already called it (e.g. Plugin inside of Mozilla/NSS)
|
// has already called it (e.g. Plugin inside of Mozilla/NSS)
|
||||||
private boolean omitInitialize = false;
|
private boolean omitInitialize = false;
|
||||||
@ -278,6 +286,18 @@ final class Config {
|
|||||||
return explicitCancel;
|
return explicitCancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean getDestroyTokenAfterLogout() {
|
||||||
|
return destroyTokenAfterLogout;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getResourceCleanerShortInterval() {
|
||||||
|
return resourceCleanerShortInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getResourceCleanerLongInterval() {
|
||||||
|
return resourceCleanerLongInterval;
|
||||||
|
}
|
||||||
|
|
||||||
int getInsertionCheckInterval() {
|
int getInsertionCheckInterval() {
|
||||||
return insertionCheckInterval;
|
return insertionCheckInterval;
|
||||||
}
|
}
|
||||||
@ -412,6 +432,18 @@ final class Config {
|
|||||||
if (insertionCheckInterval < 100) {
|
if (insertionCheckInterval < 100) {
|
||||||
throw excLine(word + " must be at least 100 ms");
|
throw excLine(word + " must be at least 100 ms");
|
||||||
}
|
}
|
||||||
|
} else if (word.equals("cleaner.shortInterval")) {
|
||||||
|
resourceCleanerShortInterval = parseIntegerEntry(word);
|
||||||
|
if (resourceCleanerShortInterval < 1_000) {
|
||||||
|
throw excLine(word + " must be at least 1000 ms");
|
||||||
|
}
|
||||||
|
} else if (word.equals("cleaner.longInterval")) {
|
||||||
|
resourceCleanerLongInterval = parseIntegerEntry(word);
|
||||||
|
if (resourceCleanerLongInterval < 1_000) {
|
||||||
|
throw excLine(word + " must be at least 1000 ms");
|
||||||
|
}
|
||||||
|
} else if (word.equals("destroyTokenAfterLogout")) {
|
||||||
|
destroyTokenAfterLogout = parseBooleanEntry(word);
|
||||||
} else if (word.equals("showInfo")) {
|
} else if (word.equals("showInfo")) {
|
||||||
showInfo = parseBooleanEntry(word);
|
showInfo = parseBooleanEntry(word);
|
||||||
} else if (word.equals("keyStoreCompatibilityMode")) {
|
} else if (word.equals("keyStoreCompatibilityMode")) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -100,4 +100,8 @@ final class KeyCache {
|
|||||||
map.put(key, p11Key);
|
map.put(key, p11Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronized void clear() {
|
||||||
|
strongCache.clear();
|
||||||
|
cacheReference = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ import sun.security.pkcs11.wrapper.*;
|
|||||||
import static sun.security.pkcs11.TemplateManager.O_GENERATE;
|
import static sun.security.pkcs11.TemplateManager.O_GENERATE;
|
||||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||||
|
|
||||||
import sun.security.util.Debug;
|
|
||||||
import sun.security.util.DerValue;
|
import sun.security.util.DerValue;
|
||||||
import sun.security.util.Length;
|
import sun.security.util.Length;
|
||||||
import sun.security.util.ECUtil;
|
import sun.security.util.ECUtil;
|
||||||
@ -142,8 +141,8 @@ abstract class P11Key implements Key, Length {
|
|||||||
&& tokenLabel[2] == 'S');
|
&& tokenLabel[2] == 'S');
|
||||||
boolean extractKeyInfo = (!DISABLE_NATIVE_KEYS_EXTRACTION && isNSS &&
|
boolean extractKeyInfo = (!DISABLE_NATIVE_KEYS_EXTRACTION && isNSS &&
|
||||||
extractable && !tokenObject);
|
extractable && !tokenObject);
|
||||||
this.keyIDHolder = new NativeKeyHolder(this, keyID, session, extractKeyInfo,
|
this.keyIDHolder = new NativeKeyHolder(this, keyID, session,
|
||||||
tokenObject);
|
extractKeyInfo, tokenObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getKeyID() {
|
public long getKeyID() {
|
||||||
@ -166,6 +165,18 @@ abstract class P11Key implements Key, Length {
|
|||||||
return (b == null) ? null : b.clone();
|
return (b == null) ? null : b.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called by the NativeResourceCleaner at specified intervals
|
||||||
|
// See NativeResourceCleaner for more information
|
||||||
|
static boolean drainRefQueue() {
|
||||||
|
boolean found = false;
|
||||||
|
SessionKeyRef next;
|
||||||
|
while ((next = (SessionKeyRef) SessionKeyRef.refQueue.poll()) != null) {
|
||||||
|
found = true;
|
||||||
|
next.dispose();
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
abstract byte[] getEncodedInternal();
|
abstract byte[] getEncodedInternal();
|
||||||
|
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
@ -882,7 +893,7 @@ abstract class P11Key implements Key, Length {
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
if (token.isValid() == false) {
|
if (!token.isValid()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
fetchValues();
|
fetchValues();
|
||||||
@ -891,7 +902,7 @@ abstract class P11Key implements Key, Length {
|
|||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) return true;
|
if (this == obj) return true;
|
||||||
// equals() should never throw exceptions
|
// equals() should never throw exceptions
|
||||||
if (token.isValid() == false) {
|
if (!token.isValid()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(obj instanceof DHPrivateKey)) {
|
if (!(obj instanceof DHPrivateKey)) {
|
||||||
@ -1129,7 +1140,6 @@ abstract class P11Key implements Key, Length {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class NativeKeyHolder {
|
final class NativeKeyHolder {
|
||||||
|
|
||||||
private static long nativeKeyWrapperKeyID = 0;
|
private static long nativeKeyWrapperKeyID = 0;
|
||||||
@ -1254,6 +1264,7 @@ final class NativeKeyHolder {
|
|||||||
this.ref = new SessionKeyRef(p11Key, keyID, wrapperKeyUsed,
|
this.ref = new SessionKeyRef(p11Key, keyID, wrapperKeyUsed,
|
||||||
keySession);
|
keySession);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nativeKeyInfo = ((ki == null || ki.length == 0)? null : ki);
|
this.nativeKeyInfo = ((ki == null || ki.length == 0)? null : ki);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1327,24 +1338,9 @@ final class NativeKeyHolder {
|
|||||||
* still use these keys during finalization such as SSLSocket.
|
* still use these keys during finalization such as SSLSocket.
|
||||||
*/
|
*/
|
||||||
final class SessionKeyRef extends PhantomReference<P11Key> {
|
final class SessionKeyRef extends PhantomReference<P11Key> {
|
||||||
private static ReferenceQueue<P11Key> refQueue =
|
static ReferenceQueue<P11Key> refQueue = new ReferenceQueue<>();
|
||||||
new ReferenceQueue<P11Key>();
|
|
||||||
private static Set<SessionKeyRef> refSet =
|
private static Set<SessionKeyRef> refSet =
|
||||||
Collections.synchronizedSet(new HashSet<SessionKeyRef>());
|
Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
static ReferenceQueue<P11Key> referenceQueue() {
|
|
||||||
return refQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void drainRefQueueBounded() {
|
|
||||||
while (true) {
|
|
||||||
SessionKeyRef next = (SessionKeyRef) refQueue.poll();
|
|
||||||
if (next == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
next.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle to the native key and the session it is generated under
|
// handle to the native key and the session it is generated under
|
||||||
private long keyID;
|
private long keyID;
|
||||||
@ -1355,13 +1351,13 @@ final class SessionKeyRef extends PhantomReference<P11Key> {
|
|||||||
Session session) {
|
Session session) {
|
||||||
super(p11Key, refQueue);
|
super(p11Key, refQueue);
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
throw new ProviderException("key must be associated with a session");
|
throw new ProviderException
|
||||||
|
("key must be associated with a session");
|
||||||
}
|
}
|
||||||
registerNativeKey(keyID, session);
|
registerNativeKey(keyID, session);
|
||||||
this.wrapperKeyUsed = wrapperKeyUsed;
|
this.wrapperKeyUsed = wrapperKeyUsed;
|
||||||
|
|
||||||
refSet.add(this);
|
refSet.add(this);
|
||||||
drainRefQueueBounded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerNativeKey(long newKeyID, Session newSession) {
|
void registerNativeKey(long newKeyID, Session newSession) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -82,10 +82,6 @@ final class Session implements Comparable<Session> {
|
|||||||
return currentTime - lastAccess < MAX_IDLE_TIME;
|
return currentTime - lastAccess < MAX_IDLE_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
long idInternal() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
long id() {
|
long id() {
|
||||||
if (token.isPresent(this.id) == false) {
|
if (token.isPresent(this.id) == false) {
|
||||||
throw new ProviderException("Token has been removed");
|
throw new ProviderException("Token has been removed");
|
||||||
@ -112,15 +108,40 @@ final class Session implements Comparable<Session> {
|
|||||||
return createdObjects.get() != 0;
|
return createdObjects.get() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// regular close which will not close sessions when there are objects(keys)
|
||||||
|
// still associated with them
|
||||||
void close() {
|
void close() {
|
||||||
if (hasObjects()) {
|
close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// forced close which will close sessions regardless if there are objects
|
||||||
|
// associated with them. Note that closing the sessions this way may
|
||||||
|
// lead to those associated objects(keys) un-usable. Thus should only be
|
||||||
|
// used for scenarios such as the token is about to be removed, etc.
|
||||||
|
void kill() {
|
||||||
|
close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close(boolean checkObjCtr) {
|
||||||
|
if (hasObjects() && checkObjCtr) {
|
||||||
throw new ProviderException(
|
throw new ProviderException(
|
||||||
"Internal error: close session with active objects");
|
"Internal error: close session with active objects");
|
||||||
}
|
}
|
||||||
sessionRef.dispose();
|
sessionRef.dispose();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// Called by the NativeResourceCleaner at specified intervals
|
||||||
|
// See NativeResourceCleaner for more information
|
||||||
|
static boolean drainRefQueue() {
|
||||||
|
boolean found = false;
|
||||||
|
SessionRef next;
|
||||||
|
while ((next = (SessionRef) SessionRef.refQueue.poll())!= null) {
|
||||||
|
found = true;
|
||||||
|
next.dispose();
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* NOTE: Use PhantomReference here and not WeakReference
|
* NOTE: Use PhantomReference here and not WeakReference
|
||||||
* otherwise the sessions maybe closed before other objects
|
* otherwise the sessions maybe closed before other objects
|
||||||
@ -129,27 +150,10 @@ final class Session implements Comparable<Session> {
|
|||||||
final class SessionRef extends PhantomReference<Session>
|
final class SessionRef extends PhantomReference<Session>
|
||||||
implements Comparable<SessionRef> {
|
implements Comparable<SessionRef> {
|
||||||
|
|
||||||
private static ReferenceQueue<Session> refQueue =
|
static ReferenceQueue<Session> refQueue = new ReferenceQueue<>();
|
||||||
new ReferenceQueue<Session>();
|
|
||||||
|
|
||||||
private static Set<SessionRef> refList =
|
private static Set<SessionRef> refList =
|
||||||
Collections.synchronizedSortedSet(new TreeSet<SessionRef>());
|
Collections.synchronizedSortedSet(new TreeSet<>());
|
||||||
|
|
||||||
static ReferenceQueue<Session> referenceQueue() {
|
|
||||||
return refQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int totalCount() {
|
|
||||||
return refList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void drainRefQueueBounded() {
|
|
||||||
while (true) {
|
|
||||||
SessionRef next = (SessionRef) refQueue.poll();
|
|
||||||
if (next == null) break;
|
|
||||||
next.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle to the native session
|
// handle to the native session
|
||||||
private long id;
|
private long id;
|
||||||
@ -160,8 +164,6 @@ final class SessionRef extends PhantomReference<Session>
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
refList.add(this);
|
refList.add(this);
|
||||||
// TBD: run at some interval and not every time?
|
|
||||||
drainRefQueueBounded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
@ -170,9 +172,7 @@ final class SessionRef extends PhantomReference<Session>
|
|||||||
if (token.isPresent(id)) {
|
if (token.isPresent(id)) {
|
||||||
token.p11.C_CloseSession(id);
|
token.p11.C_CloseSession(id);
|
||||||
}
|
}
|
||||||
} catch (PKCS11Exception e1) {
|
} catch (PKCS11Exception | ProviderException e1) {
|
||||||
// ignore
|
|
||||||
} catch (ProviderException e2) {
|
|
||||||
// ignore
|
// ignore
|
||||||
} finally {
|
} finally {
|
||||||
this.clear();
|
this.clear();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -26,11 +26,9 @@
|
|||||||
package sun.security.pkcs11;
|
package sun.security.pkcs11;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import java.security.ProviderException;
|
import java.security.ProviderException;
|
||||||
|
|
||||||
import sun.security.util.Debug;
|
import sun.security.util.Debug;
|
||||||
|
|
||||||
import sun.security.pkcs11.wrapper.*;
|
import sun.security.pkcs11.wrapper.*;
|
||||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||||
|
|
||||||
@ -171,7 +169,9 @@ final class SessionManager {
|
|||||||
System.out.println("Killing session (" + location + ") active: "
|
System.out.println("Killing session (" + location + ") active: "
|
||||||
+ activeSessions.get());
|
+ activeSessions.get());
|
||||||
}
|
}
|
||||||
closeSession(session);
|
|
||||||
|
session.kill();
|
||||||
|
activeSessions.decrementAndGet();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +179,6 @@ final class SessionManager {
|
|||||||
if ((session == null) || (token.isValid() == false)) {
|
if ((session == null) || (token.isValid() == false)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session.hasObjects()) {
|
if (session.hasObjects()) {
|
||||||
objSessions.release(session);
|
objSessions.release(session);
|
||||||
} else {
|
} else {
|
||||||
@ -188,6 +187,11 @@ final class SessionManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearPools() {
|
||||||
|
objSessions.closeAll();
|
||||||
|
opSessions.closeAll();
|
||||||
|
}
|
||||||
|
|
||||||
void demoteObjSession(Session session) {
|
void demoteObjSession(Session session) {
|
||||||
if (token.isValid() == false) {
|
if (token.isValid() == false) {
|
||||||
return;
|
return;
|
||||||
@ -196,6 +200,7 @@ final class SessionManager {
|
|||||||
System.out.println("Demoting session, active: " +
|
System.out.println("Demoting session, active: " +
|
||||||
activeSessions.get());
|
activeSessions.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean present = objSessions.remove(session);
|
boolean present = objSessions.remove(session);
|
||||||
if (present == false) {
|
if (present == false) {
|
||||||
// session is currently in use
|
// session is currently in use
|
||||||
@ -238,6 +243,7 @@ final class SessionManager {
|
|||||||
private final SessionManager mgr;
|
private final SessionManager mgr;
|
||||||
private final AbstractQueue<Session> pool;
|
private final AbstractQueue<Session> pool;
|
||||||
private final int SESSION_MAX = 5;
|
private final int SESSION_MAX = 5;
|
||||||
|
private volatile boolean closed = false;
|
||||||
|
|
||||||
// Object session pools can contain unlimited sessions.
|
// Object session pools can contain unlimited sessions.
|
||||||
// Operation session pools are limited and enforced by the queue.
|
// Operation session pools are limited and enforced by the queue.
|
||||||
@ -260,7 +266,7 @@ final class SessionManager {
|
|||||||
|
|
||||||
void release(Session session) {
|
void release(Session session) {
|
||||||
// Object session pools never return false, only Operation ones
|
// Object session pools never return false, only Operation ones
|
||||||
if (!pool.offer(session)) {
|
if (closed || !pool.offer(session)) {
|
||||||
mgr.closeSession(session);
|
mgr.closeSession(session);
|
||||||
free();
|
free();
|
||||||
}
|
}
|
||||||
@ -268,6 +274,9 @@ final class SessionManager {
|
|||||||
|
|
||||||
// Free any old operation session if this queue is full
|
// Free any old operation session if this queue is full
|
||||||
void free() {
|
void free() {
|
||||||
|
// quick return path
|
||||||
|
if (pool.size() == 0) return;
|
||||||
|
|
||||||
int n = SESSION_MAX;
|
int n = SESSION_MAX;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
Session oldestSession;
|
Session oldestSession;
|
||||||
@ -291,6 +300,14 @@ final class SessionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// empty out all sessions inside 'pool' and close them.
|
||||||
|
// however the Pool can still accept sessions
|
||||||
|
void closeAll() {
|
||||||
|
closed = true;
|
||||||
|
Session s;
|
||||||
|
while ((s = pool.poll()) != null) {
|
||||||
|
mgr.killSession(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,7 @@ import javax.security.auth.login.LoginException;
|
|||||||
import javax.security.auth.login.FailedLoginException;
|
import javax.security.auth.login.FailedLoginException;
|
||||||
import javax.security.auth.callback.Callback;
|
import javax.security.auth.callback.Callback;
|
||||||
import javax.security.auth.callback.CallbackHandler;
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
import javax.security.auth.callback.ConfirmationCallback;
|
|
||||||
import javax.security.auth.callback.PasswordCallback;
|
import javax.security.auth.callback.PasswordCallback;
|
||||||
import javax.security.auth.callback.TextOutputCallback;
|
|
||||||
|
|
||||||
import com.sun.crypto.provider.ChaCha20Poly1305Parameters;
|
import com.sun.crypto.provider.ChaCha20Poly1305Parameters;
|
||||||
|
|
||||||
@ -88,6 +86,8 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
|
|
||||||
private TokenPoller poller;
|
private TokenPoller poller;
|
||||||
|
|
||||||
|
static NativeResourceCleaner cleaner;
|
||||||
|
|
||||||
Token getToken() {
|
Token getToken() {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@ -907,13 +907,19 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
// background thread that periodically checks for token insertion
|
// background thread that periodically checks for token insertion
|
||||||
// if no token is present. We need to do that in a separate thread because
|
// if no token is present. We need to do that in a separate thread because
|
||||||
// the insertion check may block for quite a long time on some tokens.
|
// the insertion check may block for quite a long time on some tokens.
|
||||||
private static class TokenPoller implements Runnable {
|
private static class TokenPoller extends Thread {
|
||||||
private final SunPKCS11 provider;
|
private final SunPKCS11 provider;
|
||||||
private volatile boolean enabled;
|
private volatile boolean enabled;
|
||||||
|
|
||||||
private TokenPoller(SunPKCS11 provider) {
|
private TokenPoller(SunPKCS11 provider) {
|
||||||
|
super((ThreadGroup)null, "Poller-" + provider.getName());
|
||||||
|
setContextClassLoader(null);
|
||||||
|
setDaemon(true);
|
||||||
|
setPriority(Thread.MIN_PRIORITY);
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
enabled = true;
|
enabled = true;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
int interval = provider.config.getInsertionCheckInterval();
|
int interval = provider.config.getInsertionCheckInterval();
|
||||||
while (enabled) {
|
while (enabled) {
|
||||||
@ -942,13 +948,8 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
if (poller != null) {
|
if (poller != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final TokenPoller poller = new TokenPoller(this);
|
poller = new TokenPoller(this);
|
||||||
Thread t = new Thread(null, poller, "Poller " + getName(), 0, false);
|
poller.start();
|
||||||
t.setContextClassLoader(null);
|
|
||||||
t.setDaemon(true);
|
|
||||||
t.setPriority(Thread.MIN_PRIORITY);
|
|
||||||
t.start();
|
|
||||||
this.poller = poller;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// destroy the poller thread, if active
|
// destroy the poller thread, if active
|
||||||
@ -971,6 +972,56 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
return (token != null) && token.isValid();
|
return (token != null) && token.isValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class NativeResourceCleaner extends Thread {
|
||||||
|
private long sleepMillis = config.getResourceCleanerShortInterval();
|
||||||
|
private int count = 0;
|
||||||
|
boolean keyRefFound, sessRefFound;
|
||||||
|
|
||||||
|
private NativeResourceCleaner() {
|
||||||
|
super((ThreadGroup)null, "Cleanup-SunPKCS11");
|
||||||
|
setContextClassLoader(null);
|
||||||
|
setDaemon(true);
|
||||||
|
setPriority(Thread.MIN_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The cleaner.shortInterval and cleaner.longInterval properties
|
||||||
|
* may be defined in the pkcs11 config file and are specified in milliseconds
|
||||||
|
* Minimum value is 1000ms. Default values :
|
||||||
|
* cleaner.shortInterval : 2000ms
|
||||||
|
* cleaner.longInterval : 60000ms
|
||||||
|
*
|
||||||
|
* The cleaner thread runs at cleaner.shortInterval intervals
|
||||||
|
* while P11Key or Session references continue to be found for cleaning.
|
||||||
|
* If 100 iterations occur with no references being found, then the interval
|
||||||
|
* period moves to cleaner.longInterval value. The cleaner thread moves back
|
||||||
|
* to short interval checking if a resource is found
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
sleep(sleepMillis);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
keyRefFound = P11Key.drainRefQueue();
|
||||||
|
sessRefFound = Session.drainRefQueue();
|
||||||
|
if (!keyRefFound && !sessRefFound) {
|
||||||
|
count++;
|
||||||
|
if (count > 100) {
|
||||||
|
// no reference freed for some time
|
||||||
|
// increase the sleep time
|
||||||
|
sleepMillis = config.getResourceCleanerLongInterval();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
count = 0;
|
||||||
|
sleepMillis = config.getResourceCleanerShortInterval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// destroy the token. Called if we detect that it has been removed
|
// destroy the token. Called if we detect that it has been removed
|
||||||
@SuppressWarnings("removal")
|
@SuppressWarnings("removal")
|
||||||
synchronized void uninitToken(Token token) {
|
synchronized void uninitToken(Token token) {
|
||||||
@ -987,7 +1038,10 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
createPoller();
|
// keep polling for token insertion unless configured not to
|
||||||
|
if (removable && !config.getDestroyTokenAfterLogout()) {
|
||||||
|
createPoller();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isLegacy(CK_MECHANISM_INFO mechInfo)
|
private static boolean isLegacy(CK_MECHANISM_INFO mechInfo)
|
||||||
@ -1135,6 +1189,10 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.token = token;
|
this.token = token;
|
||||||
|
if (cleaner == null) {
|
||||||
|
cleaner = new NativeResourceCleaner();
|
||||||
|
cleaner.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class P11Service extends Service {
|
private static final class P11Service extends Service {
|
||||||
@ -1350,12 +1408,12 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
("authProvider." + this.getName()));
|
("authProvider." + this.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasValidToken() == false) {
|
if (!hasValidToken()) {
|
||||||
throw new LoginException("No token present");
|
throw new LoginException("No token present");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if a login is required
|
// see if a login is required
|
||||||
|
|
||||||
if ((token.tokenInfo.flags & CKF_LOGIN_REQUIRED) == 0) {
|
if ((token.tokenInfo.flags & CKF_LOGIN_REQUIRED) == 0) {
|
||||||
if (debug != null) {
|
if (debug != null) {
|
||||||
debug.println("login operation not required for token - " +
|
debug.println("login operation not required for token - " +
|
||||||
@ -1467,7 +1525,6 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
* this provider's <code>getName</code> method
|
* this provider's <code>getName</code> method
|
||||||
*/
|
*/
|
||||||
public void logout() throws LoginException {
|
public void logout() throws LoginException {
|
||||||
|
|
||||||
if (!isConfigured()) {
|
if (!isConfigured()) {
|
||||||
throw new IllegalStateException("Configuration is required");
|
throw new IllegalStateException("Configuration is required");
|
||||||
}
|
}
|
||||||
@ -1494,10 +1551,13 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (token.isLoggedInNow(null) == false) {
|
if (!token.isLoggedInNow(null)) {
|
||||||
if (debug != null) {
|
if (debug != null) {
|
||||||
debug.println("user not logged in");
|
debug.println("user not logged in");
|
||||||
}
|
}
|
||||||
|
if (config.getDestroyTokenAfterLogout()) {
|
||||||
|
token.destroy();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (PKCS11Exception e) {
|
} catch (PKCS11Exception e) {
|
||||||
@ -1505,7 +1565,6 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// perform token logout
|
// perform token logout
|
||||||
|
|
||||||
Session session = null;
|
Session session = null;
|
||||||
try {
|
try {
|
||||||
session = token.getOpSession();
|
session = token.getOpSession();
|
||||||
@ -1526,6 +1585,9 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
throw le;
|
throw le;
|
||||||
} finally {
|
} finally {
|
||||||
token.releaseSession(session);
|
token.releaseSession(session);
|
||||||
|
if (config.getDestroyTokenAfterLogout()) {
|
||||||
|
token.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,8 +292,12 @@ class Token implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void destroy() {
|
void destroy() {
|
||||||
valid = false;
|
secretCache.clear();
|
||||||
|
privateCache.clear();
|
||||||
|
|
||||||
|
sessionManager.clearPools();
|
||||||
provider.uninitToken(this);
|
provider.uninitToken(this);
|
||||||
|
valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Session getObjSession() throws PKCS11Exception {
|
Session getObjSession() throws PKCS11Exception {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -21,15 +21,12 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// common infrastructure for SunPKCS11 tests
|
// common infrastructure for SunPKCS11 tests
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -110,11 +107,9 @@ public abstract class PKCS11Test {
|
|||||||
// for quick checking for generic testing than many if-else statements.
|
// for quick checking for generic testing than many if-else statements.
|
||||||
static double softoken3_version = -1;
|
static double softoken3_version = -1;
|
||||||
static double nss3_version = -1;
|
static double nss3_version = -1;
|
||||||
static Provider pkcs11;
|
static Provider pkcs11 = newPKCS11Provider();
|
||||||
|
|
||||||
// Goes through ServiceLoader instead of Provider.getInstance() since it
|
public static Provider newPKCS11Provider() {
|
||||||
// works on all platforms
|
|
||||||
static {
|
|
||||||
ServiceLoader sl = ServiceLoader.load(java.security.Provider.class);
|
ServiceLoader sl = ServiceLoader.load(java.security.Provider.class);
|
||||||
Iterator<Provider> iter = sl.iterator();
|
Iterator<Provider> iter = sl.iterator();
|
||||||
Provider p = null;
|
Provider p = null;
|
||||||
@ -139,15 +134,20 @@ public abstract class PKCS11Test {
|
|||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pkcs11 = p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a SunPKCS11 provider configured with the specified config file
|
// Return the static test SunPKCS11 provider configured with the specified config file
|
||||||
static Provider getSunPKCS11(String config) throws Exception {
|
static Provider getSunPKCS11(String config) throws Exception {
|
||||||
if (pkcs11 == null) {
|
return getSunPKCS11(config, pkcs11);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the Provider p configured with the specified config file
|
||||||
|
static Provider getSunPKCS11(String config, Provider p) throws Exception {
|
||||||
|
if (p == null) {
|
||||||
throw new NoSuchProviderException("No PKCS11 provider available");
|
throw new NoSuchProviderException("No PKCS11 provider available");
|
||||||
}
|
}
|
||||||
return pkcs11.configure(config);
|
return p.configure(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void main(Provider p) throws Exception;
|
public abstract void main(Provider p) throws Exception;
|
||||||
@ -539,36 +539,45 @@ public abstract class PKCS11Test {
|
|||||||
nss_library = "nss3";
|
nss_library = "nss3";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run NSS testing on a Provider p configured with test nss config
|
||||||
public static void testNSS(PKCS11Test test) throws Exception {
|
public static void testNSS(PKCS11Test test) throws Exception {
|
||||||
|
String nssConfig = getNssConfig();
|
||||||
|
if (nssConfig == null) {
|
||||||
|
// issue loading libraries
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Provider p = getSunPKCS11(nssConfig);
|
||||||
|
test.premain(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getNssConfig() throws Exception {
|
||||||
String libdir = getNSSLibDir();
|
String libdir = getNSSLibDir();
|
||||||
if (libdir == null) {
|
if (libdir == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
String base = getBase();
|
|
||||||
|
|
||||||
if (loadNSPR(libdir) == false) {
|
if (loadNSPR(libdir) == false) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String base = getBase();
|
||||||
|
|
||||||
String libfile = libdir + System.mapLibraryName(nss_library);
|
String libfile = libdir + System.mapLibraryName(nss_library);
|
||||||
|
|
||||||
String customDBdir = System.getProperty("CUSTOM_DB_DIR");
|
String customDBdir = System.getProperty("CUSTOM_DB_DIR");
|
||||||
String dbdir = (customDBdir != null) ?
|
String dbdir = (customDBdir != null) ?
|
||||||
customDBdir :
|
customDBdir :
|
||||||
base + SEP + "nss" + SEP + "db";
|
base + SEP + "nss" + SEP + "db";
|
||||||
// NSS always wants forward slashes for the config path
|
// NSS always wants forward slashes for the config path
|
||||||
dbdir = dbdir.replace('\\', '/');
|
dbdir = dbdir.replace('\\', '/');
|
||||||
|
|
||||||
String customConfig = System.getProperty("CUSTOM_P11_CONFIG");
|
String customConfig = System.getProperty("CUSTOM_P11_CONFIG");
|
||||||
String customConfigName = System.getProperty("CUSTOM_P11_CONFIG_NAME", "p11-nss.txt");
|
String customConfigName = System.getProperty("CUSTOM_P11_CONFIG_NAME", "p11-nss.txt");
|
||||||
String p11config = (customConfig != null) ?
|
|
||||||
customConfig :
|
|
||||||
base + SEP + "nss" + SEP + customConfigName;
|
|
||||||
|
|
||||||
System.setProperty("pkcs11test.nss.lib", libfile);
|
System.setProperty("pkcs11test.nss.lib", libfile);
|
||||||
System.setProperty("pkcs11test.nss.db", dbdir);
|
System.setProperty("pkcs11test.nss.db", dbdir);
|
||||||
Provider p = getSunPKCS11(p11config);
|
return (customConfig != null) ?
|
||||||
test.premain(p);
|
customConfig :
|
||||||
|
base + SEP + "nss" + SEP + customConfigName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a vector of supported elliptic curves of a given provider
|
// Generate a vector of supported elliptic curves of a given provider
|
||||||
|
12
test/jdk/sun/security/pkcs11/Provider/MultipleLogins-nss.txt
Normal file
12
test/jdk/sun/security/pkcs11/Provider/MultipleLogins-nss.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
name = NSS
|
||||||
|
|
||||||
|
slot = 2
|
||||||
|
|
||||||
|
library = ${pkcs11test.nss.lib}
|
||||||
|
|
||||||
|
nssArgs = "configdir='${pkcs11test.nss.db}' certPrefix='' keyPrefix='' secmod='secmod.db' flags=readOnly"
|
||||||
|
|
||||||
|
destroyTokenAfterLogout = true
|
||||||
|
cleaner.longInterval = 10000
|
||||||
|
cleaner.shortInterval = 1000
|
||||||
|
|
128
test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java
Normal file
128
test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2003, 2021, 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import sun.security.pkcs11.SunPKCS11;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
import javax.security.auth.callback.Callback;
|
||||||
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
|
import javax.security.auth.callback.PasswordCallback;
|
||||||
|
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||||
|
import javax.security.auth.login.LoginException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.ServiceConfigurationError;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
import jdk.test.lib.util.ForceGC;
|
||||||
|
|
||||||
|
public class MultipleLogins {
|
||||||
|
private static final String KS_TYPE = "PKCS11";
|
||||||
|
private static final int NUM_PROVIDERS = 20;
|
||||||
|
private static final SunPKCS11[] providers = new SunPKCS11[NUM_PROVIDERS];
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
for (int i =0; i < NUM_PROVIDERS; i++) {
|
||||||
|
String nssConfig = PKCS11Test.getNssConfig();
|
||||||
|
if (nssConfig == null) {
|
||||||
|
throw new RuntimeException("issue setting up config");
|
||||||
|
}
|
||||||
|
providers[i] =
|
||||||
|
(SunPKCS11)PKCS11Test.newPKCS11Provider()
|
||||||
|
.configure(nssConfig);
|
||||||
|
Security.addProvider(providers[i]);
|
||||||
|
test(providers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
WeakReference<SunPKCS11>[] weakRef = new WeakReference[NUM_PROVIDERS];
|
||||||
|
for (int i =0; i < NUM_PROVIDERS; i++) {
|
||||||
|
weakRef[i] = new WeakReference<>(providers[i]);
|
||||||
|
providers[i].logout();
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
// one provider stays for use with clean up thread
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
providers[i].login(new Subject(), new PasswordCallbackHandler());
|
||||||
|
throw new RuntimeException("Expected LoginException");
|
||||||
|
} catch (LoginException le) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
Security.removeProvider(providers[i].getName());
|
||||||
|
providers[i] = null;
|
||||||
|
|
||||||
|
ForceGC gc = new ForceGC();
|
||||||
|
int finalI = i;
|
||||||
|
gc.await(() -> weakRef[finalI].get() == null);
|
||||||
|
if (!weakRef[i].refersTo(null)) {
|
||||||
|
throw new RuntimeException("Expected SunPKCS11 Provider to be GC'ed..");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test(SunPKCS11 p) throws Exception {
|
||||||
|
KeyStore ks = KeyStore.getInstance(KS_TYPE, p);
|
||||||
|
|
||||||
|
p.setCallbackHandler(new PasswordCallbackHandler());
|
||||||
|
try {
|
||||||
|
ks.load(null, (char[]) null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (!e.getMessage().contains("load failed")) {
|
||||||
|
// we expect the keystore load to fail
|
||||||
|
throw new RuntimeException("unexpected exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.logout();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ks.load(null, (char[]) null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (e.getCause() instanceof LoginException &&
|
||||||
|
e.getCause().getMessage().contains("No token present")) {
|
||||||
|
// expected
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Token was present", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PasswordCallbackHandler implements CallbackHandler {
|
||||||
|
public void handle(Callback[] callbacks)
|
||||||
|
throws IOException, UnsupportedCallbackException {
|
||||||
|
if (!(callbacks[0] instanceof PasswordCallback)) {
|
||||||
|
throw new UnsupportedCallbackException(callbacks[0]);
|
||||||
|
}
|
||||||
|
PasswordCallback pc = (PasswordCallback)callbacks[0];
|
||||||
|
pc.setPassword(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
135
test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh
Normal file
135
test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021, 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
|
||||||
|
# under the terms of the GNU General Public License version 2 only, as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
# version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
# accompanied this code).
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License version
|
||||||
|
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
# or visit www.oracle.com if you need additional information or have any
|
||||||
|
# questions.
|
||||||
|
#
|
||||||
|
|
||||||
|
# @test
|
||||||
|
# @bug 7777777
|
||||||
|
# @summary
|
||||||
|
# @library /test/lib/
|
||||||
|
# @build jdk.test.lib.util.ForceGC
|
||||||
|
# @run shell MultipleLogins.sh
|
||||||
|
|
||||||
|
# set a few environment variables so that the shell-script can run stand-alone
|
||||||
|
# in the source directory
|
||||||
|
|
||||||
|
# if running by hand on windows, change TESTSRC and TESTCLASSES to "."
|
||||||
|
if [ "${TESTSRC}" = "" ] ; then
|
||||||
|
TESTSRC=`pwd`
|
||||||
|
fi
|
||||||
|
if [ "${TESTCLASSES}" = "" ] ; then
|
||||||
|
TESTCLASSES=`pwd`
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${TESTCLASSPATH}" = "" ] ; then
|
||||||
|
TESTCLASSPATH=`pwd`
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${COMPILEJAVA}" = "" ]; then
|
||||||
|
COMPILEJAVA="${TESTJAVA}"
|
||||||
|
fi
|
||||||
|
echo TESTSRC=${TESTSRC}
|
||||||
|
echo TESTCLASSES=${TESTCLASSES}
|
||||||
|
echo TESTJAVA=${TESTJAVA}
|
||||||
|
echo COMPILEJAVA=${COMPILEJAVA}
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# let java test exit if platform unsupported
|
||||||
|
|
||||||
|
OS=`uname -s`
|
||||||
|
case "$OS" in
|
||||||
|
Linux )
|
||||||
|
FS="/"
|
||||||
|
PS=":"
|
||||||
|
CP="${FS}bin${FS}cp"
|
||||||
|
CHMOD="${FS}bin${FS}chmod"
|
||||||
|
;;
|
||||||
|
Darwin )
|
||||||
|
FS="/"
|
||||||
|
PS=":"
|
||||||
|
CP="${FS}bin${FS}cp"
|
||||||
|
CHMOD="${FS}bin${FS}chmod"
|
||||||
|
;;
|
||||||
|
AIX )
|
||||||
|
FS="/"
|
||||||
|
PS=":"
|
||||||
|
CP="${FS}bin${FS}cp"
|
||||||
|
CHMOD="${FS}bin${FS}chmod"
|
||||||
|
;;
|
||||||
|
Windows* )
|
||||||
|
FS="\\"
|
||||||
|
PS=";"
|
||||||
|
CP="cp"
|
||||||
|
CHMOD="chmod"
|
||||||
|
;;
|
||||||
|
CYGWIN* )
|
||||||
|
FS="/"
|
||||||
|
PS=";"
|
||||||
|
CP="cp"
|
||||||
|
CHMOD="chmod"
|
||||||
|
#
|
||||||
|
# javac does not like /cygdrive produced by `pwd`
|
||||||
|
#
|
||||||
|
TESTSRC=`cygpath -d ${TESTSRC}`
|
||||||
|
;;
|
||||||
|
* )
|
||||||
|
echo "Unrecognized system!"
|
||||||
|
exit 1;
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# first make cert/key DBs writable
|
||||||
|
|
||||||
|
${CP} ${TESTSRC}${FS}..${FS}nss${FS}db${FS}cert8.db ${TESTCLASSES}
|
||||||
|
${CHMOD} +w ${TESTCLASSES}${FS}cert8.db
|
||||||
|
|
||||||
|
${CP} ${TESTSRC}${FS}..${FS}nss${FS}db${FS}key3.db ${TESTCLASSES}
|
||||||
|
${CHMOD} +w ${TESTCLASSES}${FS}key3.db
|
||||||
|
|
||||||
|
# compile test
|
||||||
|
${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
|
||||||
|
-classpath ${TESTCLASSPATH} \
|
||||||
|
-d ${TESTCLASSES} \
|
||||||
|
--add-modules jdk.crypto.cryptoki \
|
||||||
|
--add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED \
|
||||||
|
${TESTSRC}${FS}..${FS}..${FS}..${FS}..${FS}..${FS}lib${FS}jdk${FS}test${FS}lib${FS}artifacts${FS}*.java \
|
||||||
|
${TESTSRC}${FS}MultipleLogins.java \
|
||||||
|
${TESTSRC}${FS}..${FS}PKCS11Test.java
|
||||||
|
|
||||||
|
# run test
|
||||||
|
${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} \
|
||||||
|
-classpath ${TESTCLASSPATH} \
|
||||||
|
--add-modules jdk.crypto.cryptoki \
|
||||||
|
--add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED \
|
||||||
|
-DCUSTOM_DB_DIR=${TESTCLASSES} \
|
||||||
|
-DCUSTOM_P11_CONFIG=${TESTSRC}${FS}MultipleLogins-nss.txt \
|
||||||
|
-DNO_DEFAULT=true \
|
||||||
|
-DNO_DEIMOS=true \
|
||||||
|
-Dtest.src=${TESTSRC} \
|
||||||
|
-Dtest.classes=${TESTCLASSES} \
|
||||||
|
-Djava.security.debug=${DEBUG} \
|
||||||
|
MultipleLogins
|
||||||
|
|
||||||
|
# save error status
|
||||||
|
status=$?
|
||||||
|
|
||||||
|
# return
|
||||||
|
exit $status
|
Loading…
Reference in New Issue
Block a user