Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java
41154 views
1
/*
2
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.pkcs11;
27
28
import java.util.*;
29
import java.util.concurrent.ConcurrentHashMap;
30
import java.io.*;
31
import java.lang.ref.*;
32
33
import java.security.*;
34
import javax.security.auth.login.LoginException;
35
36
import sun.security.jca.JCAUtil;
37
38
import sun.security.pkcs11.wrapper.*;
39
import static sun.security.pkcs11.TemplateManager.*;
40
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
41
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
42
43
/**
44
* PKCS#11 token.
45
*
46
* @author Andreas Sterbenz
47
* @since 1.5
48
*/
49
class Token implements Serializable {
50
51
// need to be serializable to allow SecureRandom to be serialized
52
private static final long serialVersionUID = 2541527649100571747L;
53
54
// how often to check if the token is still present (in ms)
55
// this is different from checking if a token has been inserted,
56
// that is done in SunPKCS11. Currently 50 ms.
57
private static final long CHECK_INTERVAL = 50;
58
59
final SunPKCS11 provider;
60
61
final PKCS11 p11;
62
63
final Config config;
64
65
final CK_TOKEN_INFO tokenInfo;
66
67
// session manager to pool sessions
68
final SessionManager sessionManager;
69
70
// template manager to customize the attributes used when creating objects
71
private final TemplateManager templateManager;
72
73
// flag indicating whether we need to explicitly cancel operations
74
// we started on the token. If false, we assume operations are
75
// automatically cancelled once we start another one
76
final boolean explicitCancel;
77
78
// translation cache for secret keys
79
final KeyCache secretCache;
80
81
// translation cache for asymmetric keys (public and private)
82
final KeyCache privateCache;
83
84
// cached instances of the various key factories, initialized on demand
85
private volatile P11KeyFactory rsaFactory, dsaFactory, dhFactory, ecFactory;
86
87
// table which maps mechanisms to the corresponding cached
88
// MechanismInfo objects
89
private final Map<Long, CK_MECHANISM_INFO> mechInfoMap;
90
91
// single SecureRandomSpi instance we use per token
92
// initialized on demand (if supported)
93
private volatile P11SecureRandom secureRandom;
94
95
// single KeyStoreSpi instance we use per provider
96
// initialized on demand
97
private volatile P11KeyStore keyStore;
98
99
// whether this token is a removable token
100
private final boolean removable;
101
102
// for removable tokens: whether this token is valid or has been removed
103
private volatile boolean valid;
104
105
// for removable tokens: time last checked for token presence
106
private long lastPresentCheck;
107
108
// unique token id, used for serialization only
109
private byte[] tokenId;
110
111
// flag indicating whether the token is write protected
112
private boolean writeProtected;
113
114
// flag indicating whether we are logged in
115
private volatile boolean loggedIn;
116
117
// time we last checked login status
118
private long lastLoginCheck;
119
120
// mutex for token-present-check
121
private static final Object CHECK_LOCK = new Object();
122
123
// object for indicating unsupported mechanism in 'mechInfoMap'
124
private static final CK_MECHANISM_INFO INVALID_MECH =
125
new CK_MECHANISM_INFO(0, 0, 0);
126
127
// flag indicating whether the token supports raw secret key material import
128
private Boolean supportsRawSecretKeyImport;
129
130
Token(SunPKCS11 provider) throws PKCS11Exception {
131
this.provider = provider;
132
this.removable = provider.removable;
133
this.valid = true;
134
p11 = provider.p11;
135
config = provider.config;
136
tokenInfo = p11.C_GetTokenInfo(provider.slotID);
137
writeProtected = (tokenInfo.flags & CKF_WRITE_PROTECTED) != 0;
138
// create session manager and open a test session
139
SessionManager sessionManager;
140
try {
141
sessionManager = new SessionManager(this);
142
Session s = sessionManager.getOpSession();
143
sessionManager.releaseSession(s);
144
} catch (PKCS11Exception e) {
145
if (writeProtected) {
146
throw e;
147
}
148
// token might not permit RW sessions even though
149
// CKF_WRITE_PROTECTED is not set
150
writeProtected = true;
151
sessionManager = new SessionManager(this);
152
Session s = sessionManager.getOpSession();
153
sessionManager.releaseSession(s);
154
}
155
this.sessionManager = sessionManager;
156
secretCache = new KeyCache();
157
privateCache = new KeyCache();
158
templateManager = config.getTemplateManager();
159
explicitCancel = config.getExplicitCancel();
160
mechInfoMap =
161
new ConcurrentHashMap<Long, CK_MECHANISM_INFO>(10);
162
}
163
164
boolean isWriteProtected() {
165
return writeProtected;
166
}
167
168
// return whether the token supports raw secret key material import
169
boolean supportsRawSecretKeyImport() {
170
if (supportsRawSecretKeyImport == null) {
171
SecureRandom random = JCAUtil.getSecureRandom();
172
byte[] encoded = new byte[48];
173
random.nextBytes(encoded);
174
175
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[3];
176
attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY);
177
attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET);
178
attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded);
179
180
Session session = null;
181
try {
182
attributes = getAttributes(O_IMPORT,
183
CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes);
184
session = getObjSession();
185
long keyID = p11.C_CreateObject(session.id(), attributes);
186
187
supportsRawSecretKeyImport = Boolean.TRUE;
188
} catch (PKCS11Exception e) {
189
supportsRawSecretKeyImport = Boolean.FALSE;
190
} finally {
191
releaseSession(session);
192
}
193
}
194
195
return supportsRawSecretKeyImport;
196
}
197
198
// return whether we are logged in
199
// uses cached result if current. session is optional and may be null
200
boolean isLoggedIn(Session session) throws PKCS11Exception {
201
// volatile load first
202
boolean loggedIn = this.loggedIn;
203
long time = System.currentTimeMillis();
204
if (time - lastLoginCheck > CHECK_INTERVAL) {
205
loggedIn = isLoggedInNow(session);
206
lastLoginCheck = time;
207
}
208
return loggedIn;
209
}
210
211
// return whether we are logged in now
212
// does not use cache
213
boolean isLoggedInNow(Session session) throws PKCS11Exception {
214
boolean allocSession = (session == null);
215
try {
216
if (allocSession) {
217
session = getOpSession();
218
}
219
CK_SESSION_INFO info = p11.C_GetSessionInfo(session.id());
220
boolean loggedIn = (info.state == CKS_RO_USER_FUNCTIONS) ||
221
(info.state == CKS_RW_USER_FUNCTIONS);
222
this.loggedIn = loggedIn;
223
return loggedIn;
224
} finally {
225
if (allocSession) {
226
releaseSession(session);
227
}
228
}
229
}
230
231
// ensure that we are logged in
232
// call provider.login() if not
233
void ensureLoggedIn(Session session) throws PKCS11Exception, LoginException {
234
if (isLoggedIn(session) == false) {
235
provider.login(null, null);
236
}
237
}
238
239
// return whether this token object is valid (i.e. token not removed)
240
// returns value from last check, does not perform new check
241
boolean isValid() {
242
if (removable == false) {
243
return true;
244
}
245
return valid;
246
}
247
248
void ensureValid() {
249
if (isValid() == false) {
250
throw new ProviderException("Token has been removed");
251
}
252
}
253
254
// return whether a token is present (i.e. token not removed)
255
// returns cached value if current, otherwise performs new check
256
boolean isPresent(long sessionID) {
257
if (removable == false) {
258
return true;
259
}
260
if (valid == false) {
261
return false;
262
}
263
long time = System.currentTimeMillis();
264
if ((time - lastPresentCheck) >= CHECK_INTERVAL) {
265
synchronized (CHECK_LOCK) {
266
if ((time - lastPresentCheck) >= CHECK_INTERVAL) {
267
boolean ok = false;
268
try {
269
// check if token still present
270
CK_SLOT_INFO slotInfo =
271
provider.p11.C_GetSlotInfo(provider.slotID);
272
if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) {
273
// if the token has been removed and re-inserted,
274
// the token should return an error
275
CK_SESSION_INFO sessInfo =
276
provider.p11.C_GetSessionInfo
277
(sessionID);
278
ok = true;
279
}
280
} catch (PKCS11Exception e) {
281
// empty
282
}
283
valid = ok;
284
lastPresentCheck = System.currentTimeMillis();
285
if (ok == false) {
286
destroy();
287
}
288
}
289
}
290
}
291
return valid;
292
}
293
294
void destroy() {
295
secretCache.clear();
296
privateCache.clear();
297
298
sessionManager.clearPools();
299
provider.uninitToken(this);
300
valid = false;
301
}
302
303
Session getObjSession() throws PKCS11Exception {
304
return sessionManager.getObjSession();
305
}
306
307
Session getOpSession() throws PKCS11Exception {
308
return sessionManager.getOpSession();
309
}
310
311
Session releaseSession(Session session) {
312
return sessionManager.releaseSession(session);
313
}
314
315
Session killSession(Session session) {
316
return sessionManager.killSession(session);
317
}
318
319
CK_ATTRIBUTE[] getAttributes(String op, long type, long alg,
320
CK_ATTRIBUTE[] attrs) throws PKCS11Exception {
321
CK_ATTRIBUTE[] newAttrs =
322
templateManager.getAttributes(op, type, alg, attrs);
323
for (CK_ATTRIBUTE attr : newAttrs) {
324
if (attr.type == CKA_TOKEN) {
325
if (attr.getBoolean()) {
326
try {
327
ensureLoggedIn(null);
328
} catch (LoginException e) {
329
throw new ProviderException("Login failed", e);
330
}
331
}
332
// break once we have found a CKA_TOKEN attribute
333
break;
334
}
335
}
336
return newAttrs;
337
}
338
339
P11KeyFactory getKeyFactory(String algorithm) {
340
P11KeyFactory f;
341
if (algorithm.equals("RSA")) {
342
f = rsaFactory;
343
if (f == null) {
344
f = new P11RSAKeyFactory(this, algorithm);
345
rsaFactory = f;
346
}
347
} else if (algorithm.equals("DSA")) {
348
f = dsaFactory;
349
if (f == null) {
350
f = new P11DSAKeyFactory(this, algorithm);
351
dsaFactory = f;
352
}
353
} else if (algorithm.equals("DH")) {
354
f = dhFactory;
355
if (f == null) {
356
f = new P11DHKeyFactory(this, algorithm);
357
dhFactory = f;
358
}
359
} else if (algorithm.equals("EC")) {
360
f = ecFactory;
361
if (f == null) {
362
f = new P11ECKeyFactory(this, algorithm);
363
ecFactory = f;
364
}
365
} else {
366
throw new ProviderException("Unknown algorithm " + algorithm);
367
}
368
return f;
369
}
370
371
P11SecureRandom getRandom() {
372
if (secureRandom == null) {
373
secureRandom = new P11SecureRandom(this);
374
}
375
return secureRandom;
376
}
377
378
P11KeyStore getKeyStore() {
379
if (keyStore == null) {
380
keyStore = new P11KeyStore(this);
381
}
382
return keyStore;
383
}
384
385
CK_MECHANISM_INFO getMechanismInfo(long mechanism) throws PKCS11Exception {
386
CK_MECHANISM_INFO result = mechInfoMap.get(mechanism);
387
if (result == null) {
388
try {
389
result = p11.C_GetMechanismInfo(provider.slotID,
390
mechanism);
391
mechInfoMap.put(mechanism, result);
392
} catch (PKCS11Exception e) {
393
if (e.getErrorCode() != CKR_MECHANISM_INVALID) {
394
throw e;
395
} else {
396
mechInfoMap.put(mechanism, INVALID_MECH);
397
}
398
}
399
} else if (result == INVALID_MECH) {
400
result = null;
401
}
402
return result;
403
}
404
405
private synchronized byte[] getTokenId() {
406
if (tokenId == null) {
407
SecureRandom random = JCAUtil.getSecureRandom();
408
tokenId = new byte[20];
409
random.nextBytes(tokenId);
410
serializedTokens.add(new WeakReference<Token>(this));
411
}
412
return tokenId;
413
}
414
415
// list of all tokens that have been serialized within this VM
416
// NOTE that elements are never removed from this list
417
// the assumption is that the number of tokens that are serialized
418
// is relatively small
419
private static final List<Reference<Token>> serializedTokens =
420
new ArrayList<Reference<Token>>();
421
422
private Object writeReplace() throws ObjectStreamException {
423
if (isValid() == false) {
424
throw new NotSerializableException("Token has been removed");
425
}
426
return new TokenRep(this);
427
}
428
429
// serialized representation of a token
430
// tokens can only be de-serialized within the same VM invocation
431
// and if the token has not been removed in the meantime
432
private static class TokenRep implements Serializable {
433
434
private static final long serialVersionUID = 3503721168218219807L;
435
436
private final byte[] tokenId;
437
438
TokenRep(Token token) {
439
tokenId = token.getTokenId();
440
}
441
442
private Object readResolve() throws ObjectStreamException {
443
for (Reference<Token> tokenRef : serializedTokens) {
444
Token token = tokenRef.get();
445
if ((token != null) && token.isValid()) {
446
if (Arrays.equals(token.getTokenId(), tokenId)) {
447
return token;
448
}
449
}
450
}
451
throw new NotSerializableException("Could not find token");
452
}
453
}
454
455
}
456
457