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/P11KeyAgreement.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.math.BigInteger;
29
30
import java.security.*;
31
import java.security.spec.*;
32
33
import javax.crypto.*;
34
import javax.crypto.interfaces.*;
35
import javax.crypto.spec.*;
36
37
import static sun.security.pkcs11.TemplateManager.*;
38
import sun.security.pkcs11.wrapper.*;
39
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
40
import sun.security.util.KeyUtil;
41
42
/**
43
* KeyAgreement implementation class. This class currently supports
44
* DH.
45
*
46
* @author Andreas Sterbenz
47
* @since 1.5
48
*/
49
final class P11KeyAgreement extends KeyAgreementSpi {
50
51
// token instance
52
private final Token token;
53
54
// algorithm name
55
private final String algorithm;
56
57
// mechanism id
58
private final long mechanism;
59
60
// private key, if initialized
61
private P11Key privateKey;
62
63
// other sides public value ("y"), if doPhase() already called
64
private BigInteger publicValue;
65
66
// length of the secret to be derived
67
private int secretLen;
68
69
// KeyAgreement from SunJCE as fallback for > 2 party agreement
70
private KeyAgreement multiPartyAgreement;
71
72
private static class AllowKDF {
73
74
private static final boolean VALUE = getValue();
75
76
@SuppressWarnings("removal")
77
private static boolean getValue() {
78
return AccessController.doPrivileged(
79
(PrivilegedAction<Boolean>)
80
() -> Boolean.getBoolean("jdk.crypto.KeyAgreement.legacyKDF"));
81
}
82
}
83
84
P11KeyAgreement(Token token, String algorithm, long mechanism) {
85
super();
86
this.token = token;
87
this.algorithm = algorithm;
88
this.mechanism = mechanism;
89
}
90
91
// see JCE spec
92
protected void engineInit(Key key, SecureRandom random)
93
throws InvalidKeyException {
94
if (key instanceof PrivateKey == false) {
95
throw new InvalidKeyException
96
("Key must be instance of PrivateKey");
97
}
98
privateKey = P11KeyFactory.convertKey(token, key, algorithm);
99
publicValue = null;
100
multiPartyAgreement = null;
101
}
102
103
// see JCE spec
104
protected void engineInit(Key key, AlgorithmParameterSpec params,
105
SecureRandom random) throws InvalidKeyException,
106
InvalidAlgorithmParameterException {
107
if (params != null) {
108
throw new InvalidAlgorithmParameterException
109
("Parameters not supported");
110
}
111
engineInit(key, random);
112
}
113
114
// see JCE spec
115
protected Key engineDoPhase(Key key, boolean lastPhase)
116
throws InvalidKeyException, IllegalStateException {
117
if (privateKey == null) {
118
throw new IllegalStateException("Not initialized");
119
}
120
if (publicValue != null) {
121
throw new IllegalStateException("Phase already executed");
122
}
123
// PKCS#11 only allows key agreement between 2 parties
124
// JCE allows >= 2 parties. To support that case (for compatibility
125
// and to pass JCK), fall back to SunJCE in this case.
126
// NOTE that we initialize using the P11Key, which will fail if it
127
// is sensitive/unextractable. However, this is not an issue in the
128
// compatibility configuration, which is all we are targeting here.
129
if ((multiPartyAgreement != null) || (lastPhase == false)) {
130
if (multiPartyAgreement == null) {
131
try {
132
multiPartyAgreement = KeyAgreement.getInstance
133
("DH", P11Util.getSunJceProvider());
134
multiPartyAgreement.init(privateKey);
135
} catch (NoSuchAlgorithmException e) {
136
throw new InvalidKeyException
137
("Could not initialize multi party agreement", e);
138
}
139
}
140
return multiPartyAgreement.doPhase(key, lastPhase);
141
}
142
if ((key instanceof PublicKey == false)
143
|| (key.getAlgorithm().equals(algorithm) == false)) {
144
throw new InvalidKeyException
145
("Key must be a PublicKey with algorithm DH");
146
}
147
BigInteger p, g, y;
148
if (key instanceof DHPublicKey) {
149
DHPublicKey dhKey = (DHPublicKey)key;
150
151
// validate the Diffie-Hellman public key
152
KeyUtil.validate(dhKey);
153
154
y = dhKey.getY();
155
DHParameterSpec params = dhKey.getParams();
156
p = params.getP();
157
g = params.getG();
158
} else {
159
// normally, DH PublicKeys will always implement DHPublicKey
160
// just in case not, attempt conversion
161
P11DHKeyFactory kf = new P11DHKeyFactory(token, "DH");
162
try {
163
DHPublicKeySpec spec = kf.engineGetKeySpec(
164
key, DHPublicKeySpec.class);
165
166
// validate the Diffie-Hellman public key
167
KeyUtil.validate(spec);
168
169
y = spec.getY();
170
p = spec.getP();
171
g = spec.getG();
172
} catch (InvalidKeySpecException e) {
173
throw new InvalidKeyException("Could not obtain key values", e);
174
}
175
}
176
// if parameters of private key are accessible, verify that
177
// they match parameters of public key
178
// XXX p and g should always be readable, even if the key is sensitive
179
if (privateKey instanceof DHPrivateKey) {
180
DHPrivateKey dhKey = (DHPrivateKey)privateKey;
181
DHParameterSpec params = dhKey.getParams();
182
if ((p.equals(params.getP()) == false)
183
|| (g.equals(params.getG()) == false)) {
184
throw new InvalidKeyException
185
("PublicKey DH parameters must match PrivateKey DH parameters");
186
}
187
}
188
publicValue = y;
189
// length of the secret is length of key
190
secretLen = (p.bitLength() + 7) >> 3;
191
return null;
192
}
193
194
// see JCE spec
195
protected byte[] engineGenerateSecret() throws IllegalStateException {
196
if (multiPartyAgreement != null) {
197
byte[] val = multiPartyAgreement.generateSecret();
198
multiPartyAgreement = null;
199
return val;
200
}
201
if ((privateKey == null) || (publicValue == null)) {
202
throw new IllegalStateException("Not initialized correctly");
203
}
204
Session session = null;
205
long privKeyID = privateKey.getKeyID();
206
try {
207
session = token.getOpSession();
208
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
209
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
210
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET),
211
};
212
attributes = token.getAttributes
213
(O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes);
214
long keyID = token.p11.C_DeriveKey(session.id(),
215
new CK_MECHANISM(mechanism, publicValue), privKeyID,
216
attributes);
217
218
attributes = new CK_ATTRIBUTE[] {
219
new CK_ATTRIBUTE(CKA_VALUE)
220
};
221
token.p11.C_GetAttributeValue(session.id(), keyID, attributes);
222
byte[] secret = attributes[0].getByteArray();
223
token.p11.C_DestroyObject(session.id(), keyID);
224
// Some vendors, e.g. NSS, trim off the leading 0x00 byte(s) from
225
// the generated secret. Thus, we need to check the secret length
226
// and trim/pad it so the returned value has the same length as
227
// the modulus size
228
if (secret.length == secretLen) {
229
return secret;
230
} else {
231
if (secret.length > secretLen) {
232
// Shouldn't happen; but check just in case
233
throw new ProviderException("generated secret is out-of-range");
234
}
235
byte[] newSecret = new byte[secretLen];
236
System.arraycopy(secret, 0, newSecret, secretLen - secret.length,
237
secret.length);
238
return newSecret;
239
}
240
} catch (PKCS11Exception e) {
241
throw new ProviderException("Could not derive key", e);
242
} finally {
243
privateKey.releaseKeyID();
244
publicValue = null;
245
token.releaseSession(session);
246
}
247
}
248
249
// see JCE spec
250
protected int engineGenerateSecret(byte[] sharedSecret, int
251
offset) throws IllegalStateException, ShortBufferException {
252
if (multiPartyAgreement != null) {
253
int n = multiPartyAgreement.generateSecret(sharedSecret, offset);
254
multiPartyAgreement = null;
255
return n;
256
}
257
if (offset + secretLen > sharedSecret.length) {
258
throw new ShortBufferException("Need " + secretLen
259
+ " bytes, only " + (sharedSecret.length - offset) + " available");
260
}
261
byte[] secret = engineGenerateSecret();
262
System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
263
return secret.length;
264
}
265
266
// see JCE spec
267
protected SecretKey engineGenerateSecret(String algorithm)
268
throws IllegalStateException, NoSuchAlgorithmException,
269
InvalidKeyException {
270
if (multiPartyAgreement != null) {
271
SecretKey key = multiPartyAgreement.generateSecret(algorithm);
272
multiPartyAgreement = null;
273
return key;
274
}
275
if (algorithm == null) {
276
throw new NoSuchAlgorithmException("Algorithm must not be null");
277
}
278
279
if (algorithm.equals("TlsPremasterSecret")) {
280
// For now, only perform native derivation for TlsPremasterSecret
281
// as that is required for FIPS compliance.
282
// For other algorithms, there are unresolved issues regarding
283
// how this should work in JCE plus a Solaris truncation bug.
284
// (bug not yet filed).
285
return nativeGenerateSecret(algorithm);
286
}
287
288
if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") &&
289
!AllowKDF.VALUE) {
290
291
throw new NoSuchAlgorithmException("Unsupported secret key "
292
+ "algorithm: " + algorithm);
293
}
294
295
byte[] secret = engineGenerateSecret();
296
// Maintain compatibility for SunJCE:
297
// verify secret length is sensible for algorithm / truncate
298
// return generated key itself if possible
299
int keyLen;
300
if (algorithm.equalsIgnoreCase("DES")) {
301
keyLen = 8;
302
} else if (algorithm.equalsIgnoreCase("DESede")) {
303
keyLen = 24;
304
} else if (algorithm.equalsIgnoreCase("Blowfish")) {
305
keyLen = Math.min(56, secret.length);
306
} else if (algorithm.equalsIgnoreCase("TlsPremasterSecret")) {
307
keyLen = secret.length;
308
} else {
309
throw new NoSuchAlgorithmException
310
("Unknown algorithm " + algorithm);
311
}
312
if (secret.length < keyLen) {
313
throw new InvalidKeyException("Secret too short");
314
}
315
if (algorithm.equalsIgnoreCase("DES") ||
316
algorithm.equalsIgnoreCase("DESede")) {
317
for (int i = 0; i < keyLen; i+=8) {
318
P11SecretKeyFactory.fixDESParity(secret, i);
319
}
320
}
321
return new SecretKeySpec(secret, 0, keyLen, algorithm);
322
}
323
324
private SecretKey nativeGenerateSecret(String algorithm)
325
throws IllegalStateException, NoSuchAlgorithmException,
326
InvalidKeyException {
327
if ((privateKey == null) || (publicValue == null)) {
328
throw new IllegalStateException("Not initialized correctly");
329
}
330
long keyType = CKK_GENERIC_SECRET;
331
Session session = null;
332
long privKeyID = privateKey.getKeyID();
333
try {
334
session = token.getObjSession();
335
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
336
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
337
new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
338
};
339
attributes = token.getAttributes
340
(O_GENERATE, CKO_SECRET_KEY, keyType, attributes);
341
long keyID = token.p11.C_DeriveKey(session.id(),
342
new CK_MECHANISM(mechanism, publicValue), privKeyID,
343
attributes);
344
CK_ATTRIBUTE[] lenAttributes = new CK_ATTRIBUTE[] {
345
new CK_ATTRIBUTE(CKA_VALUE_LEN),
346
};
347
token.p11.C_GetAttributeValue(session.id(), keyID, lenAttributes);
348
int keyLen = (int)lenAttributes[0].getLong();
349
SecretKey key = P11Key.secretKey
350
(session, keyID, algorithm, keyLen << 3, attributes);
351
if ("RAW".equals(key.getFormat())) {
352
// Workaround for Solaris bug 6318543.
353
// Strip leading zeroes ourselves if possible (key not sensitive).
354
// This should be removed once the Solaris fix is available
355
// as here we always retrieve the CKA_VALUE even for tokens
356
// that do not have that bug.
357
byte[] keyBytes = key.getEncoded();
358
byte[] newBytes = KeyUtil.trimZeroes(keyBytes);
359
if (keyBytes != newBytes) {
360
key = new SecretKeySpec(newBytes, algorithm);
361
}
362
}
363
return key;
364
} catch (PKCS11Exception e) {
365
throw new InvalidKeyException("Could not derive key", e);
366
} finally {
367
privateKey.releaseKeyID();
368
publicValue = null;
369
token.releaseSession(session);
370
}
371
}
372
373
}
374
375