This commit is contained in:
Phil Race 2018-09-24 10:59:26 -07:00
commit f605407e30
1110 changed files with 30242 additions and 8878 deletions

View file

@ -25,6 +25,11 @@
package java.lang;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
/**
* Thrown when an application tries to load in a class through its
* string name using:
@ -56,15 +61,6 @@ public class ClassNotFoundException extends ReflectiveOperationException {
*/
private static final long serialVersionUID = 9176873029745254542L;
/**
* This field holds the exception ex if the
* ClassNotFoundException(String s, Throwable ex) constructor was
* used to instantiate the object
* @serial
* @since 1.2
*/
private Throwable ex;
/**
* Constructs a <code>ClassNotFoundException</code> with no detail message.
*/
@ -92,8 +88,7 @@ public class ClassNotFoundException extends ReflectiveOperationException {
* @since 1.2
*/
public ClassNotFoundException(String s, Throwable ex) {
super(s, null); // Disallow initCause
this.ex = ex;
super(s, ex); // Disallow initCause
}
/**
@ -108,18 +103,42 @@ public class ClassNotFoundException extends ReflectiveOperationException {
* @since 1.2
*/
public Throwable getException() {
return ex;
return super.getCause();
}
/**
* Returns the cause of this exception (the exception that was raised
* if an error occurred while attempting to load the class; otherwise
* {@code null}).
* Serializable fields for ClassNotFoundException.
*
* @return the cause of this exception.
* @since 1.4
* @serialField ex Throwable
*/
public Throwable getCause() {
return ex;
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("ex", Throwable.class)
};
/*
* Reconstitutes the ClassNotFoundException instance from a stream
* and initialize the cause properly when deserializing from an older
* version.
*
* The getException and getCause method returns the private "ex" field
* in the older implementation and ClassNotFoundException::cause
* was set to null.
*/
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = s.readFields();
Throwable exception = (Throwable) fields.get("ex", null);
if (exception != null) {
setCause(exception);
}
}
/*
* To maintain compatibility with older implementation, write a serial
* "ex" field with the cause as the value.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
ObjectOutputStream.PutField fields = out.putFields();
fields.put("ex", super.getCause());
out.writeFields();
}
}

View file

@ -25,6 +25,11 @@
package java.lang;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
/**
* Signals that an unexpected exception has occurred in a static initializer.
* An <code>ExceptionInInitializerError</code> is thrown to indicate that an
@ -47,16 +52,6 @@ public class ExceptionInInitializerError extends LinkageError {
*/
private static final long serialVersionUID = 1521711792217232256L;
/**
* This field holds the exception if the
* ExceptionInInitializerError(Throwable thrown) constructor was
* used to instantiate the object
*
* @serial
*
*/
private Throwable exception;
/**
* Constructs an <code>ExceptionInInitializerError</code> with
* <code>null</code> as its detail message string and with no saved
@ -64,7 +59,7 @@ public class ExceptionInInitializerError extends LinkageError {
* A detail message is a String that describes this particular exception.
*/
public ExceptionInInitializerError() {
initCause(null); // Disallow subsequent initCause
initCause(null); // Disallow subsequent initCause
}
/**
@ -76,23 +71,20 @@ public class ExceptionInInitializerError extends LinkageError {
* @param thrown The exception thrown
*/
public ExceptionInInitializerError(Throwable thrown) {
initCause(null); // Disallow subsequent initCause
this.exception = thrown;
super(null, thrown); // Disallow subsequent initCause
}
/**
* Constructs an ExceptionInInitializerError with the specified detail
* Constructs an {@code ExceptionInInitializerError} with the specified detail
* message string. A detail message is a String that describes this
* particular exception. The detail message string is saved for later
* retrieval by the {@link Throwable#getMessage()} method. There is no
* saved throwable object.
*
*
* @param s the detail message
*/
public ExceptionInInitializerError(String s) {
super(s);
initCause(null); // Disallow subsequent initCause
super(s, null); // Disallow subsequent initCause
}
/**
@ -109,18 +101,43 @@ public class ExceptionInInitializerError extends LinkageError {
* throwable object.
*/
public Throwable getException() {
return exception;
return super.getCause();
}
/**
* Returns the cause of this error (the exception that occurred
* during a static initialization that caused this error to be created).
* Serializable fields for ExceptionInInitializerError.
*
* @return the cause of this error or <code>null</code> if the
* cause is nonexistent or unknown.
* @since 1.4
* @serialField exception Throwable
*/
public Throwable getCause() {
return exception;
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("exception", Throwable.class)
};
/*
* Reconstitutes the ExceptionInInitializerError instance from a stream
* and initialize the cause properly when deserializing from an older
* version.
*
* The getException and getCause method returns the private "exception"
* field in the older implementation and ExceptionInInitializerError::cause
* was set to null.
*/
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = s.readFields();
Throwable exception = (Throwable) fields.get("exception", null);
if (exception != null) {
setCause(exception);
}
}
/*
* To maintain compatibility with older implementation, write a serial
* "exception" field with the cause as the value.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
ObjectOutputStream.PutField fields = out.putFields();
fields.put("exception", super.getCause());
out.writeFields();
}
}

View file

@ -2201,6 +2201,9 @@ public final class System {
return StringCoding.getBytesUTF8NoRepl(s);
}
public void setCause(Throwable t, Throwable cause) {
t.setCause(cause);
}
});
}
}

View file

@ -466,6 +466,16 @@ public class Throwable implements Serializable {
return this;
}
/*
* This is called by readObject of a few exceptions such as
* ClassNotFoundException and ExceptionInInitializerError to deserialize
* a stream output from an older runtime version where the cause may
* have set to null.
*/
final void setCause(Throwable t) {
this.cause = t;
}
/**
* Returns a short description of this throwable.
* The result is the concatenation of:

View file

@ -54,6 +54,7 @@ import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -643,6 +644,10 @@ public class MethodHandles {
/** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
private final int allowedModes;
static {
Reflection.registerFieldsToFilter(Lookup.class, Set.of("lookupClass", "allowedModes"));
}
/** A single-bit mask representing {@code public} access,
* which may contribute to the result of {@link #lookupModes lookupModes}.
* The value, {@code 0x01}, happens to be the same as the value of the

View file

@ -25,6 +25,12 @@
package java.lang.reflect;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import jdk.internal.misc.SharedSecrets;
/**
* Thrown by a method invocation on a proxy instance if its invocation
* handler's {@link InvocationHandler#invoke invoke} method throws a
@ -58,12 +64,6 @@ package java.lang.reflect;
public class UndeclaredThrowableException extends RuntimeException {
static final long serialVersionUID = 330127114055056639L;
/**
* the undeclared checked exception that was thrown
* @serial
*/
private Throwable undeclaredThrowable;
/**
* Constructs an {@code UndeclaredThrowableException} with the
* specified {@code Throwable}.
@ -72,8 +72,7 @@ public class UndeclaredThrowableException extends RuntimeException {
* that was thrown
*/
public UndeclaredThrowableException(Throwable undeclaredThrowable) {
super((Throwable) null); // Disallow initCause
this.undeclaredThrowable = undeclaredThrowable;
super(null, undeclaredThrowable); // Disallow initCause
}
/**
@ -87,8 +86,7 @@ public class UndeclaredThrowableException extends RuntimeException {
public UndeclaredThrowableException(Throwable undeclaredThrowable,
String s)
{
super(s, null); // Disallow initCause
this.undeclaredThrowable = undeclaredThrowable;
super(s, undeclaredThrowable); // Disallow initCause
}
/**
@ -102,18 +100,38 @@ public class UndeclaredThrowableException extends RuntimeException {
* @return the undeclared checked exception that was thrown
*/
public Throwable getUndeclaredThrowable() {
return undeclaredThrowable;
return super.getCause();
}
/**
* Returns the cause of this exception (the {@code Throwable}
* instance wrapped in this {@code UndeclaredThrowableException},
* which may be {@code null}).
* Serializable fields for UndeclaredThrowableException.
*
* @return the cause of this exception.
* @since 1.4
* @serialField undeclaredThrowable Throwable
*/
public Throwable getCause() {
return undeclaredThrowable;
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("undeclaredThrowable", Throwable.class)
};
/*
* Reconstitutes the UndeclaredThrowableException instance from a stream
* and initialize the cause properly when deserializing from an older
* version.
*/
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = s.readFields();
Throwable exception = (Throwable) fields.get("undeclaredThrowable", null);
if (exception != null) {
SharedSecrets.getJavaLangAccess().setCause(this, exception);
}
}
/*
* To maintain compatibility with older implementation, write a serial
* "ex" field with the cause as the value.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
ObjectOutputStream.PutField fields = out.putFields();
fields.put("undeclaredThrowable", super.getCause());
out.writeFields();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2018, 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
@ -93,7 +93,7 @@
* <p> The {@link java.nio.file.attribute.DosFileAttributeView}
* class extends {@code BasicFileAttributeView} by defining methods to
* access the legacy "DOS" file attributes supported on file systems such as File
* Allocation Tabl (FAT), commonly used in consumer devices.
* Allocation Table (FAT), commonly used in consumer devices.
*
* <p> The {@link java.nio.file.attribute.AclFileAttributeView}
* class defines methods to read and write the Access Control List (ACL)

View file

@ -25,6 +25,12 @@
package java.security;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import jdk.internal.misc.SharedSecrets;
/**
* This exception is thrown by
* {@code doPrivileged(PrivilegedExceptionAction)} and
@ -52,11 +58,6 @@ public class PrivilegedActionException extends Exception {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 4724086851538908602L;
/**
* @serial
*/
private Exception exception;
/**
* Constructs a new PrivilegedActionException &quot;wrapping&quot;
* the specific Exception.
@ -64,8 +65,7 @@ public class PrivilegedActionException extends Exception {
* @param exception The exception thrown
*/
public PrivilegedActionException(Exception exception) {
super((Throwable)null); // Disallow initCause
this.exception = exception;
super(null, exception); // Disallow initCause
}
/**
@ -84,23 +84,49 @@ public class PrivilegedActionException extends Exception {
* AccessControlContext)
*/
public Exception getException() {
return exception;
}
/**
* Returns the cause of this exception (the exception thrown by
* the privileged computation that resulted in this
* {@code PrivilegedActionException}).
*
* @return the cause of this exception.
* @since 1.4
*/
public Throwable getCause() {
return exception;
return (Exception)super.getCause();
}
public String toString() {
String s = getClass().getName();
return (exception != null) ? (s + ": " + exception.toString()) : s;
Throwable cause = super.getCause();
return (cause != null) ? (s + ": " + cause.toString()) : s;
}
/**
* Serializable fields for UndeclaredThrowableException.
*
* @serialField undeclaredThrowable Throwable
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("exception", Exception.class)
};
/*
* Reconstitutes the PrivilegedActionException instance from a stream
* and initialize the cause properly when deserializing from an older
* version.
*
* The getException and getCause method returns the private "exception"
* field in the older implementation and PrivilegedActionException::cause
* was set to null.
*/
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = s.readFields();
Exception exception = (Exception) fields.get("exception", null);
if (exception != null) {
SharedSecrets.getJavaLangAccess().setCause(this, exception);
}
}
/*
* To maintain compatibility with older implementation, write a serial
* "exception" field with the cause as the value.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
ObjectOutputStream.PutField fields = out.putFields();
fields.put("exception", super.getCause());
out.writeFields();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2018, 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
@ -112,7 +112,7 @@ public abstract class SSLServerSocketFactory extends ServerSocketFactory
try {
return SSLContext.getDefault().getServerSocketFactory();
} catch (NoSuchAlgorithmException e) {
} catch (NoSuchAlgorithmException | UnsupportedOperationException e) {
return new DefaultSSLServerSocketFactory(e);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2018, 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
@ -121,7 +121,7 @@ public abstract class SSLSocketFactory extends SocketFactory
try {
return SSLContext.getDefault().getSocketFactory();
} catch (NoSuchAlgorithmException e) {
} catch (NoSuchAlgorithmException | UnsupportedOperationException e) {
return new DefaultSSLSocketFactory(e);
}
}

View file

@ -305,4 +305,10 @@ public interface JavaLangAccess {
* @throws IllegalArgumentException for malformed surrogates
*/
byte[] getBytesUTF8NoRepl(String s);
/**
* Set the cause of Throwable
* @param cause set t's cause to new value
*/
void setCause(Throwable t, Throwable cause);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2018, 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
@ -26,6 +26,7 @@
package jdk.internal.reflect;
import java.lang.reflect.*;
import java.util.Set;
/** Provides reflective access to the constant pools of classes.
Currently this is needed to provide reflective access to annotations
@ -104,7 +105,7 @@ public class ConstantPool {
//
static {
Reflection.registerFieldsToFilter(ConstantPool.class, new String[] { "constantPoolOop" });
Reflection.registerFieldsToFilter(ConstantPool.class, Set.of("constantPoolOop"));
}
// HotSpot-internal constant pool object (set by the VM, name known to the VM)

View file

@ -25,13 +25,12 @@
package jdk.internal.reflect;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.loader.ClassLoaders;
import jdk.internal.misc.VM;
/** Common utility routines used by both java.lang and
@ -43,18 +42,23 @@ public class Reflection {
view, where they are sensitive or they may contain VM-internal objects.
These Maps are updated very rarely. Rather than synchronize on
each access, we use copy-on-write */
private static volatile Map<Class<?>,String[]> fieldFilterMap;
private static volatile Map<Class<?>,String[]> methodFilterMap;
private static volatile Map<Class<?>, Set<String>> fieldFilterMap;
private static volatile Map<Class<?>, Set<String>> methodFilterMap;
private static final String WILDCARD = "*";
public static final Set<String> ALL_MEMBERS = Set.of(WILDCARD);
static {
Map<Class<?>,String[]> map = new HashMap<Class<?>,String[]>();
map.put(Reflection.class,
new String[] {"fieldFilterMap", "methodFilterMap"});
map.put(System.class, new String[] {"security"});
map.put(Class.class, new String[] {"classLoader"});
fieldFilterMap = map;
methodFilterMap = new HashMap<>();
fieldFilterMap = Map.of(
Reflection.class, ALL_MEMBERS,
AccessibleObject.class, ALL_MEMBERS,
Class.class, Set.of("classLoader"),
ClassLoader.class, ALL_MEMBERS,
Constructor.class, ALL_MEMBERS,
Field.class, ALL_MEMBERS,
Method.class, ALL_MEMBERS,
System.class, Set.of("security")
);
methodFilterMap = Map.of();
}
/** Returns the class of the caller of the method calling this method,
@ -236,31 +240,31 @@ public class Reflection {
// fieldNames must contain only interned Strings
public static synchronized void registerFieldsToFilter(Class<?> containingClass,
String ... fieldNames) {
Set<String> fieldNames) {
fieldFilterMap =
registerFilter(fieldFilterMap, containingClass, fieldNames);
}
// methodNames must contain only interned Strings
public static synchronized void registerMethodsToFilter(Class<?> containingClass,
String ... methodNames) {
Set<String> methodNames) {
methodFilterMap =
registerFilter(methodFilterMap, containingClass, methodNames);
}
private static Map<Class<?>,String[]> registerFilter(Map<Class<?>,String[]> map,
Class<?> containingClass, String ... names) {
private static Map<Class<?>, Set<String>> registerFilter(Map<Class<?>, Set<String>> map,
Class<?> containingClass,
Set<String> names) {
if (map.get(containingClass) != null) {
throw new IllegalArgumentException
("Filter already registered: " + containingClass);
}
map = new HashMap<Class<?>,String[]>(map);
map.put(containingClass, names);
map = new HashMap<>(map);
map.put(containingClass, Set.copyOf(names));
return map;
}
public static Field[] filterFields(Class<?> containingClass,
Field[] fields) {
public static Field[] filterFields(Class<?> containingClass, Field[] fields) {
if (fieldFilterMap == null) {
// Bootstrapping
return fields;
@ -276,35 +280,24 @@ public class Reflection {
return (Method[])filter(methods, methodFilterMap.get(containingClass));
}
private static Member[] filter(Member[] members, String[] filteredNames) {
private static Member[] filter(Member[] members, Set<String> filteredNames) {
if ((filteredNames == null) || (members.length == 0)) {
return members;
}
Class<?> memberType = members[0].getClass();
if (filteredNames.contains(WILDCARD)) {
return (Member[]) Array.newInstance(memberType, 0);
}
int numNewMembers = 0;
for (Member member : members) {
boolean shouldSkip = false;
for (String filteredName : filteredNames) {
if (member.getName() == filteredName) {
shouldSkip = true;
break;
}
}
if (!shouldSkip) {
if (!filteredNames.contains(member.getName())) {
++numNewMembers;
}
}
Member[] newMembers =
(Member[])Array.newInstance(members[0].getClass(), numNewMembers);
Member[] newMembers = (Member[])Array.newInstance(memberType, numNewMembers);
int destIdx = 0;
for (Member member : members) {
boolean shouldSkip = false;
for (String filteredName : filteredNames) {
if (member.getName() == filteredName) {
shouldSkip = true;
break;
}
}
if (!shouldSkip) {
if (!filteredNames.contains(member.getName())) {
newMembers[destIdx++] = member;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2018, 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
@ -28,6 +28,8 @@ package jdk.internal.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.util.Set;
import jdk.internal.misc.Unsafe;
/** Base class for jdk.internal.misc.Unsafe-based FieldAccessors for static
@ -40,7 +42,7 @@ import jdk.internal.misc.Unsafe;
abstract class UnsafeStaticFieldAccessorImpl extends UnsafeFieldAccessorImpl {
static {
Reflection.registerFieldsToFilter(UnsafeStaticFieldAccessorImpl.class,
new String[] { "base" });
Set.of("base"));
}
protected final Object base; // base

View file

@ -70,6 +70,9 @@ enum CipherSuite {
TLS_AES_256_GCM_SHA384(
0x1302, true, "TLS_AES_256_GCM_SHA384",
ProtocolVersion.PROTOCOLS_OF_13, B_AES_256_GCM_IV, H_SHA384),
TLS_CHACHA20_POLY1305_SHA256(
0x1303, true, "TLS_CHACHA20_POLY1305_SHA256",
ProtocolVersion.PROTOCOLS_OF_13, B_CC20_P1305, H_SHA256),
// Suite B compliant cipher suites, see RFC 6460.
//
@ -87,11 +90,22 @@ enum CipherSuite {
ProtocolVersion.PROTOCOLS_OF_12,
K_ECDHE_ECDSA, B_AES_128_GCM, M_NULL, H_SHA256),
// Not suite B, but we want it to position the suite early in the list
// of 1.2 suites.
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256(
0xCCA9, true, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "",
ProtocolVersion.PROTOCOLS_OF_12,
K_ECDHE_ECDSA, B_CC20_P1305, M_NULL, H_SHA256),
// AES_256(GCM)
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(
0xC030, true, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "",
ProtocolVersion.PROTOCOLS_OF_12,
K_ECDHE_RSA, B_AES_256_GCM, M_NULL, H_SHA384),
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256(
0xCCA8, true, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "",
ProtocolVersion.PROTOCOLS_OF_12,
K_ECDHE_RSA, B_CC20_P1305, M_NULL, H_SHA256),
TLS_RSA_WITH_AES_256_GCM_SHA384(
0x009D, true, "TLS_RSA_WITH_AES_256_GCM_SHA384", "",
ProtocolVersion.PROTOCOLS_OF_12,
@ -108,6 +122,10 @@ enum CipherSuite {
0x009F, true, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "",
ProtocolVersion.PROTOCOLS_OF_12,
K_DHE_RSA, B_AES_256_GCM, M_NULL, H_SHA384),
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256(
0xCCAA, true, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "",
ProtocolVersion.PROTOCOLS_OF_12,
K_DHE_RSA, B_CC20_P1305, M_NULL, H_SHA256),
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(
0x00A3, true, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "",
ProtocolVersion.PROTOCOLS_OF_12,
@ -480,8 +498,6 @@ enum CipherSuite {
// Definition of the CipherSuites that are not supported but the names
// are known.
TLS_CHACHA20_POLY1305_SHA256( // TLS 1.3
"TLS_CHACHA20_POLY1305_SHA256", 0x1303),
TLS_AES_128_CCM_SHA256( // TLS 1.3
"TLS_AES_128_CCM_SHA256", 0x1304),
TLS_AES_128_CCM_8_SHA256( // TLS 1.3

View file

@ -129,6 +129,11 @@ final class JsseJce {
*/
static final String CIPHER_AES_GCM = "AES/GCM/NoPadding";
/**
* JCE transformation string for ChaCha20-Poly1305
*/
static final String CIPHER_CHACHA20_POLY1305 = "ChaCha20-Poly1305";
/**
* JCA identifier string for DSA, i.e. a DSA with SHA-1.
*/

