mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-24 04:54:40 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -1,450 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2013, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sun.security.pkcs11;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.io.*;
|
||||
import java.lang.ref.*;
|
||||
|
||||
import java.security.*;
|
||||
import javax.security.auth.login.LoginException;
|
||||
|
||||
import sun.security.jca.JCAUtil;
|
||||
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.TemplateManager.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
|
||||
/**
|
||||
* PKCS#11 token.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @since 1.5
|
||||
*/
|
||||
class Token implements Serializable {
|
||||
|
||||
// need to be serializable to allow SecureRandom to be serialized
|
||||
private static final long serialVersionUID = 2541527649100571747L;
|
||||
|
||||
// how often to check if the token is still present (in ms)
|
||||
// this is different from checking if a token has been inserted,
|
||||
// that is done in SunPKCS11. Currently 50 ms.
|
||||
private final static long CHECK_INTERVAL = 50;
|
||||
|
||||
final SunPKCS11 provider;
|
||||
|
||||
final PKCS11 p11;
|
||||
|
||||
final Config config;
|
||||
|
||||
final CK_TOKEN_INFO tokenInfo;
|
||||
|
||||
// session manager to pool sessions
|
||||
final SessionManager sessionManager;
|
||||
|
||||
// template manager to customize the attributes used when creating objects
|
||||
private final TemplateManager templateManager;
|
||||
|
||||
// flag indicating whether we need to explicitly cancel operations
|
||||
// we started on the token. If false, we assume operations are
|
||||
// automatically cancelled once we start another one
|
||||
final boolean explicitCancel;
|
||||
|
||||
// translation cache for secret keys
|
||||
final KeyCache secretCache;
|
||||
|
||||
// translation cache for asymmetric keys (public and private)
|
||||
final KeyCache privateCache;
|
||||
|
||||
// cached instances of the various key factories, initialized on demand
|
||||
private volatile P11KeyFactory rsaFactory, dsaFactory, dhFactory, ecFactory;
|
||||
|
||||
// table which maps mechanisms to the corresponding cached
|
||||
// MechanismInfo objects
|
||||
private final Map<Long, CK_MECHANISM_INFO> mechInfoMap;
|
||||
|
||||
// single SecureRandomSpi instance we use per token
|
||||
// initialized on demand (if supported)
|
||||
private volatile P11SecureRandom secureRandom;
|
||||
|
||||
// single KeyStoreSpi instance we use per provider
|
||||
// initialized on demand
|
||||
private volatile P11KeyStore keyStore;
|
||||
|
||||
// whether this token is a removable token
|
||||
private final boolean removable;
|
||||
|
||||
// for removable tokens: whether this token is valid or has been removed
|
||||
private volatile boolean valid;
|
||||
|
||||
// for removable tokens: time last checked for token presence
|
||||
private long lastPresentCheck;
|
||||
|
||||
// unique token id, used for serialization only
|
||||
private byte[] tokenId;
|
||||
|
||||
// flag indicating whether the token is write protected
|
||||
private boolean writeProtected;
|
||||
|
||||
// flag indicating whether we are logged in
|
||||
private volatile boolean loggedIn;
|
||||
|
||||
// time we last checked login status
|
||||
private long lastLoginCheck;
|
||||
|
||||
// mutex for token-present-check
|
||||
private final static Object CHECK_LOCK = new Object();
|
||||
|
||||
// object for indicating unsupported mechanism in 'mechInfoMap'
|
||||
private final static CK_MECHANISM_INFO INVALID_MECH =
|
||||
new CK_MECHANISM_INFO(0, 0, 0);
|
||||
|
||||
// flag indicating whether the token supports raw secret key material import
|
||||
private Boolean supportsRawSecretKeyImport;
|
||||
|
||||
Token(SunPKCS11 provider) throws PKCS11Exception {
|
||||
this.provider = provider;
|
||||
this.removable = provider.removable;
|
||||
this.valid = true;
|
||||
p11 = provider.p11;
|
||||
config = provider.config;
|
||||
tokenInfo = p11.C_GetTokenInfo(provider.slotID);
|
||||
writeProtected = (tokenInfo.flags & CKF_WRITE_PROTECTED) != 0;
|
||||
// create session manager and open a test session
|
||||
SessionManager sessionManager;
|
||||
try {
|
||||
sessionManager = new SessionManager(this);
|
||||
Session s = sessionManager.getOpSession();
|
||||
sessionManager.releaseSession(s);
|
||||
} catch (PKCS11Exception e) {
|
||||
if (writeProtected) {
|
||||
throw e;
|
||||
}
|
||||
// token might not permit RW sessions even though
|
||||
// CKF_WRITE_PROTECTED is not set
|
||||
writeProtected = true;
|
||||
sessionManager = new SessionManager(this);
|
||||
Session s = sessionManager.getOpSession();
|
||||
sessionManager.releaseSession(s);
|
||||
}
|
||||
this.sessionManager = sessionManager;
|
||||
secretCache = new KeyCache();
|
||||
privateCache = new KeyCache();
|
||||
templateManager = config.getTemplateManager();
|
||||
explicitCancel = config.getExplicitCancel();
|
||||
mechInfoMap =
|
||||
new ConcurrentHashMap<Long, CK_MECHANISM_INFO>(10);
|
||||
}
|
||||
|
||||
boolean isWriteProtected() {
|
||||
return writeProtected;
|
||||
}
|
||||
|
||||
// return whether the token supports raw secret key material import
|
||||
boolean supportsRawSecretKeyImport() {
|
||||
if (supportsRawSecretKeyImport == null) {
|
||||
SecureRandom random = JCAUtil.getSecureRandom();
|
||||
byte[] encoded = new byte[48];
|
||||
random.nextBytes(encoded);
|
||||
|
||||
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[3];
|
||||
attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY);
|
||||
attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET);
|
||||
attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded);
|
||||
|
||||
Session session = null;
|
||||
try {
|
||||
attributes = getAttributes(O_IMPORT,
|
||||
CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes);
|
||||
session = getObjSession();
|
||||
long keyID = p11.C_CreateObject(session.id(), attributes);
|
||||
|
||||
supportsRawSecretKeyImport = Boolean.TRUE;
|
||||
} catch (PKCS11Exception e) {
|
||||
supportsRawSecretKeyImport = Boolean.FALSE;
|
||||
} finally {
|
||||
releaseSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
return supportsRawSecretKeyImport;
|
||||
}
|
||||
|
||||
// return whether we are logged in
|
||||
// uses cached result if current. session is optional and may be null
|
||||
boolean isLoggedIn(Session session) throws PKCS11Exception {
|
||||
// volatile load first
|
||||
boolean loggedIn = this.loggedIn;
|
||||
long time = System.currentTimeMillis();
|
||||
if (time - lastLoginCheck > CHECK_INTERVAL) {
|
||||
loggedIn = isLoggedInNow(session);
|
||||
lastLoginCheck = time;
|
||||
}
|
||||
return loggedIn;
|
||||
}
|
||||
|
||||
// return whether we are logged in now
|
||||
// does not use cache
|
||||
boolean isLoggedInNow(Session session) throws PKCS11Exception {
|
||||
boolean allocSession = (session == null);
|
||||
try {
|
||||
if (allocSession) {
|
||||
session = getOpSession();
|
||||
}
|
||||
CK_SESSION_INFO info = p11.C_GetSessionInfo(session.id());
|
||||
boolean loggedIn = (info.state == CKS_RO_USER_FUNCTIONS) ||
|
||||
(info.state == CKS_RW_USER_FUNCTIONS);
|
||||
this.loggedIn = loggedIn;
|
||||
return loggedIn;
|
||||
} finally {
|
||||
if (allocSession) {
|
||||
releaseSession(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that we are logged in
|
||||
// call provider.login() if not
|
||||
void ensureLoggedIn(Session session) throws PKCS11Exception, LoginException {
|
||||
if (isLoggedIn(session) == false) {
|
||||
provider.login(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
// return whether this token object is valid (i.e. token not removed)
|
||||
// returns value from last check, does not perform new check
|
||||
boolean isValid() {
|
||||
if (removable == false) {
|
||||
return true;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
void ensureValid() {
|
||||
if (isValid() == false) {
|
||||
throw new ProviderException("Token has been removed");
|
||||
}
|
||||
}
|
||||
|
||||
// return whether a token is present (i.e. token not removed)
|
||||
// returns cached value if current, otherwise performs new check
|
||||
boolean isPresent(long sessionID) {
|
||||
if (removable == false) {
|
||||
return true;
|
||||
}
|
||||
if (valid == false) {
|
||||
return false;
|
||||
}
|
||||
long time = System.currentTimeMillis();
|
||||
if ((time - lastPresentCheck) >= CHECK_INTERVAL) {
|
||||
synchronized (CHECK_LOCK) {
|
||||
if ((time - lastPresentCheck) >= CHECK_INTERVAL) {
|
||||
boolean ok = false;
|
||||
try {
|
||||
// check if token still present
|
||||
CK_SLOT_INFO slotInfo =
|
||||
provider.p11.C_GetSlotInfo(provider.slotID);
|
||||
if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) {
|
||||
// if the token has been removed and re-inserted,
|
||||
// the token should return an error
|
||||
CK_SESSION_INFO sessInfo =
|
||||
provider.p11.C_GetSessionInfo
|
||||
(sessionID);
|
||||
ok = true;
|
||||
}
|
||||
} catch (PKCS11Exception e) {
|
||||
// empty
|
||||
}
|
||||
valid = ok;
|
||||
lastPresentCheck = System.currentTimeMillis();
|
||||
if (ok == false) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
valid = false;
|
||||
provider.uninitToken(this);
|
||||
}
|
||||
|
||||
Session getObjSession() throws PKCS11Exception {
|
||||
return sessionManager.getObjSession();
|
||||
}
|
||||
|
||||
Session getOpSession() throws PKCS11Exception {
|
||||
return sessionManager.getOpSession();
|
||||
}
|
||||
|
||||
Session releaseSession(Session session) {
|
||||
return sessionManager.releaseSession(session);
|
||||
}
|
||||
|
||||
Session killSession(Session session) {
|
||||
return sessionManager.killSession(session);
|
||||
}
|
||||
|
||||
CK_ATTRIBUTE[] getAttributes(String op, long type, long alg,
|
||||
CK_ATTRIBUTE[] attrs) throws PKCS11Exception {
|
||||
CK_ATTRIBUTE[] newAttrs =
|
||||
templateManager.getAttributes(op, type, alg, attrs);
|
||||
for (CK_ATTRIBUTE attr : newAttrs) {
|
||||
if (attr.type == CKA_TOKEN) {
|
||||
if (attr.getBoolean()) {
|
||||
try {
|
||||
ensureLoggedIn(null);
|
||||
} catch (LoginException e) {
|
||||
throw new ProviderException("Login failed", e);
|
||||
}
|
||||
}
|
||||
// break once we have found a CKA_TOKEN attribute
|
||||
break;
|
||||
}
|
||||
}
|
||||
return newAttrs;
|
||||
}
|
||||
|
||||
P11KeyFactory getKeyFactory(String algorithm) {
|
||||
P11KeyFactory f;
|
||||
if (algorithm.equals("RSA")) {
|
||||
f = rsaFactory;
|
||||
if (f == null) {
|
||||
f = new P11RSAKeyFactory(this, algorithm);
|
||||
rsaFactory = f;
|
||||
}
|
||||
} else if (algorithm.equals("DSA")) {
|
||||
f = dsaFactory;
|
||||
if (f == null) {
|
||||
f = new P11DSAKeyFactory(this, algorithm);
|
||||
dsaFactory = f;
|
||||
}
|
||||
} else if (algorithm.equals("DH")) {
|
||||
f = dhFactory;
|
||||
if (f == null) {
|
||||
f = new P11DHKeyFactory(this, algorithm);
|
||||
dhFactory = f;
|
||||
}
|
||||
} else if (algorithm.equals("EC")) {
|
||||
f = ecFactory;
|
||||
if (f == null) {
|
||||
f = new P11ECKeyFactory(this, algorithm);
|
||||
ecFactory = f;
|
||||
}
|
||||
} else {
|
||||
throw new ProviderException("Unknown algorithm " + algorithm);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
P11SecureRandom getRandom() {
|
||||
if (secureRandom == null) {
|
||||
secureRandom = new P11SecureRandom(this);
|
||||
}
|
||||
return secureRandom;
|
||||
}
|
||||
|
||||
P11KeyStore getKeyStore() {
|
||||
if (keyStore == null) {
|
||||
keyStore = new P11KeyStore(this);
|
||||
}
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
CK_MECHANISM_INFO getMechanismInfo(long mechanism) throws PKCS11Exception {
|
||||
CK_MECHANISM_INFO result = mechInfoMap.get(mechanism);
|
||||
if (result == null) {
|
||||
try {
|
||||
result = p11.C_GetMechanismInfo(provider.slotID,
|
||||
mechanism);
|
||||
mechInfoMap.put(mechanism, result);
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.getErrorCode() != PKCS11Constants.CKR_MECHANISM_INVALID) {
|
||||
throw e;
|
||||
} else {
|
||||
mechInfoMap.put(mechanism, INVALID_MECH);
|
||||
}
|
||||
}
|
||||
} else if (result == INVALID_MECH) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private synchronized byte[] getTokenId() {
|
||||
if (tokenId == null) {
|
||||
SecureRandom random = JCAUtil.getSecureRandom();
|
||||
tokenId = new byte[20];
|
||||
random.nextBytes(tokenId);
|
||||
serializedTokens.add(new WeakReference<Token>(this));
|
||||
}
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
// list of all tokens that have been serialized within this VM
|
||||
// NOTE that elements are never removed from this list
|
||||
// the assumption is that the number of tokens that are serialized
|
||||
// is relatively small
|
||||
private static final List<Reference<Token>> serializedTokens =
|
||||
new ArrayList<Reference<Token>>();
|
||||
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
if (isValid() == false) {
|
||||
throw new NotSerializableException("Token has been removed");
|
||||
}
|
||||
return new TokenRep(this);
|
||||
}
|
||||
|
||||
// serialized representation of a token
|
||||
// tokens can only be de-serialized within the same VM invocation
|
||||
// and if the token has not been removed in the meantime
|
||||
private static class TokenRep implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3503721168218219807L;
|
||||
|
||||
private final byte[] tokenId;
|
||||
|
||||
TokenRep(Token token) {
|
||||
tokenId = token.getTokenId();
|
||||
}
|
||||
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
for (Reference<Token> tokenRef : serializedTokens) {
|
||||
Token token = tokenRef.get();
|
||||
if ((token != null) && token.isValid()) {
|
||||
if (Arrays.equals(token.getTokenId(), tokenId)) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new NotSerializableException("Could not find token");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue