23 * questions.
24 */
25
26 package sun.security.ssl;
27
28 import java.security.*;
29 import java.security.spec.AlgorithmParameterSpec;
30 import java.security.spec.ECParameterSpec;
31 import java.security.spec.MGF1ParameterSpec;
32 import java.security.spec.PSSParameterSpec;
33 import java.util.AbstractMap.SimpleImmutableEntry;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.EnumSet;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import sun.security.ssl.NamedGroup.NamedGroupType;
44 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
45 import sun.security.ssl.X509Authentication.X509Possession;
46 import sun.security.util.KeyUtil;
47 import sun.security.util.SignatureUtil;
48
49 enum SignatureScheme {
50 // EdDSA algorithms
51 ED25519 (0x0807, "ed25519", "ed25519",
52 "ed25519",
53 ProtocolVersion.PROTOCOLS_OF_13),
54 ED448 (0x0808, "ed448", "ed448",
55 "ed448",
56 ProtocolVersion.PROTOCOLS_OF_13),
57
58 // ECDSA algorithms
59 ECDSA_SECP256R1_SHA256 (0x0403, "ecdsa_secp256r1_sha256",
60 "SHA256withECDSA",
61 "EC",
62 NamedGroup.SECP256_R1,
63 ProtocolVersion.PROTOCOLS_TO_13),
134 "DSA",
135 ProtocolVersion.PROTOCOLS_TO_12),
136 ECDSA_SHA1 (0x0203, "ecdsa_sha1", "SHA1withECDSA",
137 "EC",
138 ProtocolVersion.PROTOCOLS_TO_13),
139 RSA_PKCS1_SHA1 (0x0201, "rsa_pkcs1_sha1", "SHA1withRSA",
140 "RSA", null, null, 511,
141 ProtocolVersion.PROTOCOLS_TO_13,
142 ProtocolVersion.PROTOCOLS_TO_12),
143 DSA_SHA1 (0x0202, "dsa_sha1", "SHA1withDSA",
144 "DSA",
145 ProtocolVersion.PROTOCOLS_TO_12),
146 RSA_MD5 (0x0101, "rsa_md5", "MD5withRSA",
147 "RSA", 511,
148 ProtocolVersion.PROTOCOLS_TO_12);
149
150 final int id; // hash + signature
151 final String name; // literal name
152 private final String algorithm; // signature algorithm
153 final String keyAlgorithm; // signature key algorithm
154 private final AlgorithmParameterSpec signAlgParameter;
155 private final NamedGroup namedGroup; // associated named group
156
157 // The minimal required key size in bits.
158 //
159 // Only need to check RSA algorithm at present. RSA keys of 512 bits
160 // have been shown to be practically breakable, it does not make much
161 // sense to use the strong hash algorithm for keys whose key size less
162 // than 512 bits. So it is not necessary to calculate the minimal
163 // required key size exactly for a hash algorithm.
164 //
165 // Note that some provider may use 511 bits for 512-bit strength RSA keys.
166 final int minimalKeySize;
167 final List<ProtocolVersion> supportedProtocols;
168
169 // Some signature schemes are supported in different versions for handshake
170 // messages and certificates. This field holds the supported protocols
171 // for handshake messages.
172 final List<ProtocolVersion> handshakeSupportedProtocols;
173 final boolean isAvailable;
174
175 private static final String[] hashAlgorithms = new String[] {
176 "none", "md5", "sha1", "sha224",
177 "sha256", "sha384", "sha512"
178 };
179
180 private static final String[] signatureAlgorithms = new String[] {
181 "anonymous", "rsa", "dsa", "ecdsa",
182 };
183
184 static enum SigAlgParamSpec { // support RSASSA-PSS only now
185 RSA_PSS_SHA256 ("SHA-256", 32),
186 RSA_PSS_SHA384 ("SHA-384", 48),
187 RSA_PSS_SHA512 ("SHA-512", 64);
188
189 final private AlgorithmParameterSpec parameterSpec;
190 final boolean isAvailable;
191
192 SigAlgParamSpec(String hash, int saltLength) {
193 // See RFC 8017
194 PSSParameterSpec pssParamSpec =
195 new PSSParameterSpec(hash, "MGF1",
196 new MGF1ParameterSpec(hash), saltLength, 1);
197
198 boolean mediator = true;
199 try {
200 Signature signer = JsseJce.getSignature("RSASSA-PSS");
201 signer.setParameter(pssParamSpec);
202 } catch (InvalidAlgorithmParameterException |
203 NoSuchAlgorithmException exp) {
204 mediator = false;
205 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
206 SSLLogger.warning(
207 "RSASSA-PSS signature with " + hash +
208 " is not supported by the underlying providers", exp);
209 }
210 }
211
212 this.isAvailable = mediator;
213 this.parameterSpec = mediator ? pssParamSpec : null;
214 }
215
216 AlgorithmParameterSpec getParameterSpec() {
217 return parameterSpec;
218 }
219 }
220
221 // performance optimization
222 private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
223 Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
224
225
226 private SignatureScheme(int id, String name,
227 String algorithm, String keyAlgorithm,
228 ProtocolVersion[] supportedProtocols) {
229 this(id, name, algorithm, keyAlgorithm, -1, supportedProtocols);
230 }
231
232 private SignatureScheme(int id, String name,
233 String algorithm, String keyAlgorithm,
234 int minimalKeySize,
235 ProtocolVersion[] supportedProtocols) {
236 this(id, name, algorithm, keyAlgorithm,
237 null, minimalKeySize, supportedProtocols);
240 private SignatureScheme(int id, String name,
241 String algorithm, String keyAlgorithm,
242 SigAlgParamSpec signAlgParamSpec, int minimalKeySize,
243 ProtocolVersion[] supportedProtocols) {
244 this(id, name, algorithm, keyAlgorithm,
245 signAlgParamSpec, null, minimalKeySize,
246 supportedProtocols, supportedProtocols);
247 }
248
249 private SignatureScheme(int id, String name,
250 String algorithm, String keyAlgorithm,
251 NamedGroup namedGroup,
252 ProtocolVersion[] supportedProtocols) {
253 this(id, name, algorithm, keyAlgorithm,
254 null, namedGroup, -1,
255 supportedProtocols, supportedProtocols);
256 }
257
258 private SignatureScheme(int id, String name,
259 String algorithm, String keyAlgorithm,
260 SigAlgParamSpec signAlgParamSpec,
261 NamedGroup namedGroup, int minimalKeySize,
262 ProtocolVersion[] supportedProtocols,
263 ProtocolVersion[] handshakeSupportedProtocols) {
264 this.id = id;
265 this.name = name;
266 this.algorithm = algorithm;
267 this.keyAlgorithm = keyAlgorithm;
268 this.signAlgParameter =
269 signAlgParamSpec != null ? signAlgParamSpec.parameterSpec : null;
270 this.namedGroup = namedGroup;
271 this.minimalKeySize = minimalKeySize;
272 this.supportedProtocols = Arrays.asList(supportedProtocols);
273 this.handshakeSupportedProtocols =
274 Arrays.asList(handshakeSupportedProtocols);
275
276 boolean mediator = true;
277 // An EC provider, for example the SunEC provider, may support
278 // AlgorithmParameters but not KeyPairGenerator or Signature.
279 //
280 // Note: Please be careful if removing this block!
281 if ("EC".equals(keyAlgorithm)) {
282 mediator = JsseJce.isEcAvailable();
283 }
284
285 // Check the specific algorithm and parameters.
286 if (mediator) {
287 if (signAlgParamSpec != null) {
288 mediator = signAlgParamSpec.isAvailable;
289 } else {
290 try {
291 JsseJce.getSignature(algorithm);
292 } catch (Exception e) {
293 mediator = false;
294 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
295 SSLLogger.warning(
296 "Signature algorithm, " + algorithm +
297 ", is not supported by the underlying providers");
298 }
299 }
300 }
301 }
302
303 if (mediator && ((id >> 8) & 0xFF) == 0x03) { // SHA224
304 // There are some problems to use SHA224 on Windows.
305 if (Security.getProvider("SunMSCAPI") != null) {
306 mediator = false;
307 }
308 }
338
339 return signName + "_" + hashName;
340 }
341
342 // Note: the signatureSchemeName is not case-sensitive.
343 static SignatureScheme nameOf(String signatureSchemeName) {
344 for (SignatureScheme ss: SignatureScheme.values()) {
345 if (ss.name.equalsIgnoreCase(signatureSchemeName)) {
346 return ss;
347 }
348 }
349
350 return null;
351 }
352
353 // Return the size of a SignatureScheme structure in TLS record
354 static int sizeInRecord() {
355 return 2;
356 }
357
358 // Get local supported algorithm collection complying to algorithm
359 // constraints.
360 static List<SignatureScheme> getSupportedAlgorithms(
361 SSLConfiguration config,
362 AlgorithmConstraints constraints,
363 List<ProtocolVersion> activeProtocols) {
364 List<SignatureScheme> supported = new LinkedList<>();
365 for (SignatureScheme ss: SignatureScheme.values()) {
366 if (!ss.isAvailable ||
367 (!config.signatureSchemes.isEmpty() &&
368 !config.signatureSchemes.contains(ss))) {
369 if (SSLLogger.isOn &&
370 SSLLogger.isOn("ssl,handshake,verbose")) {
371 SSLLogger.finest(
372 "Ignore unsupported signature scheme: " + ss.name);
373 }
374 continue;
375 }
376
377 boolean isMatch = false;
378 for (ProtocolVersion pv : activeProtocols) {
379 if (ss.supportedProtocols.contains(pv)) {
380 isMatch = true;
381 break;
382 }
383 }
384
385 if (isMatch) {
386 if (constraints.permits(
387 SIGNATURE_PRIMITIVE_SET, ss.algorithm, null)) {
388 supported.add(ss);
389 } else if (SSLLogger.isOn &&
390 SSLLogger.isOn("ssl,handshake,verbose")) {
391 SSLLogger.finest(
392 "Ignore disabled signature scheme: " + ss.name);
393 }
394 } else if (SSLLogger.isOn &&
395 SSLLogger.isOn("ssl,handshake,verbose")) {
396 SSLLogger.finest(
397 "Ignore inactive signature scheme: " + ss.name);
398 }
399 }
400
401 return supported;
402 }
403
404 static List<SignatureScheme> getSupportedAlgorithms(
405 SSLConfiguration config,
406 AlgorithmConstraints constraints,
407 ProtocolVersion protocolVersion, int[] algorithmIds) {
408 List<SignatureScheme> supported = new LinkedList<>();
409 for (int ssid : algorithmIds) {
410 SignatureScheme ss = SignatureScheme.valueOf(ssid);
411 if (ss == null) {
412 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
413 SSLLogger.warning(
414 "Unsupported signature scheme: " +
415 SignatureScheme.nameOf(ssid));
416 }
417 } else if (ss.isAvailable &&
418 ss.supportedProtocols.contains(protocolVersion) &&
419 (config.signatureSchemes.isEmpty() ||
420 config.signatureSchemes.contains(ss)) &&
421 constraints.permits(SIGNATURE_PRIMITIVE_SET,
422 ss.algorithm, null)) {
423 supported.add(ss);
424 } else {
425 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
426 SSLLogger.warning(
427 "Unsupported signature scheme: " + ss.name);
428 }
429 }
430 }
431
432 return supported;
433 }
434
435 static SignatureScheme getPreferableAlgorithm(
436 List<SignatureScheme> schemes,
437 SignatureScheme certScheme,
438 ProtocolVersion version) {
439
440 for (SignatureScheme ss : schemes) {
441 if (ss.isAvailable &&
442 ss.handshakeSupportedProtocols.contains(version) &&
443 certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
444
445 return ss;
446 }
447 }
448
449 return null;
450 }
451
452 static Map.Entry<SignatureScheme, Signature> getSignerOfPreferableAlgorithm(
453 List<SignatureScheme> schemes,
454 X509Possession x509Possession,
455 ProtocolVersion version) {
456
457 PrivateKey signingKey = x509Possession.popPrivateKey;
458 String keyAlgorithm = signingKey.getAlgorithm();
459 int keySize;
460 // Only need to check RSA algorithm at present.
461 if (keyAlgorithm.equalsIgnoreCase("RSA") ||
462 keyAlgorithm.equalsIgnoreCase("RSASSA-PSS")) {
463 keySize = KeyUtil.getKeySize(signingKey);
464 } else {
465 keySize = Integer.MAX_VALUE;
466 }
467 for (SignatureScheme ss : schemes) {
468 if (ss.isAvailable && (keySize >= ss.minimalKeySize) &&
469 ss.handshakeSupportedProtocols.contains(version) &&
470 keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
471 if ((ss.namedGroup != null) && (ss.namedGroup.type ==
472 NamedGroupType.NAMED_GROUP_ECDHE)) {
473 ECParameterSpec params =
474 x509Possession.getECParameterSpec();
475 if (params != null &&
476 ss.namedGroup == NamedGroup.valueOf(params)) {
477 Signature signer = ss.getSigner(signingKey);
478 if (signer != null) {
479 return new SimpleImmutableEntry<>(ss, signer);
480 }
481 }
482
483 if (SSLLogger.isOn &&
484 SSLLogger.isOn("ssl,handshake,verbose")) {
485 SSLLogger.finest(
486 "Ignore the signature algorithm (" + ss +
487 "), unsupported EC parameter spec: " + params);
488 }
489 } else if ("EC".equals(ss.keyAlgorithm)) {
490 // Must be a legacy signature algorithm, which does not
491 // specify the associated named groups. The connection
492 // cannot be established if the peer cannot recognize
535 }
536
537 return names.toArray(new String[0]);
538 }
539
540 return new String[0];
541 }
542
543 // This method is used to get the signature instance of this signature
544 // scheme for the specific public key. Unlike getSigner(), the exception
545 // is bubbled up. If the public key does not support this signature
546 // scheme, it normally means the TLS handshaking cannot continue and
547 // the connection should be terminated.
548 Signature getVerifier(PublicKey publicKey) throws NoSuchAlgorithmException,
549 InvalidAlgorithmParameterException, InvalidKeyException {
550 if (!isAvailable) {
551 return null;
552 }
553
554 Signature verifier = Signature.getInstance(algorithm);
555 SignatureUtil.initVerifyWithParam(verifier, publicKey, signAlgParameter);
556
557 return verifier;
558 }
559
560 // This method is also used to choose preferable signature scheme for the
561 // specific private key. If the private key does not support the signature
562 // scheme, {@code null} is returned, and the caller may fail back to next
563 // available signature scheme.
564 private Signature getSigner(PrivateKey privateKey) {
565 if (!isAvailable) {
566 return null;
567 }
568
569 try {
570 Signature signer = Signature.getInstance(algorithm);
571 SignatureUtil.initSignWithParam(signer, privateKey,
572 signAlgParameter,
573 null);
574 return signer;
575 } catch (NoSuchAlgorithmException | InvalidKeyException |
576 InvalidAlgorithmParameterException nsae) {
577 if (SSLLogger.isOn &&
578 SSLLogger.isOn("ssl,handshake,verbose")) {
579 SSLLogger.finest(
580 "Ignore unsupported signature algorithm (" +
581 this.name + ")", nsae);
582 }
583 }
584
585 return null;
586 }
587 }
|
23 * questions.
24 */
25
26 package sun.security.ssl;
27
28 import java.security.*;
29 import java.security.spec.AlgorithmParameterSpec;
30 import java.security.spec.ECParameterSpec;
31 import java.security.spec.MGF1ParameterSpec;
32 import java.security.spec.PSSParameterSpec;
33 import java.util.AbstractMap.SimpleImmutableEntry;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.EnumSet;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import sun.security.ssl.NamedGroup.NamedGroupSpec;
44 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
45 import sun.security.ssl.X509Authentication.X509Possession;
46 import sun.security.util.KeyUtil;
47 import sun.security.util.SignatureUtil;
48
49 enum SignatureScheme {
50 // EdDSA algorithms
51 ED25519 (0x0807, "ed25519", "ed25519",
52 "ed25519",
53 ProtocolVersion.PROTOCOLS_OF_13),
54 ED448 (0x0808, "ed448", "ed448",
55 "ed448",
56 ProtocolVersion.PROTOCOLS_OF_13),
57
58 // ECDSA algorithms
59 ECDSA_SECP256R1_SHA256 (0x0403, "ecdsa_secp256r1_sha256",
60 "SHA256withECDSA",
61 "EC",
62 NamedGroup.SECP256_R1,
63 ProtocolVersion.PROTOCOLS_TO_13),
134 "DSA",
135 ProtocolVersion.PROTOCOLS_TO_12),
136 ECDSA_SHA1 (0x0203, "ecdsa_sha1", "SHA1withECDSA",
137 "EC",
138 ProtocolVersion.PROTOCOLS_TO_13),
139 RSA_PKCS1_SHA1 (0x0201, "rsa_pkcs1_sha1", "SHA1withRSA",
140 "RSA", null, null, 511,
141 ProtocolVersion.PROTOCOLS_TO_13,
142 ProtocolVersion.PROTOCOLS_TO_12),
143 DSA_SHA1 (0x0202, "dsa_sha1", "SHA1withDSA",
144 "DSA",
145 ProtocolVersion.PROTOCOLS_TO_12),
146 RSA_MD5 (0x0101, "rsa_md5", "MD5withRSA",
147 "RSA", 511,
148 ProtocolVersion.PROTOCOLS_TO_12);
149
150 final int id; // hash + signature
151 final String name; // literal name
152 private final String algorithm; // signature algorithm
153 final String keyAlgorithm; // signature key algorithm
154 private final SigAlgParamSpec signAlgParams; // signature parameters
155 private final NamedGroup namedGroup; // associated named group
156
157 // The minimal required key size in bits.
158 //
159 // Only need to check RSA algorithm at present. RSA keys of 512 bits
160 // have been shown to be practically breakable, it does not make much
161 // sense to use the strong hash algorithm for keys whose key size less
162 // than 512 bits. So it is not necessary to calculate the minimal
163 // required key size exactly for a hash algorithm.
164 //
165 // Note that some provider may use 511 bits for 512-bit strength RSA keys.
166 final int minimalKeySize;
167 final List<ProtocolVersion> supportedProtocols;
168
169 // Some signature schemes are supported in different versions for handshake
170 // messages and certificates. This field holds the supported protocols
171 // for handshake messages.
172 final List<ProtocolVersion> handshakeSupportedProtocols;
173 final boolean isAvailable;
174
175 private static final String[] hashAlgorithms = new String[] {
176 "none", "md5", "sha1", "sha224",
177 "sha256", "sha384", "sha512"
178 };
179
180 private static final String[] signatureAlgorithms = new String[] {
181 "anonymous", "rsa", "dsa", "ecdsa",
182 };
183
184 static enum SigAlgParamSpec { // support RSASSA-PSS only now
185 RSA_PSS_SHA256 ("SHA-256", 32),
186 RSA_PSS_SHA384 ("SHA-384", 48),
187 RSA_PSS_SHA512 ("SHA-512", 64);
188
189 private final AlgorithmParameterSpec parameterSpec;
190 private final AlgorithmParameters parameters;
191 private final boolean isAvailable;
192
193 SigAlgParamSpec(String hash, int saltLength) {
194 // See RFC 8017
195 PSSParameterSpec pssParamSpec =
196 new PSSParameterSpec(hash, "MGF1",
197 new MGF1ParameterSpec(hash), saltLength, 1);
198 AlgorithmParameters pssParams = null;
199
200 boolean mediator = true;
201 try {
202 Signature signer = JsseJce.getSignature("RSASSA-PSS");
203 signer.setParameter(pssParamSpec);
204 pssParams = signer.getParameters();
205 } catch (InvalidAlgorithmParameterException |
206 NoSuchAlgorithmException | RuntimeException exp) {
207 // Signature.getParameters() may throw RuntimeException.
208 mediator = false;
209 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
210 SSLLogger.warning(
211 "RSASSA-PSS signature with " + hash +
212 " is not supported by the underlying providers", exp);
213 }
214 }
215
216 this.isAvailable = mediator;
217 this.parameterSpec = mediator ? pssParamSpec : null;
218 this.parameters = mediator ? pssParams : null;
219 }
220 }
221
222 // performance optimization
223 private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
224 Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
225
226
227 private SignatureScheme(int id, String name,
228 String algorithm, String keyAlgorithm,
229 ProtocolVersion[] supportedProtocols) {
230 this(id, name, algorithm, keyAlgorithm, -1, supportedProtocols);
231 }
232
233 private SignatureScheme(int id, String name,
234 String algorithm, String keyAlgorithm,
235 int minimalKeySize,
236 ProtocolVersion[] supportedProtocols) {
237 this(id, name, algorithm, keyAlgorithm,
238 null, minimalKeySize, supportedProtocols);
241 private SignatureScheme(int id, String name,
242 String algorithm, String keyAlgorithm,
243 SigAlgParamSpec signAlgParamSpec, int minimalKeySize,
244 ProtocolVersion[] supportedProtocols) {
245 this(id, name, algorithm, keyAlgorithm,
246 signAlgParamSpec, null, minimalKeySize,
247 supportedProtocols, supportedProtocols);
248 }
249
250 private SignatureScheme(int id, String name,
251 String algorithm, String keyAlgorithm,
252 NamedGroup namedGroup,
253 ProtocolVersion[] supportedProtocols) {
254 this(id, name, algorithm, keyAlgorithm,
255 null, namedGroup, -1,
256 supportedProtocols, supportedProtocols);
257 }
258
259 private SignatureScheme(int id, String name,
260 String algorithm, String keyAlgorithm,
261 SigAlgParamSpec signAlgParams,
262 NamedGroup namedGroup, int minimalKeySize,
263 ProtocolVersion[] supportedProtocols,
264 ProtocolVersion[] handshakeSupportedProtocols) {
265 this.id = id;
266 this.name = name;
267 this.algorithm = algorithm;
268 this.keyAlgorithm = keyAlgorithm;
269 this.signAlgParams = signAlgParams;
270 this.namedGroup = namedGroup;
271 this.minimalKeySize = minimalKeySize;
272 this.supportedProtocols = Arrays.asList(supportedProtocols);
273 this.handshakeSupportedProtocols =
274 Arrays.asList(handshakeSupportedProtocols);
275
276 boolean mediator = true;
277 // An EC provider, for example the SunEC provider, may support
278 // AlgorithmParameters but not KeyPairGenerator or Signature.
279 //
280 // Note: Please be careful if removing this block!
281 if ("EC".equals(keyAlgorithm)) {
282 mediator = JsseJce.isEcAvailable();
283 }
284
285 // Check the specific algorithm and parameters.
286 if (mediator) {
287 if (signAlgParams != null) {
288 mediator = signAlgParams.isAvailable;
289 } else {
290 try {
291 JsseJce.getSignature(algorithm);
292 } catch (Exception e) {
293 mediator = false;
294 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
295 SSLLogger.warning(
296 "Signature algorithm, " + algorithm +
297 ", is not supported by the underlying providers");
298 }
299 }
300 }
301 }
302
303 if (mediator && ((id >> 8) & 0xFF) == 0x03) { // SHA224
304 // There are some problems to use SHA224 on Windows.
305 if (Security.getProvider("SunMSCAPI") != null) {
306 mediator = false;
307 }
308 }
338
339 return signName + "_" + hashName;
340 }
341
342 // Note: the signatureSchemeName is not case-sensitive.
343 static SignatureScheme nameOf(String signatureSchemeName) {
344 for (SignatureScheme ss: SignatureScheme.values()) {
345 if (ss.name.equalsIgnoreCase(signatureSchemeName)) {
346 return ss;
347 }
348 }
349
350 return null;
351 }
352
353 // Return the size of a SignatureScheme structure in TLS record
354 static int sizeInRecord() {
355 return 2;
356 }
357
358 private boolean isPermitted(AlgorithmConstraints constraints) {
359 return constraints.permits(SIGNATURE_PRIMITIVE_SET,
360 this.name, null) &&
361 constraints.permits(SIGNATURE_PRIMITIVE_SET,
362 this.keyAlgorithm, null) &&
363 constraints.permits(SIGNATURE_PRIMITIVE_SET,
364 this.algorithm, (signAlgParams != null ?
365 signAlgParams.parameters : null)) &&
366 (namedGroup != null ?
367 namedGroup.isPermitted(constraints) : true);
368 }
369
370 // Get local supported algorithm collection complying to algorithm
371 // constraints.
372 static List<SignatureScheme> getSupportedAlgorithms(
373 SSLConfiguration config,
374 AlgorithmConstraints constraints,
375 List<ProtocolVersion> activeProtocols) {
376 List<SignatureScheme> supported = new LinkedList<>();
377 for (SignatureScheme ss: SignatureScheme.values()) {
378 if (!ss.isAvailable ||
379 (!config.signatureSchemes.isEmpty() &&
380 !config.signatureSchemes.contains(ss))) {
381 if (SSLLogger.isOn &&
382 SSLLogger.isOn("ssl,handshake,verbose")) {
383 SSLLogger.finest(
384 "Ignore unsupported signature scheme: " + ss.name);
385 }
386 continue;
387 }
388
389 boolean isMatch = false;
390 for (ProtocolVersion pv : activeProtocols) {
391 if (ss.supportedProtocols.contains(pv)) {
392 isMatch = true;
393 break;
394 }
395 }
396
397 if (isMatch) {
398 if (ss.isPermitted(constraints)) {
399 supported.add(ss);
400 } else if (SSLLogger.isOn &&
401 SSLLogger.isOn("ssl,handshake,verbose")) {
402 SSLLogger.finest(
403 "Ignore disabled signature scheme: " + ss.name);
404 }
405 } else if (SSLLogger.isOn &&
406 SSLLogger.isOn("ssl,handshake,verbose")) {
407 SSLLogger.finest(
408 "Ignore inactive signature scheme: " + ss.name);
409 }
410 }
411
412 return supported;
413 }
414
415 static List<SignatureScheme> getSupportedAlgorithms(
416 SSLConfiguration config,
417 AlgorithmConstraints constraints,
418 ProtocolVersion protocolVersion, int[] algorithmIds) {
419 List<SignatureScheme> supported = new LinkedList<>();
420 for (int ssid : algorithmIds) {
421 SignatureScheme ss = SignatureScheme.valueOf(ssid);
422 if (ss == null) {
423 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
424 SSLLogger.warning(
425 "Unsupported signature scheme: " +
426 SignatureScheme.nameOf(ssid));
427 }
428 } else if (ss.isAvailable &&
429 ss.supportedProtocols.contains(protocolVersion) &&
430 (config.signatureSchemes.isEmpty() ||
431 config.signatureSchemes.contains(ss)) &&
432 ss.isPermitted(constraints)) {
433 supported.add(ss);
434 } else {
435 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
436 SSLLogger.warning(
437 "Unsupported signature scheme: " + ss.name);
438 }
439 }
440 }
441
442 return supported;
443 }
444
445 static SignatureScheme getPreferableAlgorithm(
446 AlgorithmConstraints constraints,
447 List<SignatureScheme> schemes,
448 SignatureScheme certScheme,
449 ProtocolVersion version) {
450
451 for (SignatureScheme ss : schemes) {
452 if (ss.isAvailable &&
453 ss.handshakeSupportedProtocols.contains(version) &&
454 certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) &&
455 ss.isPermitted(constraints)) {
456 return ss;
457 }
458 }
459
460 return null;
461 }
462
463 static Map.Entry<SignatureScheme, Signature> getSignerOfPreferableAlgorithm(
464 AlgorithmConstraints constraints,
465 List<SignatureScheme> schemes,
466 X509Possession x509Possession,
467 ProtocolVersion version) {
468
469 PrivateKey signingKey = x509Possession.popPrivateKey;
470 String keyAlgorithm = signingKey.getAlgorithm();
471 int keySize;
472 // Only need to check RSA algorithm at present.
473 if (keyAlgorithm.equalsIgnoreCase("RSA") ||
474 keyAlgorithm.equalsIgnoreCase("RSASSA-PSS")) {
475 keySize = KeyUtil.getKeySize(signingKey);
476 } else {
477 keySize = Integer.MAX_VALUE;
478 }
479 for (SignatureScheme ss : schemes) {
480 if (ss.isAvailable && (keySize >= ss.minimalKeySize) &&
481 ss.handshakeSupportedProtocols.contains(version) &&
482 keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) &&
483 ss.isPermitted(constraints)) {
484 if ((ss.namedGroup != null) && (ss.namedGroup.spec ==
485 NamedGroupSpec.NAMED_GROUP_ECDHE)) {
486 ECParameterSpec params =
487 x509Possession.getECParameterSpec();
488 if (params != null &&
489 ss.namedGroup == NamedGroup.valueOf(params)) {
490 Signature signer = ss.getSigner(signingKey);
491 if (signer != null) {
492 return new SimpleImmutableEntry<>(ss, signer);
493 }
494 }
495
496 if (SSLLogger.isOn &&
497 SSLLogger.isOn("ssl,handshake,verbose")) {
498 SSLLogger.finest(
499 "Ignore the signature algorithm (" + ss +
500 "), unsupported EC parameter spec: " + params);
501 }
502 } else if ("EC".equals(ss.keyAlgorithm)) {
503 // Must be a legacy signature algorithm, which does not
504 // specify the associated named groups. The connection
505 // cannot be established if the peer cannot recognize
548 }
549
550 return names.toArray(new String[0]);
551 }
552
553 return new String[0];
554 }
555
556 // This method is used to get the signature instance of this signature
557 // scheme for the specific public key. Unlike getSigner(), the exception
558 // is bubbled up. If the public key does not support this signature
559 // scheme, it normally means the TLS handshaking cannot continue and
560 // the connection should be terminated.
561 Signature getVerifier(PublicKey publicKey) throws NoSuchAlgorithmException,
562 InvalidAlgorithmParameterException, InvalidKeyException {
563 if (!isAvailable) {
564 return null;
565 }
566
567 Signature verifier = Signature.getInstance(algorithm);
568 SignatureUtil.initVerifyWithParam(verifier, publicKey,
569 (signAlgParams != null ?
570 signAlgParams.parameterSpec : null));
571
572 return verifier;
573 }
574
575 // This method is also used to choose preferable signature scheme for the
576 // specific private key. If the private key does not support the signature
577 // scheme, {@code null} is returned, and the caller may fail back to next
578 // available signature scheme.
579 private Signature getSigner(PrivateKey privateKey) {
580 if (!isAvailable) {
581 return null;
582 }
583
584 try {
585 Signature signer = Signature.getInstance(algorithm);
586 SignatureUtil.initSignWithParam(signer, privateKey,
587 (signAlgParams != null ?
588 signAlgParams.parameterSpec : null),
589 null);
590 return signer;
591 } catch (NoSuchAlgorithmException | InvalidKeyException |
592 InvalidAlgorithmParameterException nsae) {
593 if (SSLLogger.isOn &&
594 SSLLogger.isOn("ssl,handshake,verbose")) {
595 SSLLogger.finest(
596 "Ignore unsupported signature algorithm (" +
597 this.name + ")", nsae);
598 }
599 }
600
601 return null;
602 }
603 }
|