View file

@ -329,6 +329,32 @@ enum SSLCipher {
new T13GcmWriteCipherGenerator(),
ProtocolVersion.PROTOCOLS_OF_13
)
})),
@SuppressWarnings({"unchecked", "rawtypes"})
B_CC20_P1305(CIPHER_CHACHA20_POLY1305, AEAD_CIPHER, 32, 32, 12,
12, true, false,
(Map.Entry<ReadCipherGenerator,
ProtocolVersion[]>[])(new Map.Entry[] {
new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
new T12CC20P1305ReadCipherGenerator(),
ProtocolVersion.PROTOCOLS_OF_12
),
new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
new T13CC20P1305ReadCipherGenerator(),
ProtocolVersion.PROTOCOLS_OF_13
)
}),
(Map.Entry<WriteCipherGenerator,
ProtocolVersion[]>[])(new Map.Entry[] {
new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
new T12CC20P1305WriteCipherGenerator(),
ProtocolVersion.PROTOCOLS_OF_12
),
new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
new T13CC20P1305WriteCipherGenerator(),
ProtocolVersion.PROTOCOLS_OF_13
)
}));
// descriptive name including key size, e.g. AES/128
@ -2082,6 +2108,549 @@ enum SSLCipher {
}
}
private static final class T12CC20P1305ReadCipherGenerator
implements ReadCipherGenerator {
@Override
public SSLReadCipher createCipher(SSLCipher sslCipher,
Authenticator authenticator, ProtocolVersion protocolVersion,
String algorithm, Key key, AlgorithmParameterSpec params,
SecureRandom random) throws GeneralSecurityException {
return new CC20P1305ReadCipher(authenticator, protocolVersion,
sslCipher, algorithm, key, params, random);
}
static final class CC20P1305ReadCipher extends SSLReadCipher {
private final Cipher cipher;
private final int tagSize;
private final Key key;
private final byte[] iv;
private final SecureRandom random;
CC20P1305ReadCipher(Authenticator authenticator,
ProtocolVersion protocolVersion,
SSLCipher sslCipher, String algorithm,
Key key, AlgorithmParameterSpec params,
SecureRandom random) throws GeneralSecurityException {
super(authenticator, protocolVersion);
this.cipher = JsseJce.getCipher(algorithm);
this.tagSize = sslCipher.tagSize;
this.key = key;
this.iv = ((IvParameterSpec)params).getIV();
this.random = random;
// DON'T initialize the cipher for AEAD!
}
@Override
public Plaintext decrypt(byte contentType, ByteBuffer bb,
byte[] sequence) throws GeneralSecurityException {
if (bb.remaining() <= tagSize) {
throw new BadPaddingException(
"Insufficient buffer remaining for AEAD cipher " +
"fragment (" + bb.remaining() + "). Needs to be " +
"more than tag size (" + tagSize + ")");
}
byte[] sn = sequence;
if (sn == null) {
sn = authenticator.sequenceNumber();
}
byte[] nonce = new byte[iv.length];
System.arraycopy(sn, 0, nonce, nonce.length - sn.length,
sn.length);
for (int i = 0; i < nonce.length; i++) {
nonce[i] ^= iv[i];
}
// initialize the AEAD cipher with the unique IV
AlgorithmParameterSpec spec = new IvParameterSpec(nonce);
try {
cipher.init(Cipher.DECRYPT_MODE, key, spec, random);
} catch (InvalidKeyException |
InvalidAlgorithmParameterException ikae) {
// unlikely to happen
throw new RuntimeException(
"invalid key or spec in AEAD mode", ikae);
}
// update the additional authentication data
byte[] aad = authenticator.acquireAuthenticationBytes(
contentType, bb.remaining() - tagSize, sequence);
cipher.updateAAD(aad);
// DON'T decrypt the nonce_explicit for AEAD mode. The buffer
// position has moved out of the nonce_explicit range.
int len = bb.remaining();
int pos = bb.position();
ByteBuffer dup = bb.duplicate();
try {
len = cipher.doFinal(dup, bb);
} catch (IllegalBlockSizeException ibse) {
// unlikely to happen
throw new RuntimeException(
"Cipher error in AEAD mode \"" + ibse.getMessage() +
" \"in JCE provider " + cipher.getProvider().getName());
} catch (ShortBufferException sbe) {
// catch BouncyCastle buffering error
throw new RuntimeException("Cipher buffering error in " +
"JCE provider " + cipher.getProvider().getName(), sbe);
}
// reset the limit to the end of the decrypted data
bb.position(pos);
bb.limit(pos + len);
if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
SSLLogger.fine(
"Plaintext after DECRYPTION", bb.duplicate());
}
return new Plaintext(contentType,
ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
-1, -1L, bb.slice());
}
@Override
void dispose() {
if (cipher != null) {
try {
cipher.doFinal();
} catch (Exception e) {
// swallow all types of exceptions.
}
}
}
@Override
int estimateFragmentSize(int packetSize, int headerSize) {
return packetSize - headerSize - tagSize;
}
}
}
private static final class T12CC20P1305WriteCipherGenerator
implements WriteCipherGenerator {
@Override
public SSLWriteCipher createCipher(SSLCipher sslCipher,
Authenticator authenticator, ProtocolVersion protocolVersion,
String algorithm, Key key, AlgorithmParameterSpec params,
SecureRandom random) throws GeneralSecurityException {
return new CC20P1305WriteCipher(authenticator, protocolVersion,
sslCipher, algorithm, key, params, random);
}
private static final class CC20P1305WriteCipher extends SSLWriteCipher {
private final Cipher cipher;
private final int tagSize;
private final Key key;
private final byte[] iv;
private final SecureRandom random;
CC20P1305WriteCipher(Authenticator authenticator,
ProtocolVersion protocolVersion,
SSLCipher sslCipher, String algorithm,
Key key, AlgorithmParameterSpec params,
SecureRandom random) throws GeneralSecurityException {
super(authenticator, protocolVersion);
this.cipher = JsseJce.getCipher(algorithm);
this.tagSize = sslCipher.tagSize;
this.key = key;
this.iv = ((IvParameterSpec)params).getIV();
this.random = random;
keyLimitCountdown = cipherLimits.getOrDefault(
algorithm.toUpperCase() + ":" + tag[0], 0L);
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
SSLLogger.fine("algorithm = " + algorithm.toUpperCase() +
":" + tag[0] + "\ncountdown value = " +
keyLimitCountdown);
}
if (keyLimitCountdown > 0) {
keyLimitEnabled = true;
}
// DON'T initialize the cipher for AEAD!
}
@Override
public int encrypt(byte contentType,
ByteBuffer bb) {
byte[] sn = authenticator.sequenceNumber();
byte[] nonce = new byte[iv.length];
System.arraycopy(sn, 0, nonce, nonce.length - sn.length,
sn.length);
for (int i = 0; i < nonce.length; i++) {
nonce[i] ^= iv[i];
}
// initialize the AEAD cipher for the unique IV
AlgorithmParameterSpec spec = new IvParameterSpec(nonce);
try {
cipher.init(Cipher.ENCRYPT_MODE, key, spec, random);
} catch (InvalidKeyException |
InvalidAlgorithmParameterException ikae) {
// unlikely to happen
throw new RuntimeException(
"invalid key or spec in AEAD mode", ikae);
}
// Update the additional authentication data, using the
// implicit sequence number of the authenticator.
byte[] aad = authenticator.acquireAuthenticationBytes(
contentType, bb.remaining(), null);
cipher.updateAAD(aad);
// DON'T encrypt the nonce for AEAD mode.
int len = bb.remaining();
int pos = bb.position();
if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
SSLLogger.fine(
"Plaintext before ENCRYPTION",
bb.duplicate());
}
ByteBuffer dup = bb.duplicate();
int outputSize = cipher.getOutputSize(dup.remaining());
if (outputSize > bb.remaining()) {
// Need to expand the limit of the output buffer for
// the authentication tag.
//
// DON'T worry about the buffer's capacity, we have
// reserved space for the authentication tag.
bb.limit(pos + outputSize);
}
try {
len = cipher.doFinal(dup, bb);
} catch (IllegalBlockSizeException |
BadPaddingException | ShortBufferException ibse) {
// unlikely to happen
throw new RuntimeException(
"Cipher error in AEAD mode in JCE provider " +
cipher.getProvider().getName(), ibse);
}
if (len != outputSize) {
throw new RuntimeException(
"Cipher buffering error in JCE provider " +
cipher.getProvider().getName());
}
return len;
}
@Override
void dispose() {
if (cipher != null) {
try {
cipher.doFinal();
} catch (Exception e) {
// swallow all types of exceptions.
}
}
}
@Override
int getExplicitNonceSize() {
return 0;
}
@Override
int calculateFragmentSize(int packetLimit, int headerSize) {
return packetLimit - headerSize - tagSize;
}
@Override
int calculatePacketSize(int fragmentSize, int headerSize) {
return fragmentSize + headerSize + tagSize;
}
}
}
private static final class T13CC20P1305ReadCipherGenerator
implements ReadCipherGenerator {
@Override
public SSLReadCipher createCipher(SSLCipher sslCipher,
Authenticator authenticator, ProtocolVersion protocolVersion,
String algorithm, Key key, AlgorithmParameterSpec params,
SecureRandom random) throws GeneralSecurityException {
return new CC20P1305ReadCipher(authenticator, protocolVersion,
sslCipher, algorithm, key, params, random);
}
static final class CC20P1305ReadCipher extends SSLReadCipher {
private final Cipher cipher;
private final int tagSize;
private final Key key;
private final byte[] iv;
private final SecureRandom random;
CC20P1305ReadCipher(Authenticator authenticator,
ProtocolVersion protocolVersion,
SSLCipher sslCipher, String algorithm,
Key key, AlgorithmParameterSpec params,
SecureRandom random) throws GeneralSecurityException {
super(authenticator, protocolVersion);
this.cipher = JsseJce.getCipher(algorithm);
this.tagSize = sslCipher.tagSize;
this.key = key;
this.iv = ((IvParameterSpec)params).getIV();
this.random = random;
// DON'T initialize the cipher for AEAD!
}
@Override
public Plaintext decrypt(byte contentType, ByteBuffer bb,
byte[] sequence) throws GeneralSecurityException {
// An implementation may receive an unencrypted record of type
// change_cipher_spec consisting of the single byte value 0x01
// at any time after the first ClientHello message has been
// sent or received and before the peer's Finished message has
// been received and MUST simply drop it without further
// processing.
if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
return new Plaintext(contentType,
ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
-1, -1L, bb.slice());
}
if (bb.remaining() <= tagSize) {
throw new BadPaddingException(
"Insufficient buffer remaining for AEAD cipher " +
"fragment (" + bb.remaining() + "). Needs to be " +
"more than tag size (" + tagSize + ")");
}
byte[] sn = sequence;
if (sn == null) {
sn = authenticator.sequenceNumber();
}
byte[] nonce = new byte[iv.length];
System.arraycopy(sn, 0, nonce, nonce.length - sn.length,
sn.length);
for (int i = 0; i < nonce.length; i++) {
nonce[i] ^= iv[i];
}
// initialize the AEAD cipher with the unique IV
AlgorithmParameterSpec spec = new IvParameterSpec(nonce);
try {
cipher.init(Cipher.DECRYPT_MODE, key, spec, random);
} catch (InvalidKeyException |
InvalidAlgorithmParameterException ikae) {
// unlikely to happen
throw new RuntimeException(
"invalid key or spec in AEAD mode", ikae);
}
// Update the additional authentication data, using the
// implicit sequence number of the authenticator.
byte[] aad = authenticator.acquireAuthenticationBytes(
contentType, bb.remaining(), sn);
cipher.updateAAD(aad);
int len = bb.remaining();
int pos = bb.position();
ByteBuffer dup = bb.duplicate();
try {
len = cipher.doFinal(dup, bb);
} catch (IllegalBlockSizeException ibse) {
// unlikely to happen
throw new RuntimeException(
"Cipher error in AEAD mode \"" + ibse.getMessage() +
" \"in JCE provider " + cipher.getProvider().getName());
} catch (ShortBufferException sbe) {
// catch BouncyCastle buffering error
throw new RuntimeException("Cipher buffering error in " +
"JCE provider " + cipher.getProvider().getName(), sbe);
}
// reset the limit to the end of the decrypted data
bb.position(pos);
bb.limit(pos + len);
// remove inner plaintext padding
int i = bb.limit() - 1;
for (; i > 0 && bb.get(i) == 0; i--) {
// blank
}
if (i < (pos + 1)) {
throw new BadPaddingException(
"Incorrect inner plaintext: no content type");
}
contentType = bb.get(i);
bb.limit(i);
if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
SSLLogger.fine(
"Plaintext after DECRYPTION", bb.duplicate());
}
return new Plaintext(contentType,
ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
-1, -1L, bb.slice());
}
@Override
void dispose() {
if (cipher != null) {
try {
cipher.doFinal();
} catch (Exception e) {
// swallow all types of exceptions.
}
}
}
@Override
int estimateFragmentSize(int packetSize, int headerSize) {
return packetSize - headerSize - tagSize;
}
}
}
private static final class T13CC20P1305WriteCipherGenerator
implements WriteCipherGenerator {
@Override
public SSLWriteCipher createCipher(SSLCipher sslCipher,
Authenticator authenticator, ProtocolVersion protocolVersion,
String algorithm, Key key, AlgorithmParameterSpec params,
SecureRandom random) throws GeneralSecurityException {
return new CC20P1305WriteCipher(authenticator, protocolVersion,
sslCipher, algorithm, key, params, random);
}
private static final class CC20P1305WriteCipher extends SSLWriteCipher {
private final Cipher cipher;
private final int tagSize;
private final Key key;
private final byte[] iv;
private final SecureRandom random;
CC20P1305WriteCipher(Authenticator authenticator,
ProtocolVersion protocolVersion,
SSLCipher sslCipher, String algorithm,
Key key, AlgorithmParameterSpec params,
SecureRandom random) throws GeneralSecurityException {
super(authenticator, protocolVersion);
this.cipher = JsseJce.getCipher(algorithm);
this.tagSize = sslCipher.tagSize;
this.key = key;
this.iv = ((IvParameterSpec)params).getIV();
this.random = random;
keyLimitCountdown = cipherLimits.getOrDefault(
algorithm.toUpperCase() + ":" + tag[0], 0L);
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
SSLLogger.fine("algorithm = " + algorithm.toUpperCase() +
":" + tag[0] + "\ncountdown value = " +
keyLimitCountdown);
}
if (keyLimitCountdown > 0) {
keyLimitEnabled = true;
}
// DON'T initialize the cipher for AEAD!
}
@Override
public int encrypt(byte contentType,
ByteBuffer bb) {
byte[] sn = authenticator.sequenceNumber();
byte[] nonce = new byte[iv.length];
System.arraycopy(sn, 0, nonce, nonce.length - sn.length,
sn.length);
for (int i = 0; i < nonce.length; i++) {
nonce[i] ^= iv[i];
}
// initialize the AEAD cipher for the unique IV
AlgorithmParameterSpec spec = new IvParameterSpec(nonce);
try {
cipher.init(Cipher.ENCRYPT_MODE, key, spec, random);
} catch (InvalidKeyException |
InvalidAlgorithmParameterException ikae) {
// unlikely to happen
throw new RuntimeException(
"invalid key or spec in AEAD mode", ikae);
}
// Update the additional authentication data, using the
// implicit sequence number of the authenticator.
int outputSize = cipher.getOutputSize(bb.remaining());
byte[] aad = authenticator.acquireAuthenticationBytes(
contentType, outputSize, sn);
cipher.updateAAD(aad);
int len = bb.remaining();
int pos = bb.position();
if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
SSLLogger.fine(
"Plaintext before ENCRYPTION",
bb.duplicate());
}
ByteBuffer dup = bb.duplicate();
if (outputSize > bb.remaining()) {
// Need to expand the limit of the output buffer for
// the authentication tag.
//
// DON'T worry about the buffer's capacity, we have
// reserved space for the authentication tag.
bb.limit(pos + outputSize);
}
try {
len = cipher.doFinal(dup, bb);
} catch (IllegalBlockSizeException |
BadPaddingException | ShortBufferException ibse) {
// unlikely to happen
throw new RuntimeException(
"Cipher error in AEAD mode in JCE provider " +
cipher.getProvider().getName(), ibse);
}
if (len != outputSize) {
throw new RuntimeException(
"Cipher buffering error in JCE provider " +
cipher.getProvider().getName());
}
if (keyLimitEnabled) {
keyLimitCountdown -= len;
}
return len;
}
@Override
void dispose() {
if (cipher != null) {
try {
cipher.doFinal();
} catch (Exception e) {
// swallow all types of exceptions.
}
}
}
@Override
int getExplicitNonceSize() {
return 0;
}
@Override
int calculateFragmentSize(int packetLimit, int headerSize) {
return packetLimit - headerSize - tagSize;
}
@Override
int calculatePacketSize(int fragmentSize, int headerSize) {
return fragmentSize + headerSize + tagSize;
}
}
}
private static void addMac(MAC signer,
ByteBuffer destination, byte contentType) {
if (signer.macAlg().size != 0) {
@ -2367,4 +2936,3 @@ enum SSLCipher {
return results;
}
}

View file

@ -207,6 +207,10 @@ public abstract class SSLContextImpl extends SSLContextSpi {
if (!isInitialized) {
throw new IllegalStateException("SSLContext is not initialized");
}
if (isDTLS()) {
throw new UnsupportedOperationException(
"DTLS not supported with SSLSocket");
}
return new SSLSocketFactoryImpl(this);
}
@ -215,6 +219,10 @@ public abstract class SSLContextImpl extends SSLContextSpi {
if (!isInitialized) {
throw new IllegalStateException("SSLContext is not initialized");
}
if (isDTLS()) {
throw new UnsupportedOperationException(
"DTLS not supported with SSLServerSocket");
}
return new SSLServerSocketFactoryImpl(this);
}
@ -1261,6 +1269,21 @@ public abstract class SSLContextImpl extends SSLContextSpi {
serverDefaultProtocols, false);
}
@Override
protected SSLParameters engineGetDefaultSSLParameters() {
SSLEngine engine = createSSLEngineImpl();
return engine.getSSLParameters();
}
@Override
protected SSLParameters engineGetSupportedSSLParameters() {
SSLEngine engine = createSSLEngineImpl();
SSLParameters params = new SSLParameters();
params.setCipherSuites(engine.getSupportedCipherSuites());
params.setProtocols(engine.getSupportedProtocols());
return params;
}
@Override
List<ProtocolVersion> getSupportedProtocolVersions() {
return supportedProtocols;

View file

@ -333,7 +333,7 @@ final class SSLExtensions {
return "<no extension>";
} else {
StringBuilder builder = new StringBuilder(512);
if (logMap != null) {
if (logMap != null && !logMap.isEmpty()) {
for (Map.Entry<Integer, byte[]> en : logMap.entrySet()) {
SSLExtension ext = SSLExtension.valueOf(
handshakeMessage.handshakeType(), en.getKey());

View file

@ -525,7 +525,7 @@ final class SignatureAlgorithmsExtension {
// signatures appearing in certificates.
SignatureSchemesSpec certSpec =
(SignatureSchemesSpec)chc.handshakeExtensions.get(
SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT);
SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT);
if (certSpec == null) {
chc.peerRequestedCertSignSchemes = sss;
chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);