init
This commit is contained in:
1356
java/org/apache/tomcat/util/net/AbstractEndpoint.java
Normal file
1356
java/org/apache/tomcat/util/net/AbstractEndpoint.java
Normal file
File diff suppressed because it is too large
Load Diff
267
java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java
Normal file
267
java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.channels.NetworkChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
|
||||
import org.apache.tomcat.util.compat.JreCompat;
|
||||
import org.apache.tomcat.util.net.openssl.OpenSSLImplementation;
|
||||
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
|
||||
|
||||
public abstract class AbstractJsseEndpoint<S> extends AbstractEndpoint<S> {
|
||||
|
||||
private String sslImplementationName = null;
|
||||
private int sniParseLimit = 64 * 1024;
|
||||
|
||||
private SSLImplementation sslImplementation = null;
|
||||
|
||||
public String getSslImplementationName() {
|
||||
return sslImplementationName;
|
||||
}
|
||||
|
||||
|
||||
public void setSslImplementationName(String s) {
|
||||
this.sslImplementationName = s;
|
||||
}
|
||||
|
||||
|
||||
public SSLImplementation getSslImplementation() {
|
||||
return sslImplementation;
|
||||
}
|
||||
|
||||
|
||||
public int getSniParseLimit() {
|
||||
return sniParseLimit;
|
||||
}
|
||||
|
||||
|
||||
public void setSniParseLimit(int sniParseLimit) {
|
||||
this.sniParseLimit = sniParseLimit;
|
||||
}
|
||||
|
||||
|
||||
protected void initialiseSsl() throws Exception {
|
||||
if (isSSLEnabled()) {
|
||||
sslImplementation = SSLImplementation.getInstance(getSslImplementationName());
|
||||
|
||||
for (SSLHostConfig sslHostConfig : sslHostConfigs.values()) {
|
||||
createSSLContext(sslHostConfig);
|
||||
}
|
||||
|
||||
// Validate default SSLHostConfigName
|
||||
if (sslHostConfigs.get(getDefaultSSLHostConfigName()) == null) {
|
||||
throw new IllegalArgumentException(sm.getString("endpoint.noSslHostConfig",
|
||||
getDefaultSSLHostConfigName(), getName()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void createSSLContext(SSLHostConfig sslHostConfig) throws IllegalArgumentException {
|
||||
boolean firstCertificate = true;
|
||||
for (SSLHostConfigCertificate certificate : sslHostConfig.getCertificates(true)) {
|
||||
SSLUtil sslUtil = sslImplementation.getSSLUtil(certificate);
|
||||
if (firstCertificate) {
|
||||
firstCertificate = false;
|
||||
sslHostConfig.setEnabledProtocols(sslUtil.getEnabledProtocols());
|
||||
sslHostConfig.setEnabledCiphers(sslUtil.getEnabledCiphers());
|
||||
}
|
||||
|
||||
SSLContext sslContext;
|
||||
try {
|
||||
sslContext = sslUtil.createSSLContext(negotiableProtocols);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
certificate.setSslContext(sslContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected SSLEngine createSSLEngine(String sniHostName, List<Cipher> clientRequestedCiphers,
|
||||
List<String> clientRequestedApplicationProtocols) {
|
||||
SSLHostConfig sslHostConfig = getSSLHostConfig(sniHostName);
|
||||
|
||||
SSLHostConfigCertificate certificate = selectCertificate(sslHostConfig, clientRequestedCiphers);
|
||||
|
||||
SSLContext sslContext = certificate.getSslContext();
|
||||
if (sslContext == null) {
|
||||
throw new IllegalStateException(
|
||||
sm.getString("endpoint.jsse.noSslContext", sniHostName));
|
||||
}
|
||||
|
||||
SSLEngine engine = sslContext.createSSLEngine();
|
||||
engine.setUseClientMode(false);
|
||||
engine.setEnabledCipherSuites(sslHostConfig.getEnabledCiphers());
|
||||
engine.setEnabledProtocols(sslHostConfig.getEnabledProtocols());
|
||||
|
||||
SSLParameters sslParameters = engine.getSSLParameters();
|
||||
String honorCipherOrderStr = sslHostConfig.getHonorCipherOrder();
|
||||
if (honorCipherOrderStr != null) {
|
||||
boolean honorCipherOrder = Boolean.parseBoolean(honorCipherOrderStr);
|
||||
JreCompat.getInstance().setUseServerCipherSuitesOrder(sslParameters, honorCipherOrder);
|
||||
}
|
||||
|
||||
if (JreCompat.isJre9Available() && clientRequestedApplicationProtocols != null
|
||||
&& clientRequestedApplicationProtocols.size() > 0
|
||||
&& negotiableProtocols.size() > 0) {
|
||||
// Only try to negotiate if both client and server have at least
|
||||
// one protocol in common
|
||||
// Note: Tomcat does not explicitly negotiate http/1.1
|
||||
// TODO: Is this correct? Should it change?
|
||||
List<String> commonProtocols = new ArrayList<>();
|
||||
commonProtocols.addAll(negotiableProtocols);
|
||||
commonProtocols.retainAll(clientRequestedApplicationProtocols);
|
||||
if (commonProtocols.size() > 0) {
|
||||
String[] commonProtocolsArray = commonProtocols.toArray(new String[commonProtocols.size()]);
|
||||
JreCompat.getInstance().setApplicationProtocols(sslParameters, commonProtocolsArray);
|
||||
}
|
||||
}
|
||||
switch (sslHostConfig.getCertificateVerification()) {
|
||||
case NONE:
|
||||
sslParameters.setNeedClientAuth(false);
|
||||
sslParameters.setWantClientAuth(false);
|
||||
break;
|
||||
case OPTIONAL:
|
||||
case OPTIONAL_NO_CA:
|
||||
sslParameters.setWantClientAuth(true);
|
||||
break;
|
||||
case REQUIRED:
|
||||
sslParameters.setNeedClientAuth(true);
|
||||
break;
|
||||
}
|
||||
// The getter (at least in OpenJDK and derivatives) returns a defensive copy
|
||||
engine.setSSLParameters(sslParameters);
|
||||
|
||||
return engine;
|
||||
}
|
||||
|
||||
|
||||
private SSLHostConfigCertificate selectCertificate(
|
||||
SSLHostConfig sslHostConfig, List<Cipher> clientCiphers) {
|
||||
|
||||
Set<SSLHostConfigCertificate> certificates = sslHostConfig.getCertificates(true);
|
||||
if (certificates.size() == 1) {
|
||||
return certificates.iterator().next();
|
||||
}
|
||||
|
||||
LinkedHashSet<Cipher> serverCiphers = sslHostConfig.getCipherList();
|
||||
|
||||
List<Cipher> candidateCiphers = new ArrayList<>();
|
||||
if (Boolean.parseBoolean(sslHostConfig.getHonorCipherOrder())) {
|
||||
candidateCiphers.addAll(serverCiphers);
|
||||
candidateCiphers.retainAll(clientCiphers);
|
||||
} else {
|
||||
candidateCiphers.addAll(clientCiphers);
|
||||
candidateCiphers.retainAll(serverCiphers);
|
||||
}
|
||||
|
||||
for (Cipher candidate : candidateCiphers) {
|
||||
for (SSLHostConfigCertificate certificate : certificates) {
|
||||
if (certificate.getType().isCompatibleWith(candidate.getAu())) {
|
||||
return certificate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No matches. Just return the first certificate. The handshake will
|
||||
// then fail due to no matching ciphers.
|
||||
return certificates.iterator().next();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAlpnSupported() {
|
||||
// ALPN requires TLS so if TLS is not enabled, ALPN cannot be supported
|
||||
if (!isSSLEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Depends on the SSLImplementation.
|
||||
SSLImplementation sslImplementation;
|
||||
try {
|
||||
sslImplementation = SSLImplementation.getInstance(getSslImplementationName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Ignore the exception. It will be logged when trying to start the
|
||||
// end point.
|
||||
return false;
|
||||
}
|
||||
return sslImplementation.isAlpnSupported();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
testServerCipherSuitesOrderSupport();
|
||||
super.init();
|
||||
}
|
||||
|
||||
|
||||
private void testServerCipherSuitesOrderSupport() {
|
||||
// Only need to test for this if running on Java < 8 and not using the
|
||||
// OpenSSL SSLImplementation
|
||||
if(!JreCompat.isJre8Available() &&
|
||||
!OpenSSLImplementation.class.getName().equals(getSslImplementationName())) {
|
||||
for (SSLHostConfig sslHostConfig : sslHostConfigs.values()) {
|
||||
if (sslHostConfig.getHonorCipherOrder() != null) {
|
||||
throw new UnsupportedOperationException(
|
||||
sm.getString("endpoint.jsse.cannotHonorServerCipherOrder"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void unbind() throws Exception {
|
||||
for (SSLHostConfig sslHostConfig : sslHostConfigs.values()) {
|
||||
for (SSLHostConfigCertificate certificate : sslHostConfig.getCertificates(true)) {
|
||||
certificate.setSslContext(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected abstract NetworkChannel getServerSocket();
|
||||
|
||||
|
||||
@Override
|
||||
protected final InetSocketAddress getLocalAddress() throws IOException {
|
||||
NetworkChannel serverSock = getServerSocket();
|
||||
if (serverSock == null) {
|
||||
return null;
|
||||
}
|
||||
SocketAddress sa = serverSock.getLocalAddress();
|
||||
if (sa instanceof InetSocketAddress) {
|
||||
return (InetSocketAddress) sa;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Callback interface to be able to expand buffers when buffer overflow
|
||||
* exceptions happen or to replace buffers
|
||||
*/
|
||||
public interface ApplicationBufferHandler {
|
||||
|
||||
public void setByteBuffer(ByteBuffer buffer);
|
||||
|
||||
public ByteBuffer getByteBuffer();
|
||||
|
||||
public void expand(int size);
|
||||
|
||||
}
|
||||
2753
java/org/apache/tomcat/util/net/AprEndpoint.java
Normal file
2753
java/org/apache/tomcat/util/net/AprEndpoint.java
Normal file
File diff suppressed because it is too large
Load Diff
115
java/org/apache/tomcat/util/net/AprSSLSupport.java
Normal file
115
java/org/apache/tomcat/util/net/AprSSLSupport.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import org.apache.tomcat.jni.SSL;
|
||||
|
||||
/**
|
||||
* Implementation of SSLSupport for APR.
|
||||
* <p>
|
||||
* TODO: Add a mechanism (or figure out how to use what we already have) to
|
||||
* invalidate the session.
|
||||
*/
|
||||
public class AprSSLSupport implements SSLSupport {
|
||||
|
||||
private final AprEndpoint.AprSocketWrapper socketWrapper;
|
||||
private final String clientCertProvider;
|
||||
|
||||
|
||||
public AprSSLSupport(AprEndpoint.AprSocketWrapper socketWrapper, String clientCertProvider) {
|
||||
this.socketWrapper = socketWrapper;
|
||||
this.clientCertProvider = clientCertProvider;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getCipherSuite() throws IOException {
|
||||
try {
|
||||
return socketWrapper.getSSLInfoS(SSL.SSL_INFO_CIPHER);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getPeerCertificateChain() throws IOException {
|
||||
try {
|
||||
// certLength == -1 indicates an error unless TLS session tickets
|
||||
// are in use in which case OpenSSL won't store the chain in the
|
||||
// ticket.
|
||||
int certLength = socketWrapper.getSSLInfoI(SSL.SSL_INFO_CLIENT_CERT_CHAIN);
|
||||
byte[] clientCert = socketWrapper.getSSLInfoB(SSL.SSL_INFO_CLIENT_CERT);
|
||||
X509Certificate[] certs = null;
|
||||
|
||||
if (clientCert != null) {
|
||||
if (certLength < 0) {
|
||||
certLength = 0;
|
||||
}
|
||||
certs = new X509Certificate[certLength + 1];
|
||||
CertificateFactory cf;
|
||||
if (clientCertProvider == null) {
|
||||
cf = CertificateFactory.getInstance("X.509");
|
||||
} else {
|
||||
cf = CertificateFactory.getInstance("X.509", clientCertProvider);
|
||||
}
|
||||
certs[0] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(clientCert));
|
||||
for (int i = 0; i < certLength; i++) {
|
||||
byte[] data = socketWrapper.getSSLInfoB(SSL.SSL_INFO_CLIENT_CERT_CHAIN + i);
|
||||
certs[i+1] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(data));
|
||||
}
|
||||
}
|
||||
return certs;
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Integer getKeySize() throws IOException {
|
||||
try {
|
||||
return Integer.valueOf(socketWrapper.getSSLInfoI(SSL.SSL_INFO_CIPHER_USEKEYSIZE));
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getSessionId() throws IOException {
|
||||
try {
|
||||
return socketWrapper.getSSLInfoS(SSL.SSL_INFO_SESSION_ID);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() throws IOException {
|
||||
try {
|
||||
return socketWrapper.getSSLInfoS(SSL.SSL_INFO_PROTOCOL);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
41
java/org/apache/tomcat/util/net/Constants.java
Normal file
41
java/org/apache/tomcat/util/net/Constants.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
public class Constants {
|
||||
|
||||
/**
|
||||
* Name of the system property containing
|
||||
* the tomcat instance installation path
|
||||
*/
|
||||
public static final String CATALINA_BASE_PROP = "catalina.base";
|
||||
|
||||
/**
|
||||
* JSSE and OpenSSL protocol names
|
||||
*/
|
||||
public static final String SSL_PROTO_ALL = "all";
|
||||
public static final String SSL_PROTO_TLS = "TLS";
|
||||
public static final String SSL_PROTO_TLSv1_3 = "TLSv1.3";
|
||||
public static final String SSL_PROTO_TLSv1_2 = "TLSv1.2";
|
||||
public static final String SSL_PROTO_TLSv1_1 = "TLSv1.1";
|
||||
// Two different forms for TLS 1.0
|
||||
public static final String SSL_PROTO_TLSv1_0 = "TLSv1.0";
|
||||
public static final String SSL_PROTO_TLSv1 = "TLSv1";
|
||||
public static final String SSL_PROTO_SSLv3 = "SSLv3";
|
||||
public static final String SSL_PROTO_SSLv2 = "SSLv2";
|
||||
public static final String SSL_PROTO_SSLv2Hello = "SSLv2Hello";
|
||||
}
|
||||
45
java/org/apache/tomcat/util/net/ContainerThreadMarker.java
Normal file
45
java/org/apache/tomcat/util/net/ContainerThreadMarker.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
/**
|
||||
* Used to mark threads that have been allocated by the container to process
|
||||
* data from an incoming connection. Application created threads are not
|
||||
* container threads and neither are threads taken from the container thread
|
||||
* pool to execute AsyncContext.start(Runnable).
|
||||
*/
|
||||
public class ContainerThreadMarker {
|
||||
|
||||
private static final ThreadLocal<Boolean> marker = new ThreadLocal<>();
|
||||
|
||||
public static boolean isContainerThread() {
|
||||
Boolean flag = marker.get();
|
||||
if (flag == null) {
|
||||
return false;
|
||||
} else {
|
||||
return flag.booleanValue();
|
||||
}
|
||||
}
|
||||
|
||||
public static void set() {
|
||||
marker.set(Boolean.TRUE);
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
marker.set(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
38
java/org/apache/tomcat/util/net/DispatchType.java
Normal file
38
java/org/apache/tomcat/util/net/DispatchType.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
/**
|
||||
* This enumeration lists the different types of dispatches that request
|
||||
* processing can trigger. In this instance, dispatch means re-process this
|
||||
* request using the given socket status.
|
||||
*/
|
||||
public enum DispatchType {
|
||||
|
||||
NON_BLOCKING_READ(SocketEvent.OPEN_READ),
|
||||
NON_BLOCKING_WRITE(SocketEvent.OPEN_WRITE);
|
||||
|
||||
private final SocketEvent status;
|
||||
|
||||
private DispatchType(SocketEvent status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public SocketEvent getSocketStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
252
java/org/apache/tomcat/util/net/IPv6Utils.java
Normal file
252
java/org/apache/tomcat/util/net/IPv6Utils.java
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
/**
|
||||
* <p>IPv6 utilities.
|
||||
* <p>For the moment, it only contains function to canonicalize IPv6 address
|
||||
* into RFC 5952 form.
|
||||
*/
|
||||
public class IPv6Utils {
|
||||
|
||||
private static final int MAX_NUMBER_OF_GROUPS = 8;
|
||||
private static final int MAX_GROUP_LENGTH = 4;
|
||||
|
||||
/**
|
||||
* <p>Convert IPv6 address into RFC 5952 form.
|
||||
* E.g. 2001:db8:0:1:0:0:0:1 -> 2001:db8:0:1::1</p>
|
||||
*
|
||||
* <p>Method is null safe, and if IPv4 address or host name is passed to the
|
||||
* method it is returned without any processing.</p>
|
||||
*
|
||||
* <p>Method also supports IPv4 in IPv6 (e.g. 0:0:0:0:0:ffff:192.0.2.1 ->
|
||||
* ::ffff:192.0.2.1), and zone ID (e.g. fe80:0:0:0:f0f0:c0c0:1919:1234%4
|
||||
* -> fe80::f0f0:c0c0:1919:1234%4).</p>
|
||||
*
|
||||
* <p>The behaviour of this method is undefined if an invalid IPv6 address
|
||||
* is passed in as input.</p>
|
||||
*
|
||||
* @param ipv6Address String representing valid IPv6 address.
|
||||
* @return String representing IPv6 in canonical form.
|
||||
* @throws IllegalArgumentException if IPv6 format is unacceptable.
|
||||
*/
|
||||
public static String canonize(String ipv6Address) throws IllegalArgumentException {
|
||||
|
||||
if (ipv6Address == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Definitely not an IPv6, return untouched input.
|
||||
if (!mayBeIPv6Address(ipv6Address)) {
|
||||
return ipv6Address;
|
||||
}
|
||||
|
||||
// Length without zone ID (%zone) or IPv4 address
|
||||
int ipv6AddressLength = ipv6Address.length();
|
||||
if (ipv6Address.contains(".")) {
|
||||
// IPv4 in IPv6
|
||||
// e.g. 0:0:0:0:0:FFFF:127.0.0.1
|
||||
int lastColonPos = ipv6Address.lastIndexOf(":");
|
||||
int lastColonsPos = ipv6Address.lastIndexOf("::");
|
||||
if (lastColonsPos >= 0 && lastColonPos == lastColonsPos + 1) {
|
||||
/*
|
||||
* IPv6 part ends with two consecutive colons,
|
||||
* last colon is part of IPv6 format.
|
||||
* e.g. ::127.0.0.1
|
||||
*/
|
||||
ipv6AddressLength = lastColonPos + 1;
|
||||
} else {
|
||||
/*
|
||||
* IPv6 part ends with only one colon,
|
||||
* last colon is not part of IPv6 format.
|
||||
* e.g. ::FFFF:127.0.0.1
|
||||
*/
|
||||
ipv6AddressLength = lastColonPos;
|
||||
}
|
||||
} else if (ipv6Address.contains("%")) {
|
||||
// Zone ID
|
||||
// e.g. fe80:0:0:0:f0f0:c0c0:1919:1234%4
|
||||
ipv6AddressLength = ipv6Address.lastIndexOf("%");
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
char [][] groups = new char[MAX_NUMBER_OF_GROUPS][MAX_GROUP_LENGTH];
|
||||
int groupCounter = 0;
|
||||
int charInGroupCounter = 0;
|
||||
|
||||
// Index of the current zeroGroup, -1 means not found.
|
||||
int zeroGroupIndex = -1;
|
||||
int zeroGroupLength = 0;
|
||||
|
||||
// maximum length zero group, if there is more then one, then first one
|
||||
int maxZeroGroupIndex = -1;
|
||||
int maxZeroGroupLength = 0;
|
||||
|
||||
boolean isZero = true;
|
||||
boolean groupStart = true;
|
||||
|
||||
/*
|
||||
* Two consecutive colons, initial expansion.
|
||||
* e.g. 2001:db8:0:0:1::1 -> 2001:db8:0:0:1:0:0:1
|
||||
*/
|
||||
|
||||
StringBuilder expanded = new StringBuilder(ipv6Address);
|
||||
int colonsPos = ipv6Address.indexOf("::");
|
||||
int length = ipv6AddressLength;
|
||||
int change = 0;
|
||||
|
||||
if (colonsPos >= 0 && colonsPos < ipv6AddressLength - 2) {
|
||||
int colonCounter = 0;
|
||||
for (int i = 0; i < ipv6AddressLength; i++) {
|
||||
if (ipv6Address.charAt(i) == ':') {
|
||||
colonCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
if (colonsPos == 0) {
|
||||
expanded.insert(0, "0");
|
||||
change = change + 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_NUMBER_OF_GROUPS - colonCounter; i++) {
|
||||
expanded.insert(colonsPos + 1, "0:");
|
||||
change = change + 2;
|
||||
}
|
||||
|
||||
|
||||
if (colonsPos == ipv6AddressLength - 2) {
|
||||
expanded.setCharAt(colonsPos + change + 1, '0');
|
||||
} else {
|
||||
expanded.deleteCharAt(colonsPos + change + 1);
|
||||
change = change - 1;
|
||||
}
|
||||
length = length + change;
|
||||
}
|
||||
|
||||
|
||||
// Processing one char at the time
|
||||
for (int charCounter = 0; charCounter < length; charCounter++) {
|
||||
char c = expanded.charAt(charCounter);
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
c = (char) (c + 32);
|
||||
}
|
||||
if (c != ':') {
|
||||
groups[groupCounter][charInGroupCounter] = c;
|
||||
if (!(groupStart && c == '0')) {
|
||||
++charInGroupCounter;
|
||||
groupStart = false;
|
||||
}
|
||||
if (c != '0') {
|
||||
isZero = false;
|
||||
}
|
||||
}
|
||||
if (c == ':' || charCounter == (length - 1)) {
|
||||
// We reached end of current group
|
||||
if (isZero) {
|
||||
++zeroGroupLength;
|
||||
if (zeroGroupIndex == -1) {
|
||||
zeroGroupIndex = groupCounter;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isZero || charCounter == (length - 1)) {
|
||||
// We reached end of zero group
|
||||
if (zeroGroupLength > maxZeroGroupLength) {
|
||||
maxZeroGroupLength = zeroGroupLength;
|
||||
maxZeroGroupIndex = zeroGroupIndex;
|
||||
}
|
||||
zeroGroupLength = 0;
|
||||
zeroGroupIndex = -1;
|
||||
}
|
||||
++groupCounter;
|
||||
charInGroupCounter = 0;
|
||||
isZero = true;
|
||||
groupStart = true;
|
||||
}
|
||||
}
|
||||
|
||||
int numberOfGroups = groupCounter;
|
||||
|
||||
// Output results
|
||||
for (groupCounter = 0; groupCounter < numberOfGroups; groupCounter++) {
|
||||
if (maxZeroGroupLength <= 1 || groupCounter < maxZeroGroupIndex
|
||||
|| groupCounter >= maxZeroGroupIndex + maxZeroGroupLength) {
|
||||
for (int j = 0; j < MAX_GROUP_LENGTH; j++) {
|
||||
if (groups[groupCounter][j] != 0) {
|
||||
result.append(groups[groupCounter][j]);
|
||||
}
|
||||
}
|
||||
if (groupCounter < (numberOfGroups - 1)
|
||||
&& (groupCounter != maxZeroGroupIndex - 1
|
||||
|| maxZeroGroupLength <= 1)) {
|
||||
result.append(':');
|
||||
}
|
||||
} else if (groupCounter == maxZeroGroupIndex) {
|
||||
result.append("::");
|
||||
}
|
||||
}
|
||||
|
||||
// Solve problem with three colons in IPv4 in IPv6 format
|
||||
// e.g. 0:0:0:0:0:0:127.0.0.1 -> :::127.0.0.1 -> ::127.0.0.1
|
||||
int resultLength = result.length();
|
||||
if (result.charAt(resultLength - 1) == ':' && ipv6AddressLength < ipv6Address.length()
|
||||
&& ipv6Address.charAt(ipv6AddressLength) == ':') {
|
||||
result.delete(resultLength - 1, resultLength);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append IPv4 from IPv4-in-IPv6 format or Zone ID
|
||||
*/
|
||||
for (int i = ipv6AddressLength; i < ipv6Address.length(); i++) {
|
||||
result.append(ipv6Address.charAt(i));
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Heuristic check if string might be an IPv6 address.
|
||||
*
|
||||
* @param input Any string or null
|
||||
* @return true, if input string contains only hex digits and at least two colons, before '.' or '%' character
|
||||
*/
|
||||
static boolean mayBeIPv6Address(String input) {
|
||||
if (input == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int colonsCounter = 0;
|
||||
int length = input.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = input.charAt(i);
|
||||
if (c == '.' || c == '%') {
|
||||
// IPv4 in IPv6 or Zone ID detected, end of checking.
|
||||
break;
|
||||
}
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
|
||||
|| (c >= 'A' && c <= 'F') || c == ':')) {
|
||||
return false;
|
||||
} else if (c == ':') {
|
||||
colonsCounter++;
|
||||
}
|
||||
}
|
||||
if (colonsCounter < 2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
154
java/org/apache/tomcat/util/net/LocalStrings.properties
Normal file
154
java/org/apache/tomcat/util/net/LocalStrings.properties
Normal file
@@ -0,0 +1,154 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
channel.nio.interrupted=The current thread was interrupted
|
||||
channel.nio.ssl.appInputNotEmpty=Application input buffer still contains data. Data would have been lost.
|
||||
channel.nio.ssl.appOutputNotEmpty=Application output buffer still contains data. Data would have been lost.
|
||||
channel.nio.ssl.closeSilentError=As expected, there was an exception trying to close the connection cleanly.
|
||||
channel.nio.ssl.closing=Channel is in closing state.
|
||||
channel.nio.ssl.eofDuringHandshake=EOF during handshake.
|
||||
channel.nio.ssl.expandNetInBuffer=Expanding network input buffer to [{0}] bytes
|
||||
channel.nio.ssl.expandNetOutBuffer=Expanding network output buffer to [{0}] bytes
|
||||
channel.nio.ssl.foundHttp=Found an plain text HTTP request on what should be an encrypted TLS connection
|
||||
channel.nio.ssl.handshakeError=Handshake error
|
||||
channel.nio.ssl.incompleteHandshake=Handshake incomplete, you must complete handshake before reading data.
|
||||
channel.nio.ssl.invalidCloseState=Invalid close state, will not send network data.
|
||||
channel.nio.ssl.invalidStatus=Unexpected status [{0}].
|
||||
channel.nio.ssl.netInputNotEmpty=Network input buffer still contains data. Handshake will fail.
|
||||
channel.nio.ssl.netOutputNotEmpty=Network output buffer still contains data. Handshake will fail.
|
||||
channel.nio.ssl.notHandshaking=NOT_HANDSHAKING during handshake
|
||||
channel.nio.ssl.pendingWriteDuringClose=Pending write, so remaining data in the network buffer, can't send SSL close message, socket closed anyway
|
||||
channel.nio.ssl.remainingDataDuringClose=Remaining data in the network buffer, can't send SSL close message, socket closes anyway
|
||||
channel.nio.ssl.sniDefault=Unable to buffer enough data to determine requested SNI host name. Using default
|
||||
channel.nio.ssl.sniHostName=The SNI host name extracted for connection [{0}] was [{1}]
|
||||
channel.nio.ssl.timeoutDuringHandshake=Timeout during handshake.
|
||||
channel.nio.ssl.unexpectedStatusDuringUnwrap=Unexpected status [{0}] during handshake UNWRAP.
|
||||
channel.nio.ssl.unexpectedStatusDuringWrap=Unexpected status [{0}] during handshake WRAP.
|
||||
channel.nio.ssl.unwrapFail=Unable to unwrap data, invalid status [{0}]
|
||||
channel.nio.ssl.unwrapFailResize=Unable to unwrap data because buffer is too small, invalid status [{0}]
|
||||
channel.nio.ssl.wrapException=Handshake failed during wrap
|
||||
channel.nio.ssl.wrapFail=Unable to wrap data, invalid status [{0}]
|
||||
|
||||
endpoint.accept.fail=Socket accept failed
|
||||
endpoint.alpn.fail=Failed to configure endpoint for ALPN using [{0}]
|
||||
endpoint.alpn.negotiated=Negotiated [{0}] protocol using ALPN
|
||||
endpoint.apr.applyConf=Applying OpenSSLConfCmd to SSL context
|
||||
endpoint.apr.checkConf=Checking OpenSSLConf
|
||||
endpoint.apr.errApplyConf=Could not apply OpenSSLConf to SSL context
|
||||
endpoint.apr.errCheckConf=Error during OpenSSLConf check
|
||||
endpoint.apr.errMakeConf=Could not create OpenSSLConf context
|
||||
endpoint.apr.failSslContextMake=Unable to create SSLContext. Check that SSLEngine is enabled in the AprLifecycleListener, the AprLifecycleListener has initialised correctly and that a valid SSLProtocol has been specified
|
||||
endpoint.apr.invalidSslProtocol=An invalid value [{0}] was provided for the SSLProtocol attribute
|
||||
endpoint.apr.maxConnections.running=The APR endpoint does not support the setting of maxConnections while it is running. The existing value of [{0}] will continue to be used.
|
||||
endpoint.apr.maxConnections.unlimited=The APR endpoint does not support unlimited connections. The existing value of [{0}] will continue to be used.
|
||||
endpoint.apr.noSendfileWithSSL=Sendfile is not supported for the APR/native connector when SSL is enabled
|
||||
endpoint.apr.pollAddInvalid=Invalid attempt to add a socket [{0}] to the poller
|
||||
endpoint.apr.pollError=Poller failed with error [{0}] : [{1}]
|
||||
endpoint.apr.pollMergeEvents=Merge poller event [{1}] for socket [{0}] to create merged event [{2}]
|
||||
endpoint.apr.pollUnknownEvent=A socket was returned from the poller with an unrecognized event [{0}]
|
||||
endpoint.apr.remoteport=APR socket [{0}] opened with remote port [{1}]
|
||||
endpoint.apr.tooManyCertFiles=More certificate files were configured than the AprEndpoint can handle
|
||||
endpoint.debug.channelCloseFail=Failed to close channel
|
||||
endpoint.debug.destroySocket=Destroying socket [{0}]
|
||||
endpoint.debug.pollerAdd=Add to addList socket [{0}], timeout [{1}], flags [{2}]
|
||||
endpoint.debug.pollerAddDo=Add to poller socket [{0}]
|
||||
endpoint.debug.pollerProcess=Processing socket [{0}] for event(s) [{1}]
|
||||
endpoint.debug.pollerRemove=Attempting to remove [{0}] from poller
|
||||
endpoint.debug.pollerRemoved=Removed [{0}] from poller
|
||||
endpoint.debug.registerRead=Registered read interest for [{0}]
|
||||
endpoint.debug.registerWrite=Registered write interest for [{0}]
|
||||
endpoint.debug.socket=socket [{0}]
|
||||
endpoint.debug.socketCloseFail=Failed to close socket
|
||||
endpoint.debug.socketTimeout=Timing out [{0}]
|
||||
endpoint.debug.unlock.fail=Caught exception trying to unlock accept on port [{0}]
|
||||
endpoint.debug.unlock.localFail=Unable to determine local address for [{0}]
|
||||
endpoint.debug.unlock.localNone=Failed to unlock acceptor for [{0}] because the local address was not available
|
||||
endpoint.duplicateSslHostName=Multiple SSLHostConfig elements were provided for the host name [{0}]. Host names must be unique.
|
||||
endpoint.err.close=Caught exception trying to close socket
|
||||
endpoint.err.handshake=Handshake failed
|
||||
endpoint.err.unexpected=Unexpected error processing socket
|
||||
endpoint.executor.fail=Executor rejected socket [{0}] for processing
|
||||
endpoint.getAttribute=[{0}] is [{1}]
|
||||
endpoint.init.bind=Socket bind failed: [{0}] [{1}]
|
||||
endpoint.init.bind.inherited=No inherited channel while the connector was configured to use one
|
||||
endpoint.init.listen=Socket listen failed: [{0}] [{1}]
|
||||
endpoint.init.notavail=APR not available
|
||||
endpoint.invalidJmxNameSslHost=Unable to generate a valid JMX object name for the SSLHostConfig associated with host [{0}]
|
||||
endpoint.invalidJmxNameSslHostCert=Unable to generate a valid JMX object name for the SSLHostConfigCertificate associated with host [{0}] and certificate type [{1}]
|
||||
endpoint.jmxRegistrationFailed=Failed to register the JMX object with name [{0}]
|
||||
endpoint.jsse.cannotHonorServerCipherOrder=The Java Runtime does not support "useServerCipherSuitesOrder" with JSSE. You must use OpenSSL or Java 8 onwards to use this feature.
|
||||
endpoint.jsse.noSslContext=No SSLContext could be found for the host name [{0}]
|
||||
endpoint.launch.fail=Failed to launch new runnable
|
||||
endpoint.nio.registerFail=Failed to register socket with selector from poller
|
||||
endpoint.nio.selectorCloseFail=Failed to close selector when closing the poller
|
||||
endpoint.nio.stopLatchAwaitFail=The pollers did not stop within the expected time
|
||||
endpoint.nio.stopLatchAwaitInterrupted=This thread was interrupted while waiting for the pollers to stop
|
||||
endpoint.nio.timeoutCme=Exception during processing of timeouts. The code has been checked repeatedly and no concurrent modification has been found. If you are able to repeat this error please open a Tomcat bug and provide the steps to reproduce.
|
||||
endpoint.nio2.exclusiveExecutor=The NIO2 connector requires an exclusive executor to operate properly on shutdown
|
||||
endpoint.noSslHostConfig=No SSLHostConfig element was found with the hostName [{0}] to match the defaultSSLHostConfigName for the connector [{1}]
|
||||
endpoint.noSslHostName=No host name was provided for the SSL host configuration
|
||||
endpoint.poll.error=Unexpected poller error
|
||||
endpoint.poll.fail=Critical poller failure (restarting poller): [{0}] [{1}]
|
||||
endpoint.poll.initfail=Poller creation failed
|
||||
endpoint.poll.limitedpollsize=Failed to create poller with specified size of [{0}]
|
||||
endpoint.process.fail=Error allocating socket processor
|
||||
endpoint.processing.fail=Error running socket processor
|
||||
endpoint.removeDefaultSslHostConfig=The default SSLHostConfig (named [{0}]) may not be removed
|
||||
endpoint.sendfile.addfail=Sendfile failure: [{0}] [{1}]
|
||||
endpoint.sendfile.error=Unexpected sendfile error
|
||||
endpoint.serverSocket.closeFailed=Failed to close server socket for [{0}]
|
||||
endpoint.setAttribute=Set [{0}] to [{1}]
|
||||
endpoint.timeout.err=Error processing socket timeout
|
||||
endpoint.unknownSslHostName=The SSL host name [{0}] is not recognised for this endpoint
|
||||
endpoint.warn.executorShutdown=The executor associated with thread pool [{0}] has not fully shutdown. Some application threads may still be running.
|
||||
endpoint.warn.incorrectConnectionCount=Incorrect connection count, multiple calls to socket.close for the same socket.
|
||||
endpoint.warn.noLocalAddr=Unable to determine local address for socket [{0}]
|
||||
endpoint.warn.noLocalName=Unable to determine local host name for socket [{0}]
|
||||
endpoint.warn.noLocalPort=Unable to determine local port for socket [{0}]
|
||||
endpoint.warn.noRemoteAddr=Unable to determine remote address for socket [{0}]
|
||||
endpoint.warn.noRemoteHost=Unable to determine remote host name for socket [{0}]
|
||||
endpoint.warn.noRemotePort=Unable to determine remote port for socket [{0}]
|
||||
endpoint.warn.unlockAcceptorFailed=Acceptor thread [{0}] failed to unlock. Forcing hard socket shutdown.
|
||||
|
||||
jsse.invalid_truststore_password=The provided trust store password could not be used to unlock and/or validate the trust store. Retrying to access the trust store with a null password which will skip validation.
|
||||
jsse.keystore_load_failed=Failed to load keystore type [{0}] with path [{1}] due to [{2}]
|
||||
jsse.ssl3=SSLv3 has been explicitly enabled. This protocol is known to be insecure.
|
||||
jsse.tls13.auth=The JSSE TLS 1.3 implementation does not support authentication after the initial handshake and is therefore incompatible with optional client authentication
|
||||
|
||||
sniExtractor.clientHelloInvalid=The ClientHello message was not correctly formatted
|
||||
sniExtractor.clientHelloTooBig=The ClientHello was not presented in a single TLS record so no SNI information could be extracted
|
||||
|
||||
socket.apr.clientAbort=The client aborted the connection.
|
||||
socket.apr.closed=The socket [{0}] associated with this connection has been closed.
|
||||
socket.apr.read.error=Unexpected error [{0}] reading data from the APR/native socket [{1}] with wrapper [{2}].
|
||||
socket.apr.write.error=Unexpected error [{0}] writing data to the APR/native socket [{1}] with wrapper [{2}].
|
||||
socket.closed=The socket associated with this connection has been closed.
|
||||
socket.sslreneg=Exception re-negotiating SSL connection
|
||||
|
||||
sslHostConfig.certificate.notype=Multiple certificates were specified and at least one is missing the required attribute type
|
||||
sslHostConfig.certificateVerificationInvalid=The certificate verification value [{0}] is not recognised
|
||||
sslHostConfig.fileNotFound=Configured file [{0}] does not exist
|
||||
sslHostConfig.mismatch=The property [{0}] was set on the SSLHostConfig named [{1}] and is for the [{2}] configuration syntax but the SSLHostConfig is being used with the [{3}] configuration syntax
|
||||
sslHostConfig.opensslconf.alreadyset=Attempt to set another OpenSSLConf ignored
|
||||
sslHostConfig.opensslconf.null=Attempt to set null OpenSSLConf ignored
|
||||
sslHostConfig.prefix_missing=The protocol [{0}] was added to the list of protocols on the SSLHostConfig named [{1}]. Check if a +/- prefix is missing.
|
||||
|
||||
sslHostConfigCertificate.mismatch=The property [{0}] was set on the SSLHostConfigCertificate named [{1}] and is for certificate storage type [{2}] but the certificate is being used with a storage of type [{3}]
|
||||
|
||||
sslImplementation.cnfe=Unable to create SSLImplementation for class [{0}]
|
||||
|
||||
sslUtilBase.active=The [{0}] that are active are : [{1}]
|
||||
sslUtilBase.noneSupported=None of the [{0}] specified are supported by the SSL engine : [{1}]
|
||||
sslUtilBase.skipped=Some of the specified [{0}] are not supported by the SSL engine and have been skipped: [{1}]
|
||||
48
java/org/apache/tomcat/util/net/LocalStrings_de.properties
Normal file
48
java/org/apache/tomcat/util/net/LocalStrings_de.properties
Normal file
@@ -0,0 +1,48 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
channel.nio.ssl.sniDefault=Puffer ist nicht groß genug um den angefragten SNI Host-Namen zu ermitteln. Benutze den Standard Wert
|
||||
channel.nio.ssl.sniHostName=Aus Verbindung [{0}] konnte der SNI Hostname [{1}] extrahiert werden
|
||||
channel.nio.ssl.unwrapFail=Daten können nicht entpackt werden, ungültiger Status [{0}]
|
||||
|
||||
endpoint.apr.applyConf=Wende OpenSSLConfCmd auf SSL Kontext an
|
||||
endpoint.apr.checkConf=Überprüfe OpenSSLConf
|
||||
endpoint.apr.errApplyConf=Die OpenSSLConf konnte nicht auf den Context angewandt werden
|
||||
endpoint.apr.errMakeConf=Konnte OpenSSLConf Kontext nicht erzeugen
|
||||
endpoint.apr.pollAddInvalid=Ungültiger Versuch einen Socket [{0}] zum Poller hinzuzufügen
|
||||
endpoint.apr.tooManyCertFiles=Es wurden mehr Zertifikatsdateien konfiguriert als ein APR Endpunkt handhaben kann
|
||||
endpoint.debug.channelCloseFail=Kanal konnte nicht geschlossen werden
|
||||
endpoint.debug.socketCloseFail=Socket konnte nicht geschlossen werden
|
||||
endpoint.init.bind=Binden des Sockets fehlgeschlagen: [{0}] [{1}]
|
||||
endpoint.init.notavail=APR nicht verfügbar
|
||||
endpoint.noSslHostName=Es wurde kein Hostname für die SSL Host Konfiguration angegeben
|
||||
endpoint.poll.limitedpollsize=Konnte Poller mit der angegebenen Große von [{0}] nicht erzeugen
|
||||
endpoint.removeDefaultSslHostConfig=Die Standard SSLHostConfig (namens [{0}]) darf nicht entfernt werden
|
||||
endpoint.sendfile.addfail=Sendfile-Fehler: [{0}][{1}]
|
||||
endpoint.sendfile.error=Unerwarteter sendfile-Fehler
|
||||
endpoint.serverSocket.closeFailed=Konnte Server Socket für [{0}] nicht schliessen
|
||||
endpoint.setAttribute=Setze [{0}] auf [{1}]
|
||||
endpoint.warn.incorrectConnectionCount=Falsche Verbindungsanzahl, mehrere socket.close-Aufrufe auf dem gleichen Socket
|
||||
endpoint.warn.noLocalName=Lokaler Hostname für Socket [{0}] konnte nicht ermittelt werden
|
||||
|
||||
jsse.ssl3=SSLv3 wurde explizit eingeschalten. Dieses Protokoll ist als unsicher bekannt.
|
||||
|
||||
socket.apr.closed=Der zu dieser Verbindung gehörende Socket [{0}] wurde geschlossen.
|
||||
|
||||
sslHostConfig.certificate.notype=Es wurden mehrere Zertifikate angegeben und mindestens einem fehlt ein erforderlicher Attributs Typ
|
||||
sslHostConfig.fileNotFound=Die konfigurierte Datei [{0}] existiert nicht.\n
|
||||
sslHostConfig.opensslconf.null=Versuch eine null OpenSSLConf zu setzen ignoriert
|
||||
|
||||
sslUtilBase.noneSupported=Keine der spezifizierten [{0}] wird von der SSL Engine unterstützt: [{1}]
|
||||
75
java/org/apache/tomcat/util/net/LocalStrings_es.properties
Normal file
75
java/org/apache/tomcat/util/net/LocalStrings_es.properties
Normal file
@@ -0,0 +1,75 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
channel.nio.ssl.notHandshaking=NOT_HANDSHAKING durante el handshake
|
||||
channel.nio.ssl.sniDefault=Imposible almacenar los datos suficientes para determinar el SNI del host solicitado. Utilizando el default
|
||||
channel.nio.ssl.sniHostName=El nombre del servidor (SNI) extraído de la conexión [{0}] es [{1}]
|
||||
channel.nio.ssl.unexpectedStatusDuringWrap=Estado inesperado [{0}] durante el handshake WRAP.\n
|
||||
channel.nio.ssl.unwrapFail=Incapáz de desenvolver los datos, estatus no válido [{0}]\n
|
||||
|
||||
endpoint.accept.fail=Aceptación de conector falló
|
||||
endpoint.apr.applyConf=Aplicando OpenSSLConfCmd al contexto SSL
|
||||
endpoint.apr.checkConf=Verificando OpenSSLConf
|
||||
endpoint.apr.errMakeConf=No se pudo crear el contexto OpenSSLConf\n
|
||||
endpoint.apr.invalidSslProtocol=Se ha proporcionado un valor inválido [{0}] para el atributo SSLProtocol
|
||||
endpoint.apr.maxConnections.running=El endpoint APR no soporta cambiar el parámetro maxConnections mientras está corriendo. Se continuará usando el valor existente [{0}].
|
||||
endpoint.apr.pollAddInvalid=Intento no válido de adicionar el socket [{0}] a la encuesta\n
|
||||
endpoint.apr.tooManyCertFiles=Fueron configurados más archivos de ceritificados que los que AprEndpoint puede manejar
|
||||
endpoint.debug.channelCloseFail=No puede cerrar el canal
|
||||
endpoint.debug.socketCloseFail=No pude cerrar el enchufe (socket)
|
||||
endpoint.debug.unlock.fail=Excepción cogida intentando desbloquear aceptación en puerto [{0}]
|
||||
endpoint.err.close=Excepción cogida intentando cerrar conector
|
||||
endpoint.err.handshake=Acuerdo fallido
|
||||
endpoint.err.unexpected=Error inesperado al procesar conector
|
||||
endpoint.init.bind=Ligado de conector falló: [{0}] [{1}]
|
||||
endpoint.init.listen=Escucha de conector falló: [{0}] [{1}]
|
||||
endpoint.init.notavail=APR no disponible
|
||||
endpoint.invalidJmxNameSslHostCert=\n\
|
||||
Imposible generar un nombre de objeto JMX válido para el SSLHostConfigCertificate asociado con el servidor [{0}] y el tipo de certificado [{1}]\n
|
||||
endpoint.jsse.noSslContext=No se encontró ningún conexto SSLContext para el hostname [{0}]\n
|
||||
endpoint.nio.stopLatchAwaitInterrupted=Este hilo fue interrumpido mientras esperaba porque los encuestadores se detuvieran
|
||||
endpoint.noSslHostConfig=No se encontró elemento SSLHostConfig con nombre de máquina [{0}] para machear el defaultSSLHostConfigName para el conector [{1}]\n
|
||||
endpoint.noSslHostName=No se proveió un nombre de host para la configuración SSL
|
||||
endpoint.poll.error=Error inesperado de encuestador
|
||||
endpoint.poll.fail=Fallo crítico de encuestador (reiniciando encuestador): [{0}] [{1}]
|
||||
endpoint.poll.initfail=Falló la creación del encuestador
|
||||
endpoint.poll.limitedpollsize=No pude crear encuestador de medida específica de [{0}]
|
||||
endpoint.process.fail=Error reservando procesador de conector
|
||||
endpoint.sendfile.addfail=Fallo en Sendfile: [{0}] [{1}]
|
||||
endpoint.sendfile.error=Error inesperado de envío de fichero
|
||||
endpoint.serverSocket.closeFailed=Fallo al cerrar el socket del servidor para [{0}]
|
||||
endpoint.setAttribute=Fijando [{0}] a [{1}]\n
|
||||
endpoint.warn.executorShutdown=El ejecutor asociado con el hilo del pool [{0}] no fue totalmente apagado. Algunos hilos de la aplicación pudieran estar corriendo aún.
|
||||
endpoint.warn.incorrectConnectionCount=Conteo de conexión errónea, hay varias llamadas a socket.close en el mismo socket
|
||||
endpoint.warn.noLocalName=Imposible determinar el nombre de la máquina local para el socket [{0}]\n
|
||||
endpoint.warn.noLocalPort=Uncapaz de determinar el puerto local para el socket [{0}]\n
|
||||
endpoint.warn.unlockAcceptorFailed=El hilo aceptador [{0}] falló al desbloquear. Forzando apagado de enchufe (socket).
|
||||
|
||||
jsse.invalid_truststore_password=La clave del almacén de confianza suministrada no se pudo usar para desbloquear y/o validar el almacén de confianza. Reintentando acceder el almacén de confianza con una clave nula que se saltará la validación.
|
||||
jsse.keystore_load_failed=No pude cargar almacén de claves de tipo [{0}] con ruta [{1}] debido a [{2}]
|
||||
jsse.ssl3=SSLv3 ha sido explicitamente habilitado. Se conoce que este protocolo es inseguro
|
||||
|
||||
sniExtractor.clientHelloTooBig=El ClientHello no fue presentado en un sólo registro TLS por lo cual no se pudo extraer la información SNI
|
||||
|
||||
socket.apr.closed=El socket [{0}] asociado con esta conexión ha sido cerrado.
|
||||
socket.sslreneg=Excepción renegociando la conexión SSL
|
||||
|
||||
sslHostConfig.certificate.notype=Se especificaron multiples certificados y al menos uno de ellos no tiene el tipo de atributo requerido
|
||||
sslHostConfig.fileNotFound=No existe el archivo configurado [{0}]
|
||||
sslHostConfig.opensslconf.null=El intento de fijar OpenSSLConf en nulo fue ignorado
|
||||
|
||||
sslImplementation.cnfe=Incapaz de crear SSLImplementation para la clase [{0}]
|
||||
|
||||
sslUtilBase.noneSupported=Ninguno de los [{0}] especificados es soportado por el motor SSL : [{1}]
|
||||
153
java/org/apache/tomcat/util/net/LocalStrings_fr.properties
Normal file
153
java/org/apache/tomcat/util/net/LocalStrings_fr.properties
Normal file
@@ -0,0 +1,153 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
channel.nio.interrupted=Le thread en cours a été interrompu
|
||||
channel.nio.ssl.appInputNotEmpty=Le tampon d'entrée de l'application contient toujours des données, des données ont été perdues
|
||||
channel.nio.ssl.appOutputNotEmpty=Le tampon de sortie de l'application contient toujours des données, des données ont été perdues
|
||||
channel.nio.ssl.closeSilentError=Il y a eu une exception en essayant de fermer proprement la connection, comme prévu
|
||||
channel.nio.ssl.closing=Le canal est en état de fermeture
|
||||
channel.nio.ssl.eofDuringHandshake=EOF pendant la négociation
|
||||
channel.nio.ssl.expandNetInBuffer=Augmentation de la taille du tampon d''entrée réseau à [{0}] octets
|
||||
channel.nio.ssl.expandNetOutBuffer=Augmentation de la taille du tampon de sortie réseau à [{0}] octets
|
||||
channel.nio.ssl.foundHttp=Une requête HTTP non cryptée a été trouvée sur la connection qui aurait dû être cryptée par TLS
|
||||
channel.nio.ssl.handshakeError=Erreur lors de la négociation
|
||||
channel.nio.ssl.incompleteHandshake=La négociation est incomplète, elle doit être terminée pour pouvoir lire des données
|
||||
channel.nio.ssl.invalidCloseState=Etat de fermeture invalide, aucune donnée ne sera envoyée sur le réseau
|
||||
channel.nio.ssl.invalidStatus=Etat inattendu [{0}]
|
||||
channel.nio.ssl.netInputNotEmpty=Le tampon d'entrée du réseau contient toujours des données, la négociation va échouer
|
||||
channel.nio.ssl.netOutputNotEmpty=Le tampon de sortie du réseau contient toujours des données, la négociation va échouer
|
||||
channel.nio.ssl.notHandshaking=NOT_HANDSHAKING pendant la négociation SSL
|
||||
channel.nio.ssl.pendingWriteDuringClose=Une écriture est en cours donc des données sont toujours présentes dans le tampon réseau, impossible d'envoyer le message de fermeture de SSL mais le socket sera fermé de toutes manières
|
||||
channel.nio.ssl.remainingDataDuringClose=Des données sont toujours présentes dans le tampon réseau, impossible d'envoyer le message de fermeture de SSL mais le socket sera fermé de toutes manières
|
||||
channel.nio.ssl.sniDefault=Incapacité d'accumuler assez d'information pour déterminer le nom du hôte SNI demandé. Valeur par défaut utilisée.
|
||||
channel.nio.ssl.sniHostName=Le nom d''hôte SNI extrait pour la connexion [{0}] est [{1}]
|
||||
channel.nio.ssl.timeoutDuringHandshake=Timeout pendant la négociation
|
||||
channel.nio.ssl.unexpectedStatusDuringUnwrap=Statut inattendu [{0}] lors de l''UNWRAP de la négociation
|
||||
channel.nio.ssl.unexpectedStatusDuringWrap=Statut inattendu [{0}] lors du WRAP de la négociation
|
||||
channel.nio.ssl.unwrapFail=Incapable de désenrober les données ("unwrap data"), statut invalide [{0}]
|
||||
channel.nio.ssl.unwrapFailResize=Impossible de faire l''unwrap des données parce que le tampon est trop petit, statut invalide [{0}]
|
||||
channel.nio.ssl.wrapException=La négociation a échouée pendant le wrap
|
||||
channel.nio.ssl.wrapFail=Impossible d''enrober (wrap) les données, le status est invalide [{0}]
|
||||
|
||||
endpoint.accept.fail=Aucun socket n'a pu être accepté
|
||||
endpoint.alpn.fail=Erreur de configuration de la terminaison pour ALPN en utilisant [{0}]
|
||||
endpoint.alpn.negotiated=Le protocole [{0}] a été négocié en utilisant ALPN
|
||||
endpoint.apr.applyConf=Application de OpenSSLConfCmd au contexte SSL
|
||||
endpoint.apr.checkConf=Vérification de OpenSSLConf en cours
|
||||
endpoint.apr.errApplyConf=Impossible d'appliquer OpenSSLConf au contexte SSL
|
||||
endpoint.apr.errCheckConf=Erreur pendant la vérification de OpenSSLConf
|
||||
endpoint.apr.errMakeConf=Impossible de créer le contexte de OpenSSLConf
|
||||
endpoint.apr.failSslContextMake=Incapable de créer un SSLContext. Vérifier que SSLEngine est activé dans l'AprLifecycleListener, que l'AprLifecycleListener a été correctement initialisé et qu'un protocole SSL valide a été spécifié.
|
||||
endpoint.apr.invalidSslProtocol=Un valeur invalide [{0}] a été donnée pour l''attribut SSLProtocol
|
||||
endpoint.apr.maxConnections.running=La terminaison APR ne permet pas de fixer maxConnections pendant son exécution, la valeur existante [{0}] continuera à être utilisée
|
||||
endpoint.apr.maxConnections.unlimited=La terminaison APR ne supporte pas un nombre illimité de connections, la valeur existante [{0}] va continuer à être utilisée
|
||||
endpoint.apr.noSendfileWithSSL=Sendfile n'est pas supporté avec le connecteur APR lorsque SSL est active
|
||||
endpoint.apr.pollAddInvalid=Tentative invalide d''ajout d''une socket [{0}] au scrutateur ("poller")
|
||||
endpoint.apr.pollError=Le scrutateur ("poller") a échoué avec l''erreur [{0}] : [{1}]
|
||||
endpoint.apr.pollMergeEvents=Fusion des évènements [{1}] du poller pour le socket [{0}] pour créer l''évènement fusionné [{2}]
|
||||
endpoint.apr.pollUnknownEvent=Un socket a été retourné par le poller avec un évènement inconnu [{0}]
|
||||
endpoint.apr.remoteport=Le socket APR [{0}] a été ouvert avec le port distant [{1}]
|
||||
endpoint.apr.tooManyCertFiles=Plus de fichiers de certificats ont été configurés que ce que l'AprEndpoint peut gérer
|
||||
endpoint.debug.channelCloseFail=Echec de la fermeture du canal (channel)
|
||||
endpoint.debug.destroySocket=Destruction du socket [{0}]
|
||||
endpoint.debug.pollerAdd=Ajout à la addList socket [{0}], inactivité maximale [{1}], drapeaux [{2}]
|
||||
endpoint.debug.pollerAddDo=Ajout du socket [{0}] au poller
|
||||
endpoint.debug.pollerProcess=Traitement de(s) évènement(s) [{1}] pour la socket [{0}]
|
||||
endpoint.debug.pollerRemove=Essai d''enlever [{0}] du poller
|
||||
endpoint.debug.pollerRemoved=Enlevé [{0}] du poller
|
||||
endpoint.debug.registerRead=Enregistrement de l’intérêt en lecture pour [{0}]
|
||||
endpoint.debug.registerWrite=Enregistrement de l’intérêt en écriture pour [{0}]
|
||||
endpoint.debug.socket=socket [{0}]
|
||||
endpoint.debug.socketCloseFail=Echec de fermeture du socket
|
||||
endpoint.debug.socketTimeout=Expiration [{0}]
|
||||
endpoint.debug.unlock.fail=Reçu une exception en essayant de déverrouiller l''accepteur sur le port [{0}]
|
||||
endpoint.debug.unlock.localFail=Impossible de déterminer l''adresse locales pour [{0}]
|
||||
endpoint.debug.unlock.localNone=Impossible de débloquer l''accepteur pour [{0}] car l''adresse locale n''était pas disponible
|
||||
endpoint.duplicateSslHostName=Plusieurs éléments SSLHostConfig ont été fournis pour le nom d''hôte [{0}], les noms d''hôte doivent être uniques
|
||||
endpoint.err.close=Une exception s'est produite en essayant de fermer le socket
|
||||
endpoint.err.handshake=Echec de négociation
|
||||
endpoint.err.unexpected=Erreur inattendue lors du traitement du socket
|
||||
endpoint.executor.fail=L''exécuteur a rejeté le traitement du socket [{0}]
|
||||
endpoint.getAttribute=[{0}] est [{1}]
|
||||
endpoint.init.bind=L''association du socket a échoué: [{0}] [{1}]
|
||||
endpoint.init.bind.inherited=Pas de canal hérité alors que le connecteur était configuré pour en utiliser un
|
||||
endpoint.init.listen=L''écoute sur le socket a échoué: [{0}] [{1}]
|
||||
endpoint.init.notavail=APR n'est pas disponible
|
||||
endpoint.invalidJmxNameSslHost=Impossible de générer un nom d''objet JMX valide pour le SSLHostConfig associé à l''hôte [{0}]
|
||||
endpoint.invalidJmxNameSslHostCert=Impossible de générer un nom d''objet JMX valide pour le SSLHostConfigCertificate associé à l''hôte [{0}] et au type de certificat [{1}]
|
||||
endpoint.jmxRegistrationFailed=Echec de l''enregistrement JMX de l''objet avec le nom [{0}]
|
||||
endpoint.jsse.noSslContext=Aucun SSLContext n''a été trouvé pour le nom d''hôte [{0}]
|
||||
endpoint.launch.fail=Impossible de démarrer le nouvel exécutable
|
||||
endpoint.nio.registerFail=Echec d'enregistrement du socket avec le sélecteur du poller
|
||||
endpoint.nio.selectorCloseFail=Impossible de fermer le sélecteur lors de la fermeture du poller
|
||||
endpoint.nio.stopLatchAwaitFail=Les pollers ne se sont pas arrêtés dans le temps imparti
|
||||
endpoint.nio.stopLatchAwaitInterrupted=Ce thread a été interrompu pendant qu'il attendait l'arrêt des scrutateurs ("pollers")
|
||||
endpoint.nio.timeoutCme=Exception pendant le traitement du délai d'attente maximum; le code a été vérifié de manière répétée et aucune modification concurrence n'a pu être trouvée, si vous obtenez cette erreur de manière reproductible merci d'ouvrir un rapport d'erreur sur Tomcat en fournissant les informations pour la reproduire
|
||||
endpoint.nio2.exclusiveExecutor=Le connecteur NIO2 a besoin d'un accès exclusif à un exécuteur pour pouvoir avoir un comportement prévisible lors de son arrêt
|
||||
endpoint.noSslHostConfig=Pas d''élément SSLHostConfig trouvé avec hostName [{0}] correspondant au defaultSSLHostConfigName du connecteur [{1}]
|
||||
endpoint.noSslHostName=Aucun nom d'hôte n'a été fourni pour la configuration de l'hôte SSL
|
||||
endpoint.poll.error=Erreur inattendue du poller
|
||||
endpoint.poll.fail=Echec critique du poller, redémarrage: [{0}] [{1}]
|
||||
endpoint.poll.initfail=Echec de création du poller
|
||||
endpoint.poll.limitedpollsize=Echec de création d''un poller avec la taille spécifiée [{0}]
|
||||
endpoint.process.fail=Erreur lors de l'allocation d'un processeur de socket
|
||||
endpoint.processing.fail=Erreur lors de l’exécution du processeur du socket
|
||||
endpoint.removeDefaultSslHostConfig=Le SSLHostConfig par défaut (de nom [{0}]) ne peut pas être retiré
|
||||
endpoint.sendfile.addfail=Echec de Sendfile: [{0}] [{1}]
|
||||
endpoint.sendfile.error=Erreur lors de sendfile
|
||||
endpoint.serverSocket.closeFailed=Le socket serveur [{0}] n''a pas pu être fermé
|
||||
endpoint.setAttribute=Met [{0}] à [{1}]
|
||||
endpoint.timeout.err=Erreur en traitant le dépassement de temps d'attente du socket
|
||||
endpoint.unknownSslHostName=Le nom d''hôte SSL [{0}] n''est pas reconnu pour cette terminaison
|
||||
endpoint.warn.executorShutdown=L''exécuteur associé au pool de threads [{0}] n''est pas complètement arrêté, certains threads d''application peuvent toujours être en cours d''exécution
|
||||
endpoint.warn.incorrectConnectionCount=Le décompte du nombre de connections est incorrect, la méthode de fermeture d'un même socket a été appelée plusieurs fois
|
||||
endpoint.warn.noLocalAddr=Impossible de déterminer l''addresse locale pour le socket [{0}]
|
||||
endpoint.warn.noLocalName=Incapable de déterminer l''hôte local ("local host") pour la socket [{0}]
|
||||
endpoint.warn.noLocalPort=Impossible de déterminer le port local pour le socket [{0}]
|
||||
endpoint.warn.noRemoteAddr=Impossible de déterminer l''adresse distante pour le socket [{0}]
|
||||
endpoint.warn.noRemoteHost=Impossible de déterminer le nom d''hôte distant pour le socket [{0}]
|
||||
endpoint.warn.noRemotePort=Impossible de déterminer le port distant pour le socket [{0}]
|
||||
endpoint.warn.unlockAcceptorFailed=Le thread qui accepte les sockets [{0}] n''a pu être débloqué, arrêt forcé su socket serveur
|
||||
|
||||
jsse.invalid_truststore_password=Le mot de passe de la base de confiance n'a pas pu être utilisé pour déverrouiller et ou valider celle ci, nouvel essai en utilisant un mot de passe null pour passer la validation
|
||||
jsse.keystore_load_failed=Impossible de changer la base de clés de type [{0}] avec le chemin [{1}] à cause de [{2}]
|
||||
jsse.ssl3=SSLv3 a été explicitement activé. Ce protocole est connu comme non-sécurisé.
|
||||
jsse.tls13.auth=L’implémentation JSSE de TLS 1.3 ne supporte pas l'authentification après la négociation initiale, elle est donc incompatible avec l’authentification optionnelle du client
|
||||
|
||||
sniExtractor.clientHelloInvalid=Le message ClientHello n'était pas formaté correctement
|
||||
sniExtractor.clientHelloTooBig=Le ClientHello n'a pas été présenté dans un seul enregistrement TLS donc l'information SNI n'a pu être extraite
|
||||
|
||||
socket.apr.clientAbort=Le client a avorté la connection
|
||||
socket.apr.closed=Le socket [{0}] associé avec cete connection a été fermé.
|
||||
socket.apr.read.error=Erreur inattendue [{0}] lors de la lecture de données depuis le socket APR [{1}] avec l''enrobeur [{2}]
|
||||
socket.apr.write.error=Erreur inattendue [{0}] lors de l''écriture de données vers le socket APR [{1}] avec l''enrobeur [{2}]
|
||||
socket.closed=Le socket associé à cette connection a été fermé
|
||||
socket.sslreneg=Exception lors de la renégociation de la connection SSL
|
||||
|
||||
sslHostConfig.certificate.notype=Plusieurs certificats ont été spécifiés et au moins un n'a pas d'attribut type
|
||||
sslHostConfig.certificateVerificationInvalid=La valeur de vérification de certificat [{0}] n''est pas reconnue
|
||||
sslHostConfig.fileNotFound=Le fichier [{0}] configuré n''existe pas.
|
||||
sslHostConfig.mismatch=La propriété [{0}] a été fixée sur le SSLHostConfig nommé [{1}] et est pour la syntaxe de configuration [{2}] mais le SSLHostConfig est utilisé avec la syntaxe de configuration [{3}]
|
||||
sslHostConfig.opensslconf.alreadyset=Un tentative de fixer une autre OpenSSLConf a été ignorée
|
||||
sslHostConfig.opensslconf.null=L'OpenSSLConf nul a été ignoré
|
||||
sslHostConfig.prefix_missing=Le protocole [{0}] a été ajouté à la liste des protocoles du SSLHostConfig nommé [{1}], vérifier qu''un préfixe +/- ne manque pas
|
||||
|
||||
sslHostConfigCertificate.mismatch=La propriété [{0}] a été définie sur le SSLHostConfigCertificate nommé [{1}] et est pour un certificat de stockage de type [{2}] mais le certificat est utilisé avec un stockage de type [{3}]
|
||||
|
||||
sslImplementation.cnfe=Impossible de créer une SSLImplementation avec la class [{0}]
|
||||
|
||||
sslUtilBase.active=Les [{0}] qui sont actifs sont: [{1}]
|
||||
sslUtilBase.noneSupported=Aucun des [{0}] spécifiés n''est supporté par le moteur SSL : [{1}]
|
||||
sslUtilBase.skipped=Quelques [{0}] spécifiés ne sont pas supportés par le moteur SSL et ont été ignorés: [{1}]
|
||||
151
java/org/apache/tomcat/util/net/LocalStrings_ja.properties
Normal file
151
java/org/apache/tomcat/util/net/LocalStrings_ja.properties
Normal file
@@ -0,0 +1,151 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
channel.nio.interrupted=現在のスレッドが中断されました
|
||||
channel.nio.ssl.appInputNotEmpty=アプリケーションの入力バッファにはデータが残っています。残ったデータは失われます。
|
||||
channel.nio.ssl.appOutputNotEmpty=アプリケーション出力バッファにはまだデータが含まれています。 データは失われました。
|
||||
channel.nio.ssl.closeSilentError=コネクションを丁寧に切断しようとしましたが例外が発生しました。
|
||||
channel.nio.ssl.closing=チャネルはクロージング状態です
|
||||
channel.nio.ssl.eofDuringHandshake=ハンドシェイク中のEOF。
|
||||
channel.nio.ssl.expandNetInBuffer=ネットワーク入力バッファを[{0}]バイトに拡張しています
|
||||
channel.nio.ssl.expandNetOutBuffer=ネットワーク出力バッファを[{0}]バイトに拡張します
|
||||
channel.nio.ssl.foundHttp=暗号化された TLS 接続から平文の HTTP リクエストを受信しました。
|
||||
channel.nio.ssl.handshakeError=ハンドシェイクエラー
|
||||
channel.nio.ssl.incompleteHandshake=ハンドシェイクが不完全です。データを読み取る前にハンドシェイクを完了する必要があります。
|
||||
channel.nio.ssl.invalidCloseState=無効なクローズ状態で、ネットワークデータを送信しません。
|
||||
channel.nio.ssl.invalidStatus=予期しないステータス[{0}]。
|
||||
channel.nio.ssl.netInputNotEmpty=ネットワーク入力バッファにはまだデータが含まれています。 ハンドシェイクは失敗します。
|
||||
channel.nio.ssl.netOutputNotEmpty=ネットワーク出力バッファにはまだデータが含まれています。 ハンドシェイクは失敗します。
|
||||
channel.nio.ssl.notHandshaking=ハンドシェイク中にNOT_HANDSHAKING
|
||||
channel.nio.ssl.pendingWriteDuringClose=書き込みを保留しているためネットワークバッファーにデータが残っています。SSL 切断メッセージを送信できません。代わりに close(true) で強制的に切断してください。
|
||||
channel.nio.ssl.remainingDataDuringClose=ネットワークバッファ内にデータが残っていて、SSLクローズメッセージを送信できません。代わりにclose(true)でクローズします。
|
||||
channel.nio.ssl.sniDefault=要求された SNI ホスト名を取得するために十分なデータを蓄積できないため初期値を使用します。
|
||||
channel.nio.ssl.sniHostName=コネクション [{0}] から取得した SNI ホスト名は [{1}] です。
|
||||
channel.nio.ssl.timeoutDuringHandshake=ハンドシェイクがタイムアウトしました。
|
||||
channel.nio.ssl.unexpectedStatusDuringUnwrap=UNWRAPハンドシェイク中に予期しないステータス[{0}]が発生しました。
|
||||
channel.nio.ssl.unexpectedStatusDuringWrap=ハンドシェイクWRAP中に予期しないステータス[{0}]が発生しました。
|
||||
channel.nio.ssl.unwrapFail=データをアンラップできません、無効なステータス[{0}]
|
||||
channel.nio.ssl.unwrapFailResize=バッファが小さすぎるためデータをアンラップできません。無効なステータス[{0}]
|
||||
channel.nio.ssl.wrapException=ラップ中にハンドシェイクに失敗しました
|
||||
channel.nio.ssl.wrapFail=データをラップできません。無効なステータス[{0}]
|
||||
|
||||
endpoint.accept.fail=ソケット受け付け失敗
|
||||
endpoint.alpn.fail=[{0}]を使用してALPNのエンドポイントを設定できませんでした。
|
||||
endpoint.alpn.negotiated=ALPNを使用して交渉された[{0}]プロトコル
|
||||
endpoint.apr.applyConf=OpenSSLConfCmdを SSL contextに適用します。
|
||||
endpoint.apr.checkConf=OpenSSLConfの確認中
|
||||
endpoint.apr.errApplyConf=OpenSSLConfをSSLコンテキストに適用できませんでした。
|
||||
endpoint.apr.errCheckConf=OpenSSLConfチェック中のエラー
|
||||
endpoint.apr.errMakeConf=OpenSSLConfコンテキストを作成できませんでした。
|
||||
endpoint.apr.failSslContextMake=SSLContextを作成できません。 SSLEngineがAprLifecycleListenerで有効になっていること、AprLifecycleListenerが正しく初期化されていること、有効なSSLProtocolが指定されていることを確認して下さい
|
||||
endpoint.apr.invalidSslProtocol=SSLProtocol属性に無効な値[{0}]が指定されました
|
||||
endpoint.apr.maxConnections.running=APR エンドポイントは実行中に maxConnection の値を変更できません。現在の値 [{0}] をそのまま使用します。
|
||||
endpoint.apr.maxConnections.unlimited=APRエンドポイントは、無制限の接続をサポートしていません。 [{0}]の既存の値は引き続き使用されます。
|
||||
endpoint.apr.noSendfileWithSSL=SSLが有効な場合、APR /nativeコネクタでSendfileはサポートされていません。
|
||||
endpoint.apr.pollAddInvalid=ソケット [{0}] をポーラーに追加できませんでした。
|
||||
endpoint.apr.pollError=Pollerはエラー[{0}]で失敗しました:[{1}]
|
||||
endpoint.apr.pollMergeEvents=ソケット[{0}]のpoller イベント[{1}]をマージして、マージイベント[{2}]を作成。
|
||||
endpoint.apr.pollUnknownEvent=認識できないイベント[{0}]を持つソケットがPollerから返されました。
|
||||
endpoint.apr.remoteport=APR ソケット [{0}] はリモートポート [{1}] へ接続しました。
|
||||
endpoint.apr.tooManyCertFiles=Apr エンドポイントに処理できるより多い証明書ファイルが構成されています。
|
||||
endpoint.debug.channelCloseFail=チャンネルを切断できませんでした。
|
||||
endpoint.debug.destroySocket=ソケット [{0}] を破棄します。
|
||||
endpoint.debug.pollerAdd=addListに追加、ソケット[{0}]、タイムアウト[{1}]、フラグ[{2}]
|
||||
endpoint.debug.pollerAddDo=Pollerソケット[{0}]に追加
|
||||
endpoint.debug.pollerProcess=イベント[{1}]のソケット[{0}]の処理中
|
||||
endpoint.debug.pollerRemove=Pollerから[{0}]を取り除こうとしています。
|
||||
endpoint.debug.pollerRemoved=poller から [{0}] を削除しました。
|
||||
endpoint.debug.socket=ソケット[{0}]
|
||||
endpoint.debug.socketCloseFail=ソケットを切断できませんでした。
|
||||
endpoint.debug.socketTimeout=タイムアウト [{0}]
|
||||
endpoint.debug.unlock.fail=port [{0}]のaccept をロック解除しようした際に例外が発生しました。
|
||||
endpoint.debug.unlock.localFail=[{0}]のローカルアドレスを特定できません
|
||||
endpoint.debug.unlock.localNone=ローカルアドレスが利用できなかったため、[{0}]のアクセプタのロックを解除できませんでした。
|
||||
endpoint.duplicateSslHostName=ホスト名[{0}]に複数のSSLHostConfig要素が提供されました。 ホスト名は一意でなければなりません。
|
||||
endpoint.err.close=ソケットをクローズしようとした際に例外が発生しました
|
||||
endpoint.err.handshake=ハンドシェイク失敗
|
||||
endpoint.err.unexpected=ソケットの処理中に予期せぬエラーが発生しました。
|
||||
endpoint.executor.fail=エグゼキュータは処理するソケット[{0}]を拒否しました。
|
||||
endpoint.getAttribute=[{0}]は[{1}]です
|
||||
endpoint.init.bind=ソケットバインドに失敗しました:[{0}] [{1}]
|
||||
endpoint.init.bind.inherited=コネクタが1つを使用するように構成されている間、継承されたチャネルはありません。
|
||||
endpoint.init.listen=ソケットの待ち受けを開始できません: [{0}] [{1}]
|
||||
endpoint.init.notavail=APRは利用できません
|
||||
endpoint.invalidJmxNameSslHost=ホスト [{0}] に対応付けられた SSLHostConfig に正常な JMX オブジェクト名を生成できません。
|
||||
endpoint.invalidJmxNameSslHostCert=ホスト名 [{0}]、証明書タイプ [{1}] の SSLHostConfigCertificate のための正常な JMX オブジェクト名を生成できませんでした。
|
||||
endpoint.jmxRegistrationFailed=名前 [{0}] の JMX オブジェクトを登録できませんでした。
|
||||
endpoint.jsse.noSslContext=ホスト名[{0}]のSSLContextが見つかりませんでした
|
||||
endpoint.launch.fail=new Runnableの起動に失敗しました
|
||||
endpoint.nio.registerFail=Pollerからソケットのセレクタに登録できませんでした。
|
||||
endpoint.nio.selectorCloseFail=Pollerを閉じるときにセレクターを閉じることができませんでした。
|
||||
endpoint.nio.stopLatchAwaitFail=Pollerは予想された時間内に止まりませんでした
|
||||
endpoint.nio.stopLatchAwaitInterrupted=このスレッドはPollerが停止するのを待つ間に中断されました
|
||||
endpoint.nio.timeoutCme=タイムアウトの処理中の例外。 コードは繰り返しチェックされており、同時に変更されていません。 このエラーを繰り返すことができる場合は、Tomcatのバグを開いて、再現手順を提示してください。
|
||||
endpoint.nio2.exclusiveExecutor=NIO2コネクタはシャットダウン時に排他的エグゼキュータを正しく動作させる必要があります。
|
||||
endpoint.noSslHostConfig=コネクタ[{1}]のdefaultSSLHostConfigName に一致するSSLHostConfig要素がhostName [{0}]で見つかりませんでした
|
||||
endpoint.noSslHostName=SSL のホスト設定にホスト名がありません。
|
||||
endpoint.poll.error=予期しないpoller エラー
|
||||
endpoint.poll.fail=重大なPoller障害(Pollerの再始動):[{0}] [{1}]
|
||||
endpoint.poll.initfail=Pollerの作成に失敗しました。
|
||||
endpoint.poll.limitedpollsize=サイズ [{0}] の Poller インスタンスを作成できません。
|
||||
endpoint.process.fail=ソケットプロセッサーの割り当て中にエラーが発生しました。
|
||||
endpoint.processing.fail=ソケットプロセッサの実行中エラー
|
||||
endpoint.removeDefaultSslHostConfig=デフォルトのSSLHostConfig([{0}])は削除できません
|
||||
endpoint.sendfile.addfail=Sendfile 失敗: [{0}] [{1}]
|
||||
endpoint.sendfile.error=sendfile の送信中に予期せぬ異常が発生しました。
|
||||
endpoint.serverSocket.closeFailed=[{0}] によりサーバーソケットの切断に失敗しました。
|
||||
endpoint.setAttribute=[{0}]を[{1}]に設定
|
||||
endpoint.timeout.err=ソケットタイムアウトの処理エラー
|
||||
endpoint.unknownSslHostName=SSL ホスト名 [{0}] はこのエンドポイントから認識されていません。
|
||||
endpoint.warn.executorShutdown=スレッドプール [{0}] と関連付けられたエグゼキュターは完全に停止できませんでした。アプリケーションスレッドは実行し続ける可能性がありますり。
|
||||
endpoint.warn.incorrectConnectionCount=不正なコネクション数。複数のsocket.closeが同じソケットで呼び出されました。
|
||||
endpoint.warn.noLocalAddr=ソケット [{0}] のローカルアドレスを取得できません。
|
||||
endpoint.warn.noLocalName=ソケット [{0}] のローカルホスト名を取得できません。
|
||||
endpoint.warn.noLocalPort=ソケット [{0}] のローカルポートが取得できません。
|
||||
endpoint.warn.noRemoteAddr=ソケット [{0}] のリモートアドレスを取得できません。
|
||||
endpoint.warn.noRemoteHost=ソケット [{0}] のリモートホスト名を取得できません。
|
||||
endpoint.warn.noRemotePort=ソケット[{0}] のリモートポート番号を取得できません。
|
||||
endpoint.warn.unlockAcceptorFailed=Acceptor スレッド[{0}]のロックを解除できませんでした。 強制的にハードソケットをシャットダウンします。
|
||||
|
||||
jsse.invalid_truststore_password=提供されたトラストストアパスワードは、トラストストアのロック解除および検証に使用できませんでした。 検証をスキップするnullパスワードでトラストストアにアクセスしようとしました。
|
||||
jsse.keystore_load_failed=[{0}] のキーストア [{1}] の読み込みは [{2}] により失敗しました。
|
||||
jsse.ssl3=SSLv3 が明示的に有効化化されています。このプロトコルは安全ではありません。
|
||||
jsse.tls13.auth=JSSE TLS 1.3実装は、初期ハンドシェイク後の認証をサポートしていないため、オプションのクライアント認証と互換性がありません。
|
||||
|
||||
sniExtractor.clientHelloInvalid=ClientHelloメッセージが正しくフォーマットされていません。
|
||||
sniExtractor.clientHelloTooBig=ClientHelloは単一のTLSレコードには表示されないため、SNI情報は抽出できませんでした
|
||||
|
||||
socket.apr.clientAbort=クライアントはコネクションを切断しました。
|
||||
socket.apr.closed=コネクションに関連付けられたソケット [{0}] はすでに切断されています。
|
||||
socket.apr.read.error=ラッパー[2]でAPR /ネイティブソケット[{1}]からのデータ読み込みで予期しないエラー[{0}]が発生しました。
|
||||
socket.apr.write.error=ラッパー [{2}] 経由で APR/native ソケット [{1}] へデータを書き込み中に予期せぬエラー [{0}] が発生しました。
|
||||
socket.closed=このコネクションに関連付けられたソケットは閉じられました。
|
||||
socket.sslreneg=SSLコネクションの再ネゴシエーション時の例外
|
||||
|
||||
sslHostConfig.certificate.notype=指定された複数の証明書の中に、少なくとも1つは必須要素の存在しない証明書が含まれています。
|
||||
sslHostConfig.certificateVerificationInvalid=証明書検証値[{0}]が認識されません
|
||||
sslHostConfig.fileNotFound=構成ファイル[{0}]は存在しません
|
||||
sslHostConfig.mismatch=[{0}]プロパティは[{1}]という名前のSSLHostConfigで設定され、[{2}]構成構文用ですが、[{3}]構成構文でSSLHostConfigが使用されています。
|
||||
sslHostConfig.opensslconf.alreadyset=別のOpenSSLConfを設定しようとする試みが無視されます。
|
||||
sslHostConfig.opensslconf.null=Null OpenSSLConfを設定しようとしましたが無視されました
|
||||
sslHostConfig.prefix_missing=[{1}]というSSLHostConfigのプロトコルのリストにプロトコル[{0}]が追加されました。 +/-接頭辞がないか確認してください。
|
||||
|
||||
sslHostConfigCertificate.mismatch=プロパティ[{0}]は[{1}]という名前のSSLHostConfigCertificateに設定されており、証明書の格納タイプ[{2}]用ですが、証明書は[{3}]タイプのストレージで使用されています。
|
||||
|
||||
sslImplementation.cnfe=クラス [{0}] のインスタンスを SSLImplementation として作成できません。
|
||||
|
||||
sslUtilBase.active=アクティブな[{0}]は次のとおりです:[{1}]
|
||||
sslUtilBase.noneSupported=指定された[{0}]のどれもSSLエンジンでサポートされていません:[{1}]
|
||||
sslUtilBase.skipped=指定された[{0}]の一部はSSLエンジンでサポートされておらず、スキップされています:[{1}]
|
||||
153
java/org/apache/tomcat/util/net/LocalStrings_ko.properties
Normal file
153
java/org/apache/tomcat/util/net/LocalStrings_ko.properties
Normal file
@@ -0,0 +1,153 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
channel.nio.interrupted=현재 쓰레드가 중단되었습니다.
|
||||
channel.nio.ssl.appInputNotEmpty=애플리케이션 입력 버퍼가 여전히 데이터를 포함하고 있습니다. 데이터를 잃을 뻔했습니다.
|
||||
channel.nio.ssl.appOutputNotEmpty=애플리케이션 출력 버퍼가 여전히 데이터를 포함하고 있습니다. 데이터를 잃을 뻔했습니다.
|
||||
channel.nio.ssl.closeSilentError=이미 예상했던대로, 연결을 깨끗하게 닫으려 시도하던 중 예외 발생이 있었습니다.
|
||||
channel.nio.ssl.closing=채널이 닫는 중 상태에 있습니다.
|
||||
channel.nio.ssl.eofDuringHandshake=Handshake 하는 동안 EOF 발생
|
||||
channel.nio.ssl.expandNetInBuffer=네트워크 입력 버퍼를 [{0}] 바이트 크기로 확장합니다.
|
||||
channel.nio.ssl.expandNetOutBuffer=네트워크 출력 버퍼를 [{0}] 바이트 크기로 확장합니다.
|
||||
channel.nio.ssl.foundHttp=암호화된 TLS 연결이어야 하는 곳에서, plain 텍스트 HTTP 요청이 발견되었습니다.
|
||||
channel.nio.ssl.handshakeError=Handshake 오류
|
||||
channel.nio.ssl.incompleteHandshake=Handshake가 완료되지 않았습니다. 데이터를 읽기 전 반드시 handshake를 완료해야 합니다.
|
||||
channel.nio.ssl.invalidCloseState=유효하지 않은, 닫힘 상태입니다. 네트워크 데이터를 보내지 않을 것입니다.
|
||||
channel.nio.ssl.invalidStatus=예기치 않은 상태 [{0}].
|
||||
channel.nio.ssl.netInputNotEmpty=네트워크 입력 버퍼가 여전히 데이터를 포함하고 있습니다. Handshake가 실패할 것입니다.
|
||||
channel.nio.ssl.netOutputNotEmpty=네트워크 출력 버퍼가 여전히 데이터를 포함하고 있습니다. Handshake는 실패할 것입니다.
|
||||
channel.nio.ssl.notHandshaking=Handshake 중 NOT_HANDSHAKING 발생
|
||||
channel.nio.ssl.pendingWriteDuringClose=쓰기가 진행 중이어서, 네트워크 버퍼에 데이터가 남아 있습니다. SSL 닫기 메시지를 보낼 수 없습니다. close(true)를 대신 사용하여 강제로 닫을 것입니다.
|
||||
channel.nio.ssl.remainingDataDuringClose=네트워크 버퍼에 데이터가 남아 있어, SSL 닫기 메시지를 보낼 수 없습니다. close(true)를 대신 사용하여 강제로 닫으려 합니다.
|
||||
channel.nio.ssl.sniDefault=요청된 SNI 호스트 이름을 결정하기 위한 버퍼를 충분히 채울 수 없습니다. 기본 값을 사용합니다.
|
||||
channel.nio.ssl.sniHostName=연결 [{0}]을(를) 위해 추출된 SNI 호스트 이름은 [{1}]입니다.
|
||||
channel.nio.ssl.timeoutDuringHandshake=Handshake 도중 제한 시간 초과
|
||||
channel.nio.ssl.unexpectedStatusDuringUnwrap=Handshake UNWRAP 처리 중 예기치 않은 상태: [{0}]
|
||||
channel.nio.ssl.unexpectedStatusDuringWrap=WRAP을 위해 handshake 수행 중 예기치 않은 상태 [{0}]입니다.
|
||||
channel.nio.ssl.unwrapFail=데이터를 unwrap할 수 없습니다. 유효하지 상태: [{0}]
|
||||
channel.nio.ssl.unwrapFailResize=버퍼가 너무 작아서 데이터를 unwrap할 수 없습니다. 유효하지 않은 상태 [{0}]
|
||||
channel.nio.ssl.wrapException=Wrap하는 중 handshake가 실패했습니다.
|
||||
channel.nio.ssl.wrapFail=데이터를 wrap할 수 없습니다. 유효하지 않은 상태 [{0}]
|
||||
|
||||
endpoint.accept.fail=소켓 accept 실패
|
||||
endpoint.alpn.fail=[{0}]을(를) 사용하여 ALPN을 위한 엔드포인트를 설정하지 못했습니다.
|
||||
endpoint.alpn.negotiated=ALPN을 사용하여 [{0}] 프로토콜로 negotiate 했습니다.
|
||||
endpoint.apr.applyConf=OpenSSLConfCmd를 SSL 컨텍스트에 적용합니다.
|
||||
endpoint.apr.checkConf=OpenSSLConf를 점검합니다.
|
||||
endpoint.apr.errApplyConf=OpenSSLConf를 SSL 컨텍스트에 적용할 수 없었습니다.
|
||||
endpoint.apr.errCheckConf=OpenSSLConf 점검 중 오류 발생
|
||||
endpoint.apr.errMakeConf=OpenSSLConf 컨텍스트를 생성할 수 없었습니다.
|
||||
endpoint.apr.failSslContextMake=SSLContext를 생성할 수 없습니다. AprLifecycleListener에서 SSLEngine이 사용가능 상태로 설정되었는지, AprLifecycleListener가 올바로 초기화되었는지, 그리고 유효한 SSLProtocol이 지정되었는지 점검하십시오.
|
||||
endpoint.apr.invalidSslProtocol=SSLProtocol 속성을 위해 유효하지 않은 값 [{0}]이(가) 제공되었습니다.
|
||||
endpoint.apr.maxConnections.running=APR 엔드포인트는 실행 중 maxConnections 설정을 지원하지 않습니다. 기존 값인 [{0}]이(가) 계속해서 사용될 것입니다.
|
||||
endpoint.apr.maxConnections.unlimited=APR 엔드포인트는 무제한 연결들을 지원하지 않습니다. 기존 값 [{0}]이(가) 계속해서 사용될 것입니다.
|
||||
endpoint.apr.noSendfileWithSSL=SSL이 사용가능 상태로 설정되어 있을 때에는, APR/native connector를 위한 sendfile이 지원되지 않습니다.
|
||||
endpoint.apr.pollAddInvalid=소켓 [{0}]을(를) poller에 추가하려는, 유효하지 않은 시도입니다.
|
||||
endpoint.apr.pollError=Poller가 다음 오류와 함께 실패했습니다. [{0}] : [{1}]
|
||||
endpoint.apr.pollMergeEvents=병합 이벤트 [{2}]을(를) 생성하기 위해, 소켓 [{0}]을(를) 위한 poller 이벤트 [{1}]을(를) 병합합니다.
|
||||
endpoint.apr.pollUnknownEvent=인식되지 않는 이벤트 [{0}]와(과) 함께, 소켓이 poller로 부터 반환되었습니다.
|
||||
endpoint.apr.remoteport=APR 소켓 [{0}]이(가) 원격 포트 [{1}](으)로 열렸습니다.
|
||||
endpoint.apr.tooManyCertFiles=AprEndpoint가 처리할 수 있는 것 보다 더 많은 인증서 파일들이 설정되었습니다.
|
||||
endpoint.debug.channelCloseFail=채널을 닫지 못했습니다.
|
||||
endpoint.debug.destroySocket=소켓 [{0}]을(를) 소멸시킵니다.
|
||||
endpoint.debug.pollerAdd=addList에 추가합니다: 소켓 [{0}], 제한시간 [{1}], 플래그들 [{2}]
|
||||
endpoint.debug.pollerAddDo=Poller에 소켓 [{0}]을(를) 추가합니다.
|
||||
endpoint.debug.pollerProcess=다음 이벤트(들)을 위해 소켓 [{0}]을(를) 처리합니다: [{1}]
|
||||
endpoint.debug.pollerRemove=Poller로부터 [{0}]을(를) 제거하려 시도 중
|
||||
endpoint.debug.pollerRemoved=Poller로부터 [{0}]을(를) 제거했습니다.
|
||||
endpoint.debug.registerRead=[{0}]을(를) 위한 readInterest를 등록했습니다.
|
||||
endpoint.debug.registerWrite=[{0}]을(를) 위한 writeInterest를 등록했습니다.
|
||||
endpoint.debug.socket=소켓 [{0}]
|
||||
endpoint.debug.socketCloseFail=소켓을 닫지 못했습니다.
|
||||
endpoint.debug.socketTimeout=제한 시간 초과로 처리합니다: [{0}]
|
||||
endpoint.debug.unlock.fail=포트 [{0}]에 대한 accept의 잠금을 풀고자 시도하는 중 예외 발생
|
||||
endpoint.debug.unlock.localFail=[{0}]을(를) 위한 로컬 주소를 결정할 수 없습니다.
|
||||
endpoint.debug.unlock.localNone=로컬 주소가 가용하지 않기 때문에, [{0}]을(를) 위한 acceptor의 잠금 상태를 풀지 못했습니다.
|
||||
endpoint.duplicateSslHostName=호스트 이름 [{0}]을(를) 위해 여러 개의 SSLHostConfig 엘리먼트들이 제공되었습니다. 호스트 이름들은 반드시 유일해야 합니다.
|
||||
endpoint.err.close=소켓을 닫으려 시도하는 중 예외 발생
|
||||
endpoint.err.handshake=Handshake가 실패했습니다.
|
||||
endpoint.err.unexpected=소켓 처리 중 예기치 않은 오류 발생
|
||||
endpoint.executor.fail=Executor가 소켓 [{0}]을(를) 처리하기를 거부했습니다.
|
||||
endpoint.getAttribute=[{0}]의 값은 [{1}]입니다.
|
||||
endpoint.init.bind=소켓 바인딩 실패: [{0}] [{1}]
|
||||
endpoint.init.bind.inherited=Connector가 상속된 채널을 사용하도록 설정되었는데, 상속된 채널이 없습니다.
|
||||
endpoint.init.listen=소켓 listen 실패: [{0}] [{1}]
|
||||
endpoint.init.notavail=APR이 가용하지 않음
|
||||
endpoint.invalidJmxNameSslHost=호스트 [{0}]와(과) 연관된 SSLHostConfig를 위한, 유효한 JMX 객체 이름을 생성할 수 없습니다.
|
||||
endpoint.invalidJmxNameSslHostCert=호스트가 [{0}]이고 인증서 타입이 [{1}]인 SSLHostConfigCertificate을 위한, 유효한 JMX 객체 이름을 생성할 수 없습니다.
|
||||
endpoint.jmxRegistrationFailed=JMX 객체를 [{0}](이)라는 이름으로 등록시키지 못했습니다.
|
||||
endpoint.jsse.noSslContext=호스트 이름 [{0}]을(를) 위한 SSLContext를 찾을 수 없습니다.
|
||||
endpoint.launch.fail=새로운 Runnable을 시작하지 못했습니다.
|
||||
endpoint.nio.registerFail=Poller로부터의 selector와 함께, 소켓을 등록하지 못했습니다.
|
||||
endpoint.nio.selectorCloseFail=Poller를 닫을 때, selector를 닫지 못했습니다.
|
||||
endpoint.nio.stopLatchAwaitFail=Poller들이 요구되는 시간 내에 중지되지 않았습니다.
|
||||
endpoint.nio.stopLatchAwaitInterrupted=이 쓰레드는 poller들이 중지되기를 기다리는 동안 중단되었습니다.
|
||||
endpoint.nio.timeoutCme=제한 시간 초과들을 처리하는 동안 예외 발생. 해당 코드는 반복해서 점검되어 왔고 ConcurrentModificationException이 발생하지 않아 왔습니다. 이 오류를 재현할 수 있다면, Tomcat 버그 티켓을 여시고 오류 재현 과정들을 제공해 주십시오.
|
||||
endpoint.nio2.exclusiveExecutor=NIO2 Connector가 셧다운 시에 정상적으로 동작하기 위해서는, 배타적인 Executor가 필수적으로 요구됩니다.
|
||||
endpoint.noSslHostConfig=호스트 이름 [{0}]을(를) 사용하여, Connector [{1}]을(를) 위한 defaultSSLHostConfigName과 부합하는 SSLHostConfig 엘리먼트를 찾지 못했습니다.
|
||||
endpoint.noSslHostName=SSL 호스트 설정을 위한 호스트 이름이 제공되지 않았습니다.
|
||||
endpoint.poll.error=예기치 않은 poller 오류 발생
|
||||
endpoint.poll.fail=심각한 poller 실패 (poller를 재시작합니다): [{0}] [{1}]
|
||||
endpoint.poll.initfail=Poller 생성이 실패했습니다.
|
||||
endpoint.poll.limitedpollsize=지정된 크기 [{0}]로 poller를 생성하지 못했습니다.
|
||||
endpoint.process.fail=소켓 프로세서를 할당하는 중 오류 발생
|
||||
endpoint.processing.fail=소켓 프로세서 실행 중 오류 발생
|
||||
endpoint.removeDefaultSslHostConfig=기본 SSLHostConfig(이름: [{0}])는 제거될 수 없습니다.
|
||||
endpoint.sendfile.addfail=Sendfile 실패: [{0}] [{1}]
|
||||
endpoint.sendfile.error=예기치 않은 sendfile 오류
|
||||
endpoint.serverSocket.closeFailed=엔드포인트 [{0}]을(를) 위한 서버 소켓을 닫지 못했습니다.
|
||||
endpoint.setAttribute=[{1}]에 [{0}]을(를) 설정합니다.
|
||||
endpoint.timeout.err=소켓 제한 시간 초과 처리 중 오류 발생
|
||||
endpoint.unknownSslHostName=SSL 호스트 이름 [{0}]은(는), 이 엔드포인트를 위해 인식되지 않는 이름입니다.
|
||||
endpoint.warn.executorShutdown=쓰레드 풀 [{0}]와(과) 연관된 해당 Executor는 완전히 종료되지 않았습니다. 일부 애플리케이션 쓰레드들이 여전히 실행 중일 수 있습니다.
|
||||
endpoint.warn.incorrectConnectionCount=잘못된 연결 개수. 동일한 소켓에 여러 번의 socket.close가 호출되었음.
|
||||
endpoint.warn.noLocalAddr=소켓 [{0}]을(를) 위한 로컬 주소를 결정할 수 없습니다.
|
||||
endpoint.warn.noLocalName=소켓 [{0}]을(를) 위한 로컬 호스트 이름을 결정할 수 없습니다.
|
||||
endpoint.warn.noLocalPort=소켓 [{0}]을(를) 위한 로컬 포트를 결정할 수 없습니다.
|
||||
endpoint.warn.noRemoteAddr=소켓 [{0}]을(를) 위한 원격 주소를 결정할 수 없습니다.
|
||||
endpoint.warn.noRemoteHost=소켓 [{0}]을(를) 위한 원격 호스트 이름을 결정할 수 없습니다.
|
||||
endpoint.warn.noRemotePort=소켓 [{0}]을(를) 위한 원격 포트를 결정할 수 없습니다.
|
||||
endpoint.warn.unlockAcceptorFailed=Acceptor 쓰레드 [{0}]이(가) 잠금을 풀지 못했습니다. 강제로 소켓을 셧다운합니다.
|
||||
|
||||
jsse.invalid_truststore_password=Trust 저장소를 잠금을 풀거나 유효한지 확인하는 용도로, 제공된 Trust 저장소 비밀번호를 사용할 수 없었습니다. 널 비밀번호를 사용하여, 해당 Trust 저장소에 대한 접근을 다시 시도합니다. 이는 유효한지 확인하는 작업을 건너뛸 것입니다.
|
||||
jsse.keystore_load_failed=[{2}](으)로 인하여, 경로 [{1}]에 있고 타입이 [{0}]인 키 저장소를 로드하지 못했습니다.
|
||||
jsse.ssl3=SSLv3이 명시적으로 사용 가능 상태로 설정되었습니다. 이 프로토콜은 안전하지 않은 것으로 알려져 있습니다.
|
||||
jsse.tls13.auth=JSSE TLS 1.3 구현이 초기 handshake 이후의 인증을 지원하지 않음에 따라, 선택사항인 클라이언트 인증과 호환되지 않습니다.
|
||||
|
||||
sniExtractor.clientHelloInvalid=ClientHello 메시지가 정확히 포맷되지 않았습니다.
|
||||
sniExtractor.clientHelloTooBig=ClientHello가 단일 TLS 레코드에 존재하지 않았기에, SNI 정보를 추출할 수 없었습니다.
|
||||
|
||||
socket.apr.clientAbort=클라이언트가 연결을 중단했습니다.
|
||||
socket.apr.closed=이 연결과 연관된 소켓 [{0}]이(가) 이미 닫혀 있습니다.
|
||||
socket.apr.read.error=Wrapper [{2}]을(를) 사용하여, APR/native 소켓 [{1}]으로부터 데이터를 읽는 중, 예기치 않은 오류 발생: [{0}]
|
||||
socket.apr.write.error=Wrapper [{2}]을(를) 가지고 APR/native 소켓 [{1}]에 데이터를 쓰는 중, 예기치 않은 오류 발생: [{0}]
|
||||
socket.closed=이 연결과 연관된 해당 소켓은 이미 닫혔습니다.
|
||||
socket.sslreneg=SSL 연결을 re-negotiate하는 동안 예외 발생
|
||||
|
||||
sslHostConfig.certificate.notype=여러 개의 인증서들이 지정되었는데, 적어도 하나의 인증서에 필수 속성 타입이 없습니다.
|
||||
sslHostConfig.certificateVerificationInvalid=인증서 검증 값 [{0}]은(는) 인식되지 않는 값입니다.
|
||||
sslHostConfig.fileNotFound=설정된 파일 [{0}]이(가) 존재하지 않습니다.
|
||||
sslHostConfig.mismatch=[{1}](이)라는 이름의 SSLHostConfig에 프로퍼티 [{0}]이(가) 설정되었는데, 이 프로퍼티는 [{2}] 설정 문법을 위한 것이나, 해당 SSLHostConfig은 [{3}] 설정 문법으로 사용되고 있습니다.
|
||||
sslHostConfig.opensslconf.alreadyset=또 다른 OpenSSLConf을 설정하려는 시도는 무시되었습니다.
|
||||
sslHostConfig.opensslconf.null=널인 OpenSSLConf를 설정하려는 시도가 무시되었습니다.
|
||||
sslHostConfig.prefix_missing=프로토콜 [{0}]이(가) [{1}](이)라는 이름을 가진 SSLHostConfig의 프로토콜 목록에 추가되어 있습니다. +/- prefix가 누락되었는지 점검하십시오.
|
||||
|
||||
sslHostConfigCertificate.mismatch=프로퍼티 [{0}]이(가) [{1}](이)라는 이름의 SSLHostConfigCertificate에 설정되었고, 이는 인증서 저장소 타입 [{2}]을(를) 위한 것이지만, 인증서가 타입 [{3}]의 인증서 저장소와 함께 사용되고 있습니다.
|
||||
|
||||
sslImplementation.cnfe=클래스 [{0}]의 SSLImplementation 객체를 생성할 수 없습니다.
|
||||
|
||||
sslUtilBase.active=활성화 된 [{0}]은(는) 다음과 같습니다: [{1}]
|
||||
sslUtilBase.noneSupported=지정된 [{0}]의 어느 것도 SSL 엔진에 의해 지원되지 않습니다: [{1}]
|
||||
sslUtilBase.skipped=지정된 [{0}]의 일부가 SSL 엔진에 의해 지원되지 않아 건너뜁니다: [{1}]
|
||||
19
java/org/apache/tomcat/util/net/LocalStrings_ru.properties
Normal file
19
java/org/apache/tomcat/util/net/LocalStrings_ru.properties
Normal file
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
endpoint.debug.socketCloseFail=Ошибка при закрытии соединения.
|
||||
endpoint.setAttribute=Установка [{0}] в [{1}]
|
||||
|
||||
sslHostConfig.fileNotFound=Сконфигурированный файл [{0}] не существует
|
||||
@@ -0,0 +1,91 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
channel.nio.ssl.appOutputNotEmpty=应用程序输出缓冲区仍包含数据。数据可能会丢失。
|
||||
channel.nio.ssl.closing=通道处于关闭状态
|
||||
channel.nio.ssl.eofDuringHandshake=握手期间EOF
|
||||
channel.nio.ssl.foundHttp=找到一个明文HTTP请求,它应该是一个加密的TLS连接
|
||||
channel.nio.ssl.invalidCloseState=无效的关闭状态,不会发送网络数据。
|
||||
channel.nio.ssl.notHandshaking=握手认证期间NOT_HANDSHAKING
|
||||
channel.nio.ssl.remainingDataDuringClose=网络缓冲区中的剩余数据,无法发送SSL关闭消息,套接字仍将关闭
|
||||
channel.nio.ssl.sniDefault=无法缓冲足够的数据来确定请求的SNI主机名。使用默认值
|
||||
channel.nio.ssl.sniHostName=连接[{0}]中提取的SNI主机名称是[{1}]
|
||||
channel.nio.ssl.timeoutDuringHandshake=握手期间超时。
|
||||
channel.nio.ssl.unexpectedStatusDuringWrap=握手WRAP期间出现意外状态[{0}]。
|
||||
channel.nio.ssl.unwrapFail=无法解包数据,无效状态 [{0}]
|
||||
channel.nio.ssl.unwrapFailResize=由于缓冲区太小无法解包数据,无效状态 [{0}]
|
||||
|
||||
endpoint.alpn.negotiated=使用ALPN协商的[{0}]协议
|
||||
endpoint.apr.applyConf=正将OpenSSLConfCmd应用在SSL Context上。
|
||||
endpoint.apr.checkConf=检查配置OpenSSLConf
|
||||
endpoint.apr.errApplyConf=不能对SSL上下文应用OpenSSLConf 配置
|
||||
endpoint.apr.errMakeConf=无法创建OpenSSLConf 上下文
|
||||
endpoint.apr.failSslContextMake=无法创建SSLContext。检查AprLifecycleListener中的SSLEngine 是否已启用,AprLifecycleListener是否已正确初始化,以及是否已指定有效的SSLProtocol
|
||||
endpoint.apr.invalidSslProtocol=为SSLProtocol属性提供了无效值[{0}]
|
||||
endpoint.apr.maxConnections.running=):APR终结点在运行时不支持MaxConnections的设置。[{0}]的现有值将继续使用。
|
||||
endpoint.apr.maxConnections.unlimited=APR终结点不支持无限连接。[{0}]的现有值将继续使用。
|
||||
endpoint.apr.pollAddInvalid=无效企图向一个轮询器中添加一个套接字[{0}]
|
||||
endpoint.apr.tooManyCertFiles=证书文件配置超过了
|
||||
endpoint.debug.channelCloseFail=关闭频道失败
|
||||
endpoint.debug.destroySocket=将销毁socket [{0}]
|
||||
endpoint.debug.socket=socket [{0}]
|
||||
endpoint.debug.socketCloseFail=关闭 socket 失败
|
||||
endpoint.debug.unlock.localNone=无法解除 [{0}] 的接受器,因为本地地址不可用
|
||||
endpoint.err.close=抓住异常试图关闭socket
|
||||
endpoint.err.unexpected=处理套接字时意外错误
|
||||
endpoint.getAttribute=[{0}] 是 [{1}]
|
||||
endpoint.init.bind=套接字绑定失败: [{0}] [{1}]
|
||||
endpoint.init.notavail=APR.不可用
|
||||
endpoint.invalidJmxNameSslHostCert=对于SSLHostConfigCertificate关联的主机[{0}]和证书类型[{1}],无法生成有效的XML对象名称
|
||||
endpoint.jmxRegistrationFailed=未能使用名称[{0}]注册JMX对象
|
||||
endpoint.jsse.noSslContext=):找不到主机名[{0}]的SSLContext
|
||||
endpoint.nio.stopLatchAwaitInterrupted=在等待轮询器停止时,该线程被中断
|
||||
endpoint.nio.timeoutCme=处理超时异常. 这段代码已经被重复检查并且没有并发修改发现。如果你能重现这个错误,请提交一个tomcat bug, 提供重现步骤.
|
||||
endpoint.noSslHostConfig=没有找到带有hostName[{0}]的SSLHostConfig元素,以匹配连接器[{1}]的默认SSLHostConfigName
|
||||
endpoint.noSslHostName=SSL主机中没有被提供主机名
|
||||
endpoint.poll.fail=严重轮询器故障(重新启动轮询器)[{0}] [{1}]
|
||||
endpoint.poll.limitedpollsize=创建轮询器失败,大小:[{0}]
|
||||
endpoint.process.fail=分配 socket 处理器出错
|
||||
endpoint.processing.fail=运行.套接字处理器出错
|
||||
endpoint.removeDefaultSslHostConfig=默认SSLHostConfig(名为[{0}])可能未被移除
|
||||
endpoint.sendfile.addfail=发送文件(Sendfile)失败: [{0}] [{1}]
|
||||
endpoint.sendfile.error=未知的sendfile异常。
|
||||
endpoint.serverSocket.closeFailed=无法为 [{0}] 关闭服务器 socket
|
||||
endpoint.setAttribute=设置. [{0}] 到 [{1}]
|
||||
endpoint.timeout.err=处理套接字超时出错
|
||||
endpoint.warn.executorShutdown=与线程池[{0}]关联的执行程序尚未完全关闭。 某些应用程序线程可能仍在运行。
|
||||
endpoint.warn.incorrectConnectionCount=连接数不正确,在同一个套接字上调用多个socket.close。
|
||||
endpoint.warn.noLocalAddr=无法确定套接字 [{0}] 的本地地址
|
||||
endpoint.warn.noLocalName=无法确定 socket [{0}] 的本地主机名
|
||||
endpoint.warn.noLocalPort=无法确定套接字 [{0}] 的本地端口
|
||||
endpoint.warn.noRemotePort=无法确定 socket [{0}] 的远程端口
|
||||
|
||||
jsse.ssl3=SSLv3 已显式启用。 已知该协议是不安全。
|
||||
|
||||
sniExtractor.clientHelloTooBig=):ClientHello 没有出现在单个TLS记录中,因此无法提取SNI信息
|
||||
|
||||
socket.apr.closed=与该链接所关联的 socket [{0}] 被关闭
|
||||
socket.closed=与此连接关联的套接字已关闭。
|
||||
|
||||
sslHostConfig.certificate.notype=指定了多个证书,并且至少有一个证书缺少必需的属性类型
|
||||
sslHostConfig.fileNotFound=配置文件 [{0}] 不存在
|
||||
sslHostConfig.mismatch=属性[{0}]是在名为[{1}]的SSLHostConfig 上设置的,用于[{2}]配置语法,但SSLHostConfig 正与[{3}]配置语法一起使用
|
||||
sslHostConfig.opensslconf.null=(:忽略设置空OpenSSLConf 的尝试
|
||||
sslHostConfig.prefix_missing=协议[{0}]已添加到名为[{1}]的SSLHostConfig 上的协议列表中。检查是否缺少一个+/-前缀。
|
||||
|
||||
sslImplementation.cnfe=无法为类 [{0}] 创建SSLImplementation
|
||||
|
||||
sslUtilBase.noneSupported=SSL引擎不支持指定的[{0}]:[{1}]
|
||||
sslUtilBase.skipped=某些指定的[{0}]不受SSL引擎支持,已被跳过:[{1}]
|
||||
224
java/org/apache/tomcat/util/net/Nio2Channel.java
Normal file
224
java/org/apache/tomcat/util/net/Nio2Channel.java
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousByteChannel;
|
||||
import java.nio.channels.AsynchronousSocketChannel;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* Base class for a SocketChannel wrapper used by the endpoint.
|
||||
* This way, logic for an SSL socket channel remains the same as for
|
||||
* a non SSL, making sure we don't need to code for any exception cases.
|
||||
*/
|
||||
public class Nio2Channel implements AsynchronousByteChannel {
|
||||
|
||||
protected static final ByteBuffer emptyBuf = ByteBuffer.allocate(0);
|
||||
|
||||
protected AsynchronousSocketChannel sc = null;
|
||||
protected SocketWrapperBase<Nio2Channel> socket = null;
|
||||
protected final SocketBufferHandler bufHandler;
|
||||
|
||||
public Nio2Channel(SocketBufferHandler bufHandler) {
|
||||
this.bufHandler = bufHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the channel.
|
||||
*
|
||||
* @param channel The new async channel to associate with this NIO2 channel
|
||||
* @param socket The new socket to associate with this NIO2 channel
|
||||
*
|
||||
* @throws IOException If a problem was encountered resetting the channel
|
||||
*/
|
||||
public void reset(AsynchronousSocketChannel channel, SocketWrapperBase<Nio2Channel> socket)
|
||||
throws IOException {
|
||||
this.sc = channel;
|
||||
this.socket = socket;
|
||||
bufHandler.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the channel memory
|
||||
*/
|
||||
public void free() {
|
||||
bufHandler.free();
|
||||
}
|
||||
|
||||
public SocketWrapperBase<Nio2Channel> getSocket() {
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes this channel.
|
||||
*
|
||||
* @throws IOException If an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
sc.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close the connection.
|
||||
*
|
||||
* @param force Should the underlying socket be forcibly closed?
|
||||
*
|
||||
* @throws IOException If closing the secure channel fails.
|
||||
*/
|
||||
public void close(boolean force) throws IOException {
|
||||
if (isOpen() || force) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tells whether or not this channel is open.
|
||||
*
|
||||
* @return <code>true</code> if, and only if, this channel is open
|
||||
*/
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return sc.isOpen();
|
||||
}
|
||||
|
||||
public SocketBufferHandler getBufHandler() {
|
||||
return bufHandler;
|
||||
}
|
||||
|
||||
public AsynchronousSocketChannel getIOChannel() {
|
||||
return sc;
|
||||
}
|
||||
|
||||
public boolean isClosing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isHandshakeComplete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs SSL handshake hence is a no-op for the non-secure
|
||||
* implementation.
|
||||
*
|
||||
* @return Always returns zero
|
||||
*
|
||||
* @throws IOException Never for non-secure channel
|
||||
*/
|
||||
public int handshake() throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+":"+this.sc.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Integer> read(ByteBuffer dst) {
|
||||
return sc.read(dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> void read(ByteBuffer dst, A attachment,
|
||||
CompletionHandler<Integer, ? super A> handler) {
|
||||
read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
|
||||
}
|
||||
|
||||
public <A> void read(ByteBuffer dst,
|
||||
long timeout, TimeUnit unit, A attachment,
|
||||
CompletionHandler<Integer, ? super A> handler) {
|
||||
sc.read(dst, timeout, unit, attachment, handler);
|
||||
}
|
||||
|
||||
public <A> void read(ByteBuffer[] dsts,
|
||||
int offset, int length, long timeout, TimeUnit unit,
|
||||
A attachment, CompletionHandler<Long,? super A> handler) {
|
||||
sc.read(dsts, offset, length, timeout, unit, attachment, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Integer> write(ByteBuffer src) {
|
||||
return sc.write(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> void write(ByteBuffer src, A attachment,
|
||||
CompletionHandler<Integer, ? super A> handler) {
|
||||
write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler);
|
||||
}
|
||||
|
||||
public <A> void write(ByteBuffer src, long timeout, TimeUnit unit, A attachment,
|
||||
CompletionHandler<Integer, ? super A> handler) {
|
||||
sc.write(src, timeout, unit, attachment, handler);
|
||||
}
|
||||
|
||||
public <A> void write(ByteBuffer[] srcs, int offset, int length,
|
||||
long timeout, TimeUnit unit, A attachment,
|
||||
CompletionHandler<Long,? super A> handler) {
|
||||
sc.write(srcs, offset, length, timeout, unit, attachment, handler);
|
||||
}
|
||||
|
||||
private static final Future<Boolean> DONE = new Future<Boolean>() {
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public Boolean get() throws InterruptedException,
|
||||
ExecutionException {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
@Override
|
||||
public Boolean get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
};
|
||||
|
||||
public Future<Boolean> flush() {
|
||||
return DONE;
|
||||
}
|
||||
|
||||
|
||||
private ApplicationBufferHandler appReadBufHandler;
|
||||
public void setAppReadBufHandler(ApplicationBufferHandler handler) {
|
||||
this.appReadBufHandler = handler;
|
||||
}
|
||||
protected ApplicationBufferHandler getAppReadBufHandler() {
|
||||
return appReadBufHandler;
|
||||
}
|
||||
}
|
||||
1694
java/org/apache/tomcat/util/net/Nio2Endpoint.java
Normal file
1694
java/org/apache/tomcat/util/net/Nio2Endpoint.java
Normal file
File diff suppressed because it is too large
Load Diff
475
java/org/apache/tomcat/util/net/NioBlockingSelector.java
Normal file
475
java/org/apache/tomcat/util/net/NioBlockingSelector.java
Normal file
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
import org.apache.tomcat.util.collections.SynchronizedQueue;
|
||||
import org.apache.tomcat.util.collections.SynchronizedStack;
|
||||
import org.apache.tomcat.util.net.NioEndpoint.NioSocketWrapper;
|
||||
|
||||
public class NioBlockingSelector {
|
||||
|
||||
private static final Log log = LogFactory.getLog(NioBlockingSelector.class);
|
||||
|
||||
private static AtomicInteger threadCounter = new AtomicInteger(0);
|
||||
|
||||
private final SynchronizedStack<KeyReference> keyReferenceStack =
|
||||
new SynchronizedStack<>();
|
||||
|
||||
protected Selector sharedSelector;
|
||||
|
||||
protected BlockPoller poller;
|
||||
public NioBlockingSelector() {
|
||||
|
||||
}
|
||||
|
||||
public void open(Selector selector) {
|
||||
sharedSelector = selector;
|
||||
poller = new BlockPoller();
|
||||
poller.selector = sharedSelector;
|
||||
poller.setDaemon(true);
|
||||
poller.setName("NioBlockingSelector.BlockPoller-"+(threadCounter.getAndIncrement()));
|
||||
poller.start();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (poller!=null) {
|
||||
poller.disable();
|
||||
poller.interrupt();
|
||||
poller = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a blocking write using the bytebuffer for data to be written
|
||||
* If the <code>selector</code> parameter is null, then it will perform a busy write that could
|
||||
* take up a lot of CPU cycles.
|
||||
* @param buf ByteBuffer - the buffer containing the data, we will write as long as <code>(buf.hasRemaining()==true)</code>
|
||||
* @param socket SocketChannel - the socket to write data to
|
||||
* @param writeTimeout long - the timeout for this write operation in milliseconds, -1 means no timeout
|
||||
* @return int - returns the number of bytes written
|
||||
* @throws EOFException if write returns -1
|
||||
* @throws SocketTimeoutException if the write times out
|
||||
* @throws IOException if an IO Exception occurs in the underlying socket logic
|
||||
*/
|
||||
public int write(ByteBuffer buf, NioChannel socket, long writeTimeout)
|
||||
throws IOException {
|
||||
SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
|
||||
if ( key == null ) throw new IOException("Key no longer registered");
|
||||
KeyReference reference = keyReferenceStack.pop();
|
||||
if (reference == null) {
|
||||
reference = new KeyReference();
|
||||
}
|
||||
NioSocketWrapper att = (NioSocketWrapper) key.attachment();
|
||||
int written = 0;
|
||||
boolean timedout = false;
|
||||
int keycount = 1; //assume we can write
|
||||
long time = System.currentTimeMillis(); //start the timeout timer
|
||||
try {
|
||||
while ( (!timedout) && buf.hasRemaining()) {
|
||||
if (keycount > 0) { //only write if we were registered for a write
|
||||
int cnt = socket.write(buf); //write the data
|
||||
if (cnt == -1)
|
||||
throw new EOFException();
|
||||
written += cnt;
|
||||
if (cnt > 0) {
|
||||
time = System.currentTimeMillis(); //reset our timeout timer
|
||||
continue; //we successfully wrote, try again without a selector
|
||||
}
|
||||
}
|
||||
try {
|
||||
if ( att.getWriteLatch()==null || att.getWriteLatch().getCount()==0) att.startWriteLatch(1);
|
||||
poller.add(att,SelectionKey.OP_WRITE,reference);
|
||||
if (writeTimeout < 0) {
|
||||
att.awaitWriteLatch(Long.MAX_VALUE,TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
att.awaitWriteLatch(writeTimeout,TimeUnit.MILLISECONDS);
|
||||
}
|
||||
} catch (InterruptedException ignore) {
|
||||
// Ignore
|
||||
}
|
||||
if ( att.getWriteLatch()!=null && att.getWriteLatch().getCount()> 0) {
|
||||
//we got interrupted, but we haven't received notification from the poller.
|
||||
keycount = 0;
|
||||
}else {
|
||||
//latch countdown has happened
|
||||
keycount = 1;
|
||||
att.resetWriteLatch();
|
||||
}
|
||||
|
||||
if (writeTimeout > 0 && (keycount == 0))
|
||||
timedout = (System.currentTimeMillis() - time) >= writeTimeout;
|
||||
} //while
|
||||
if (timedout)
|
||||
throw new SocketTimeoutException();
|
||||
} finally {
|
||||
poller.remove(att,SelectionKey.OP_WRITE);
|
||||
if (timedout && reference.key!=null) {
|
||||
poller.cancelKey(reference.key);
|
||||
}
|
||||
reference.key = null;
|
||||
keyReferenceStack.push(reference);
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a blocking read using the bytebuffer for data to be read
|
||||
* If the <code>selector</code> parameter is null, then it will perform a busy read that could
|
||||
* take up a lot of CPU cycles.
|
||||
* @param buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out
|
||||
* @param socket SocketChannel - the socket to write data to
|
||||
* @param readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout
|
||||
* @return int - returns the number of bytes read
|
||||
* @throws EOFException if read returns -1
|
||||
* @throws SocketTimeoutException if the read times out
|
||||
* @throws IOException if an IO Exception occurs in the underlying socket logic
|
||||
*/
|
||||
public int read(ByteBuffer buf, NioChannel socket, long readTimeout) throws IOException {
|
||||
SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
|
||||
if ( key == null ) throw new IOException("Key no longer registered");
|
||||
KeyReference reference = keyReferenceStack.pop();
|
||||
if (reference == null) {
|
||||
reference = new KeyReference();
|
||||
}
|
||||
NioSocketWrapper att = (NioSocketWrapper) key.attachment();
|
||||
int read = 0;
|
||||
boolean timedout = false;
|
||||
int keycount = 1; //assume we can read
|
||||
long time = System.currentTimeMillis(); //start the timeout timer
|
||||
try {
|
||||
while(!timedout) {
|
||||
if (keycount > 0) { //only read if we were registered for a read
|
||||
read = socket.read(buf);
|
||||
if (read != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if ( att.getReadLatch()==null || att.getReadLatch().getCount()==0) att.startReadLatch(1);
|
||||
poller.add(att,SelectionKey.OP_READ, reference);
|
||||
if (readTimeout < 0) {
|
||||
att.awaitReadLatch(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
att.awaitReadLatch(readTimeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
} catch (InterruptedException ignore) {
|
||||
// Ignore
|
||||
}
|
||||
if ( att.getReadLatch()!=null && att.getReadLatch().getCount()> 0) {
|
||||
//we got interrupted, but we haven't received notification from the poller.
|
||||
keycount = 0;
|
||||
}else {
|
||||
//latch countdown has happened
|
||||
keycount = 1;
|
||||
att.resetReadLatch();
|
||||
}
|
||||
if (readTimeout >= 0 && (keycount == 0))
|
||||
timedout = (System.currentTimeMillis() - time) >= readTimeout;
|
||||
} //while
|
||||
if (timedout)
|
||||
throw new SocketTimeoutException();
|
||||
} finally {
|
||||
poller.remove(att,SelectionKey.OP_READ);
|
||||
if (timedout && reference.key!=null) {
|
||||
poller.cancelKey(reference.key);
|
||||
}
|
||||
reference.key = null;
|
||||
keyReferenceStack.push(reference);
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
|
||||
protected static class BlockPoller extends Thread {
|
||||
protected volatile boolean run = true;
|
||||
protected Selector selector = null;
|
||||
protected final SynchronizedQueue<Runnable> events = new SynchronizedQueue<>();
|
||||
public void disable() { run = false; selector.wakeup();}
|
||||
protected final AtomicInteger wakeupCounter = new AtomicInteger(0);
|
||||
|
||||
public void cancelKey(final SelectionKey key) {
|
||||
Runnable r = new RunnableCancel(key);
|
||||
events.offer(r);
|
||||
wakeup();
|
||||
}
|
||||
|
||||
public void wakeup() {
|
||||
if (wakeupCounter.addAndGet(1)==0) selector.wakeup();
|
||||
}
|
||||
|
||||
public void cancel(SelectionKey sk, NioSocketWrapper key, int ops){
|
||||
if (sk!=null) {
|
||||
sk.cancel();
|
||||
sk.attach(null);
|
||||
if (SelectionKey.OP_WRITE==(ops&SelectionKey.OP_WRITE)) countDown(key.getWriteLatch());
|
||||
if (SelectionKey.OP_READ==(ops&SelectionKey.OP_READ))countDown(key.getReadLatch());
|
||||
}
|
||||
}
|
||||
|
||||
public void add(final NioSocketWrapper key, final int ops, final KeyReference ref) {
|
||||
if ( key == null ) return;
|
||||
NioChannel nch = key.getSocket();
|
||||
final SocketChannel ch = nch.getIOChannel();
|
||||
if ( ch == null ) return;
|
||||
|
||||
Runnable r = new RunnableAdd(ch, key, ops, ref);
|
||||
events.offer(r);
|
||||
wakeup();
|
||||
}
|
||||
|
||||
public void remove(final NioSocketWrapper key, final int ops) {
|
||||
if ( key == null ) return;
|
||||
NioChannel nch = key.getSocket();
|
||||
final SocketChannel ch = nch.getIOChannel();
|
||||
if ( ch == null ) return;
|
||||
|
||||
Runnable r = new RunnableRemove(ch, key, ops);
|
||||
events.offer(r);
|
||||
wakeup();
|
||||
}
|
||||
|
||||
public boolean events() {
|
||||
Runnable r = null;
|
||||
|
||||
/* We only poll and run the runnable events when we start this
|
||||
* method. Further events added to the queue later will be delayed
|
||||
* to the next execution of this method.
|
||||
*
|
||||
* We do in this way, because running event from the events queue
|
||||
* may lead the working thread to add more events to the queue (for
|
||||
* example, the worker thread may add another RunnableAdd event when
|
||||
* waken up by a previous RunnableAdd event who got an invalid
|
||||
* SelectionKey). Trying to consume all the events in an increasing
|
||||
* queue till it's empty, will make the loop hard to be terminated,
|
||||
* which will kill a lot of time, and greatly affect performance of
|
||||
* the poller loop.
|
||||
*/
|
||||
int size = events.size();
|
||||
for (int i = 0; i < size && (r = events.poll()) != null; i++) {
|
||||
r.run();
|
||||
}
|
||||
|
||||
return (size > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (run) {
|
||||
try {
|
||||
events();
|
||||
int keyCount = 0;
|
||||
try {
|
||||
int i = wakeupCounter.get();
|
||||
if (i>0)
|
||||
keyCount = selector.selectNow();
|
||||
else {
|
||||
wakeupCounter.set(-1);
|
||||
keyCount = selector.select(1000);
|
||||
}
|
||||
wakeupCounter.set(0);
|
||||
if (!run) break;
|
||||
}catch ( NullPointerException x ) {
|
||||
//sun bug 5076772 on windows JDK 1.5
|
||||
if (selector==null) throw x;
|
||||
if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x);
|
||||
continue;
|
||||
} catch ( CancelledKeyException x ) {
|
||||
//sun bug 5076772 on windows JDK 1.5
|
||||
if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x);
|
||||
continue;
|
||||
} catch (Throwable x) {
|
||||
ExceptionUtils.handleThrowable(x);
|
||||
log.error("",x);
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator<SelectionKey> iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null;
|
||||
|
||||
// Walk through the collection of ready keys and dispatch
|
||||
// any active event.
|
||||
while (run && iterator != null && iterator.hasNext()) {
|
||||
SelectionKey sk = iterator.next();
|
||||
NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
|
||||
try {
|
||||
iterator.remove();
|
||||
sk.interestOps(sk.interestOps() & (~sk.readyOps()));
|
||||
if ( sk.isReadable() ) {
|
||||
countDown(attachment.getReadLatch());
|
||||
}
|
||||
if (sk.isWritable()) {
|
||||
countDown(attachment.getWriteLatch());
|
||||
}
|
||||
}catch (CancelledKeyException ckx) {
|
||||
sk.cancel();
|
||||
countDown(attachment.getReadLatch());
|
||||
countDown(attachment.getWriteLatch());
|
||||
}
|
||||
}//while
|
||||
}catch ( Throwable t ) {
|
||||
log.error("",t);
|
||||
}
|
||||
}
|
||||
events.clear();
|
||||
// If using a shared selector, the NioSelectorPool will also try and
|
||||
// close the selector. Try and avoid the ClosedSelectorException
|
||||
// although because multiple threads are involved there is always
|
||||
// the possibility of an Exception here.
|
||||
if (selector.isOpen()) {
|
||||
try {
|
||||
// Cancels all remaining keys
|
||||
selector.selectNow();
|
||||
}catch( Exception ignore ) {
|
||||
if (log.isDebugEnabled())log.debug("",ignore);
|
||||
}
|
||||
}
|
||||
try {
|
||||
selector.close();
|
||||
}catch( Exception ignore ) {
|
||||
if (log.isDebugEnabled())log.debug("",ignore);
|
||||
}
|
||||
}
|
||||
|
||||
public void countDown(CountDownLatch latch) {
|
||||
if ( latch == null ) return;
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
|
||||
private class RunnableAdd implements Runnable {
|
||||
|
||||
private final SocketChannel ch;
|
||||
private final NioSocketWrapper key;
|
||||
private final int ops;
|
||||
private final KeyReference ref;
|
||||
|
||||
public RunnableAdd(SocketChannel ch, NioSocketWrapper key, int ops, KeyReference ref) {
|
||||
this.ch = ch;
|
||||
this.key = key;
|
||||
this.ops = ops;
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
SelectionKey sk = ch.keyFor(selector);
|
||||
try {
|
||||
if (sk == null) {
|
||||
sk = ch.register(selector, ops, key);
|
||||
ref.key = sk;
|
||||
} else if (!sk.isValid()) {
|
||||
cancel(sk, key, ops);
|
||||
} else {
|
||||
sk.interestOps(sk.interestOps() | ops);
|
||||
}
|
||||
} catch (CancelledKeyException cx) {
|
||||
cancel(sk, key, ops);
|
||||
} catch (ClosedChannelException cx) {
|
||||
cancel(null, key, ops);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class RunnableRemove implements Runnable {
|
||||
|
||||
private final SocketChannel ch;
|
||||
private final NioSocketWrapper key;
|
||||
private final int ops;
|
||||
|
||||
public RunnableRemove(SocketChannel ch, NioSocketWrapper key, int ops) {
|
||||
this.ch = ch;
|
||||
this.key = key;
|
||||
this.ops = ops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
SelectionKey sk = ch.keyFor(selector);
|
||||
try {
|
||||
if (sk == null) {
|
||||
if (SelectionKey.OP_WRITE==(ops&SelectionKey.OP_WRITE)) countDown(key.getWriteLatch());
|
||||
if (SelectionKey.OP_READ==(ops&SelectionKey.OP_READ))countDown(key.getReadLatch());
|
||||
} else {
|
||||
if (sk.isValid()) {
|
||||
sk.interestOps(sk.interestOps() & (~ops));
|
||||
if (SelectionKey.OP_WRITE==(ops&SelectionKey.OP_WRITE)) countDown(key.getWriteLatch());
|
||||
if (SelectionKey.OP_READ==(ops&SelectionKey.OP_READ))countDown(key.getReadLatch());
|
||||
if (sk.interestOps()==0) {
|
||||
sk.cancel();
|
||||
sk.attach(null);
|
||||
}
|
||||
}else {
|
||||
sk.cancel();
|
||||
sk.attach(null);
|
||||
}
|
||||
}
|
||||
}catch (CancelledKeyException cx) {
|
||||
if (sk!=null) {
|
||||
sk.cancel();
|
||||
sk.attach(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class RunnableCancel implements Runnable {
|
||||
|
||||
private final SelectionKey key;
|
||||
|
||||
public RunnableCancel(SelectionKey key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
key.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class KeyReference {
|
||||
SelectionKey key = null;
|
||||
|
||||
@Override
|
||||
public void finalize() {
|
||||
if (key!=null && key.isValid()) {
|
||||
log.warn("Possible key leak, cancelling key in the finalizer.");
|
||||
try {key.cancel();}catch (Exception ignore){}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
269
java/org/apache/tomcat/util/net/NioChannel.java
Normal file
269
java/org/apache/tomcat/util/net/NioChannel.java
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ByteChannel;
|
||||
import java.nio.channels.GatheringByteChannel;
|
||||
import java.nio.channels.ScatteringByteChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import org.apache.tomcat.util.net.NioEndpoint.Poller;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Base class for a SocketChannel wrapper used by the endpoint.
|
||||
* This way, logic for an SSL socket channel remains the same as for
|
||||
* a non SSL, making sure we don't need to code for any exception cases.
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public class NioChannel implements ByteChannel, ScatteringByteChannel, GatheringByteChannel {
|
||||
|
||||
protected static final StringManager sm = StringManager.getManager(NioChannel.class);
|
||||
|
||||
protected static final ByteBuffer emptyBuf = ByteBuffer.allocate(0);
|
||||
|
||||
protected SocketChannel sc = null;
|
||||
protected SocketWrapperBase<NioChannel> socketWrapper = null;
|
||||
|
||||
protected final SocketBufferHandler bufHandler;
|
||||
|
||||
protected Poller poller;
|
||||
|
||||
public NioChannel(SocketChannel channel, SocketBufferHandler bufHandler) {
|
||||
this.sc = channel;
|
||||
this.bufHandler = bufHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the channel
|
||||
*
|
||||
* @throws IOException If a problem was encountered resetting the channel
|
||||
*/
|
||||
public void reset() throws IOException {
|
||||
bufHandler.reset();
|
||||
}
|
||||
|
||||
|
||||
void setSocketWrapper(SocketWrapperBase<NioChannel> socketWrapper) {
|
||||
this.socketWrapper = socketWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the channel memory
|
||||
*/
|
||||
public void free() {
|
||||
bufHandler.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the network buffer has been flushed out and is empty.
|
||||
*
|
||||
* @param block Unused. May be used when overridden
|
||||
* @param s Unused. May be used when overridden
|
||||
* @param timeout Unused. May be used when overridden
|
||||
* @return Always returns <code>true</code> since there is no network buffer
|
||||
* in the regular channel
|
||||
*
|
||||
* @throws IOException Never for non-secure channel
|
||||
*/
|
||||
public boolean flush(boolean block, Selector s, long timeout)
|
||||
throws IOException {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes this channel.
|
||||
*
|
||||
* @throws IOException If an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
getIOChannel().socket().close();
|
||||
getIOChannel().close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection.
|
||||
*
|
||||
* @param force Should the underlying socket be forcibly closed?
|
||||
*
|
||||
* @throws IOException If closing the secure channel fails.
|
||||
*/
|
||||
public void close(boolean force) throws IOException {
|
||||
if (isOpen() || force ) close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether or not this channel is open.
|
||||
*
|
||||
* @return <code>true</code> if, and only if, this channel is open
|
||||
*/
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return sc.isOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a sequence of bytes to this channel from the given buffer.
|
||||
*
|
||||
* @param src The buffer from which bytes are to be retrieved
|
||||
* @return The number of bytes written, possibly zero
|
||||
* @throws IOException If some other I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
checkInterruptStatus();
|
||||
return sc.write(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long write(ByteBuffer[] srcs) throws IOException {
|
||||
return write(srcs, 0, srcs.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long write(ByteBuffer[] srcs, int offset, int length)
|
||||
throws IOException {
|
||||
checkInterruptStatus();
|
||||
return sc.write(srcs, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a sequence of bytes from this channel into the given buffer.
|
||||
*
|
||||
* @param dst The buffer into which bytes are to be transferred
|
||||
* @return The number of bytes read, possibly zero, or <code>-1</code> if
|
||||
* the channel has reached end-of-stream
|
||||
* @throws IOException If some other I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
return sc.read(dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read(ByteBuffer[] dsts) throws IOException {
|
||||
return read(dsts, 0, dsts.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read(ByteBuffer[] dsts, int offset, int length)
|
||||
throws IOException {
|
||||
return sc.read(dsts, offset, length);
|
||||
}
|
||||
|
||||
public Object getAttachment() {
|
||||
Poller pol = getPoller();
|
||||
Selector sel = pol!=null?pol.getSelector():null;
|
||||
SelectionKey key = sel!=null?getIOChannel().keyFor(sel):null;
|
||||
Object att = key!=null?key.attachment():null;
|
||||
return att;
|
||||
}
|
||||
|
||||
public SocketBufferHandler getBufHandler() {
|
||||
return bufHandler;
|
||||
}
|
||||
|
||||
public Poller getPoller() {
|
||||
return poller;
|
||||
}
|
||||
|
||||
public SocketChannel getIOChannel() {
|
||||
return sc;
|
||||
}
|
||||
|
||||
public boolean isClosing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isHandshakeComplete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs SSL handshake hence is a no-op for the non-secure
|
||||
* implementation.
|
||||
*
|
||||
* @param read Unused in non-secure implementation
|
||||
* @param write Unused in non-secure implementation
|
||||
* @return Always returns zero
|
||||
* @throws IOException Never for non-secure channel
|
||||
*/
|
||||
public int handshake(boolean read, boolean write) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setPoller(Poller poller) {
|
||||
this.poller = poller;
|
||||
}
|
||||
|
||||
public void setIOChannel(SocketChannel IOChannel) {
|
||||
this.sc = IOChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+":"+this.sc.toString();
|
||||
}
|
||||
|
||||
public int getOutboundRemaining() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer wrote data. NO-OP for non-secure channel.
|
||||
*
|
||||
* @return Always returns {@code false} for non-secure channel
|
||||
*
|
||||
* @throws IOException Never for non-secure channel
|
||||
*/
|
||||
public boolean flushOutbound() throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be used to check the interrupt status before
|
||||
* attempting a write.
|
||||
*
|
||||
* If a thread has been interrupted and the interrupt has not been cleared
|
||||
* then an attempt to write to the socket will fail. When this happens the
|
||||
* socket is removed from the poller without the socket being selected. This
|
||||
* results in a connection limit leak for NIO as the endpoint expects the
|
||||
* socket to be selected even in error conditions.
|
||||
* @throws IOException If the current thread was interrupted
|
||||
*/
|
||||
protected void checkInterruptStatus() throws IOException {
|
||||
if (Thread.interrupted()) {
|
||||
throw new IOException(sm.getString("channel.nio.interrupted"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ApplicationBufferHandler appReadBufHandler;
|
||||
public void setAppReadBufHandler(ApplicationBufferHandler handler) {
|
||||
this.appReadBufHandler = handler;
|
||||
}
|
||||
protected ApplicationBufferHandler getAppReadBufHandler() {
|
||||
return appReadBufHandler;
|
||||
}
|
||||
}
|
||||
1666
java/org/apache/tomcat/util/net/NioEndpoint.java
Normal file
1666
java/org/apache/tomcat/util/net/NioEndpoint.java
Normal file
File diff suppressed because it is too large
Load Diff
320
java/org/apache/tomcat/util/net/NioSelectorPool.java
Normal file
320
java/org/apache/tomcat/util/net/NioSelectorPool.java
Normal file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* Thread safe non blocking selector pool
|
||||
* @version 1.0
|
||||
* @since 6.0
|
||||
*/
|
||||
|
||||
public class NioSelectorPool {
|
||||
|
||||
public NioSelectorPool() {
|
||||
}
|
||||
|
||||
private static final Log log = LogFactory.getLog(NioSelectorPool.class);
|
||||
|
||||
protected static final boolean SHARED =
|
||||
Boolean.parseBoolean(System.getProperty("org.apache.tomcat.util.net.NioSelectorShared", "true"));
|
||||
|
||||
protected NioBlockingSelector blockingSelector;
|
||||
|
||||
protected volatile Selector SHARED_SELECTOR;
|
||||
|
||||
protected int maxSelectors = 200;
|
||||
protected long sharedSelectorTimeout = 30000;
|
||||
protected int maxSpareSelectors = -1;
|
||||
protected boolean enabled = true;
|
||||
protected AtomicInteger active = new AtomicInteger(0);
|
||||
protected AtomicInteger spare = new AtomicInteger(0);
|
||||
protected ConcurrentLinkedQueue<Selector> selectors =
|
||||
new ConcurrentLinkedQueue<>();
|
||||
|
||||
protected Selector getSharedSelector() throws IOException {
|
||||
if (SHARED && SHARED_SELECTOR == null) {
|
||||
synchronized ( NioSelectorPool.class ) {
|
||||
if ( SHARED_SELECTOR == null ) {
|
||||
SHARED_SELECTOR = Selector.open();
|
||||
log.info("Using a shared selector for servlet write/read");
|
||||
}
|
||||
}
|
||||
}
|
||||
return SHARED_SELECTOR;
|
||||
}
|
||||
|
||||
public Selector get() throws IOException{
|
||||
if ( SHARED ) {
|
||||
return getSharedSelector();
|
||||
}
|
||||
if ( (!enabled) || active.incrementAndGet() >= maxSelectors ) {
|
||||
if ( enabled ) active.decrementAndGet();
|
||||
return null;
|
||||
}
|
||||
Selector s = null;
|
||||
try {
|
||||
s = selectors.size()>0?selectors.poll():null;
|
||||
if (s == null) {
|
||||
s = Selector.open();
|
||||
}
|
||||
else spare.decrementAndGet();
|
||||
|
||||
}catch (NoSuchElementException x ) {
|
||||
try {
|
||||
s = Selector.open();
|
||||
} catch (IOException iox) {
|
||||
}
|
||||
} finally {
|
||||
if ( s == null ) active.decrementAndGet();//we were unable to find a selector
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void put(Selector s) throws IOException {
|
||||
if ( SHARED ) return;
|
||||
if ( enabled ) active.decrementAndGet();
|
||||
if ( enabled && (maxSpareSelectors==-1 || spare.get() < Math.min(maxSpareSelectors,maxSelectors)) ) {
|
||||
spare.incrementAndGet();
|
||||
selectors.offer(s);
|
||||
}
|
||||
else s.close();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
enabled = false;
|
||||
Selector s;
|
||||
while ( (s = selectors.poll()) != null ) s.close();
|
||||
spare.set(0);
|
||||
active.set(0);
|
||||
if (blockingSelector!=null) {
|
||||
blockingSelector.close();
|
||||
}
|
||||
if ( SHARED && getSharedSelector()!=null ) {
|
||||
getSharedSelector().close();
|
||||
SHARED_SELECTOR = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void open() throws IOException {
|
||||
enabled = true;
|
||||
getSharedSelector();
|
||||
if (SHARED) {
|
||||
blockingSelector = new NioBlockingSelector();
|
||||
blockingSelector.open(getSharedSelector());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a write using the bytebuffer for data to be written and a
|
||||
* selector to block (if blocking is requested). If the
|
||||
* <code>selector</code> parameter is null, and blocking is requested then
|
||||
* it will perform a busy write that could take up a lot of CPU cycles.
|
||||
* @param buf The buffer containing the data, we will write as long as <code>(buf.hasRemaining()==true)</code>
|
||||
* @param socket The socket to write data to
|
||||
* @param selector The selector to use for blocking, if null then a busy write will be initiated
|
||||
* @param writeTimeout The timeout for this write operation in milliseconds, -1 means no timeout
|
||||
* @param block <code>true</code> to perform a blocking write
|
||||
* otherwise a non-blocking write will be performed
|
||||
* @return int - returns the number of bytes written
|
||||
* @throws EOFException if write returns -1
|
||||
* @throws SocketTimeoutException if the write times out
|
||||
* @throws IOException if an IO Exception occurs in the underlying socket logic
|
||||
*/
|
||||
public int write(ByteBuffer buf, NioChannel socket, Selector selector,
|
||||
long writeTimeout, boolean block) throws IOException {
|
||||
if ( SHARED && block ) {
|
||||
return blockingSelector.write(buf,socket,writeTimeout);
|
||||
}
|
||||
SelectionKey key = null;
|
||||
int written = 0;
|
||||
boolean timedout = false;
|
||||
int keycount = 1; //assume we can write
|
||||
long time = System.currentTimeMillis(); //start the timeout timer
|
||||
try {
|
||||
while ( (!timedout) && buf.hasRemaining() ) {
|
||||
int cnt = 0;
|
||||
if ( keycount > 0 ) { //only write if we were registered for a write
|
||||
cnt = socket.write(buf); //write the data
|
||||
if (cnt == -1) throw new EOFException();
|
||||
|
||||
written += cnt;
|
||||
if (cnt > 0) {
|
||||
time = System.currentTimeMillis(); //reset our timeout timer
|
||||
continue; //we successfully wrote, try again without a selector
|
||||
}
|
||||
if (cnt==0 && (!block)) break; //don't block
|
||||
}
|
||||
if ( selector != null ) {
|
||||
//register OP_WRITE to the selector
|
||||
if (key==null) key = socket.getIOChannel().register(selector, SelectionKey.OP_WRITE);
|
||||
else key.interestOps(SelectionKey.OP_WRITE);
|
||||
if (writeTimeout==0) {
|
||||
timedout = buf.hasRemaining();
|
||||
} else if (writeTimeout<0) {
|
||||
keycount = selector.select();
|
||||
} else {
|
||||
keycount = selector.select(writeTimeout);
|
||||
}
|
||||
}
|
||||
if (writeTimeout > 0 && (selector == null || keycount == 0) ) timedout = (System.currentTimeMillis()-time)>=writeTimeout;
|
||||
}//while
|
||||
if ( timedout ) throw new SocketTimeoutException();
|
||||
} finally {
|
||||
if (key != null) {
|
||||
key.cancel();
|
||||
if (selector != null) selector.selectNow();//removes the key from this selector
|
||||
}
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a blocking read using the bytebuffer for data to be read and a selector to block.
|
||||
* If the <code>selector</code> parameter is null, then it will perform a busy read that could
|
||||
* take up a lot of CPU cycles.
|
||||
* @param buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out
|
||||
* @param socket SocketChannel - the socket to write data to
|
||||
* @param selector Selector - the selector to use for blocking, if null then a busy read will be initiated
|
||||
* @param readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout
|
||||
* @return int - returns the number of bytes read
|
||||
* @throws EOFException if read returns -1
|
||||
* @throws SocketTimeoutException if the read times out
|
||||
* @throws IOException if an IO Exception occurs in the underlying socket logic
|
||||
*/
|
||||
public int read(ByteBuffer buf, NioChannel socket, Selector selector, long readTimeout) throws IOException {
|
||||
return read(buf,socket,selector,readTimeout,true);
|
||||
}
|
||||
/**
|
||||
* Performs a read using the bytebuffer for data to be read and a selector to register for events should
|
||||
* you have the block=true.
|
||||
* If the <code>selector</code> parameter is null, then it will perform a busy read that could
|
||||
* take up a lot of CPU cycles.
|
||||
* @param buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out
|
||||
* @param socket SocketChannel - the socket to write data to
|
||||
* @param selector Selector - the selector to use for blocking, if null then a busy read will be initiated
|
||||
* @param readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout
|
||||
* @param block - true if you want to block until data becomes available or timeout time has been reached
|
||||
* @return int - returns the number of bytes read
|
||||
* @throws EOFException if read returns -1
|
||||
* @throws SocketTimeoutException if the read times out
|
||||
* @throws IOException if an IO Exception occurs in the underlying socket logic
|
||||
*/
|
||||
public int read(ByteBuffer buf, NioChannel socket, Selector selector, long readTimeout, boolean block) throws IOException {
|
||||
if ( SHARED && block ) {
|
||||
return blockingSelector.read(buf,socket,readTimeout);
|
||||
}
|
||||
SelectionKey key = null;
|
||||
int read = 0;
|
||||
boolean timedout = false;
|
||||
int keycount = 1; //assume we can write
|
||||
long time = System.currentTimeMillis(); //start the timeout timer
|
||||
try {
|
||||
while ( (!timedout) ) {
|
||||
int cnt = 0;
|
||||
if ( keycount > 0 ) { //only read if we were registered for a read
|
||||
cnt = socket.read(buf);
|
||||
if (cnt == -1) {
|
||||
if (read == 0) {
|
||||
read = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
read += cnt;
|
||||
if (cnt > 0) continue; //read some more
|
||||
if (cnt==0 && (read>0 || (!block) ) ) break; //we are done reading
|
||||
}
|
||||
if ( selector != null ) {//perform a blocking read
|
||||
//register OP_WRITE to the selector
|
||||
if (key==null) key = socket.getIOChannel().register(selector, SelectionKey.OP_READ);
|
||||
else key.interestOps(SelectionKey.OP_READ);
|
||||
if (readTimeout==0) {
|
||||
timedout = (read==0);
|
||||
} else if (readTimeout<0) {
|
||||
keycount = selector.select();
|
||||
} else {
|
||||
keycount = selector.select(readTimeout);
|
||||
}
|
||||
}
|
||||
if (readTimeout > 0 && (selector == null || keycount == 0) ) timedout = (System.currentTimeMillis()-time)>=readTimeout;
|
||||
}//while
|
||||
if ( timedout ) throw new SocketTimeoutException();
|
||||
} finally {
|
||||
if (key != null) {
|
||||
key.cancel();
|
||||
if (selector != null) selector.selectNow();//removes the key from this selector
|
||||
}
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
public void setMaxSelectors(int maxSelectors) {
|
||||
this.maxSelectors = maxSelectors;
|
||||
}
|
||||
|
||||
public void setMaxSpareSelectors(int maxSpareSelectors) {
|
||||
this.maxSpareSelectors = maxSpareSelectors;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public void setSharedSelectorTimeout(long sharedSelectorTimeout) {
|
||||
this.sharedSelectorTimeout = sharedSelectorTimeout;
|
||||
}
|
||||
|
||||
public int getMaxSelectors() {
|
||||
return maxSelectors;
|
||||
}
|
||||
|
||||
public int getMaxSpareSelectors() {
|
||||
return maxSpareSelectors;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public long getSharedSelectorTimeout() {
|
||||
return sharedSelectorTimeout;
|
||||
}
|
||||
|
||||
public ConcurrentLinkedQueue<Selector> getSelectors() {
|
||||
return selectors;
|
||||
}
|
||||
|
||||
public AtomicInteger getSpare() {
|
||||
return spare;
|
||||
}
|
||||
}
|
||||
54
java/org/apache/tomcat/util/net/SSLContext.java
Normal file
54
java/org/apache/tomcat/util/net/SSLContext.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
|
||||
/**
|
||||
* This interface is needed to override the default SSLContext class
|
||||
* to allow SSL implementation pluggability without having to use JCE. With
|
||||
* regular JSSE it will do nothing but delegate to the SSLContext.
|
||||
*/
|
||||
public interface SSLContext {
|
||||
|
||||
public void init(KeyManager[] kms, TrustManager[] tms,
|
||||
SecureRandom sr) throws KeyManagementException;
|
||||
|
||||
public void destroy();
|
||||
|
||||
public SSLSessionContext getServerSessionContext();
|
||||
|
||||
public SSLEngine createSSLEngine();
|
||||
|
||||
public SSLServerSocketFactory getServerSocketFactory();
|
||||
|
||||
public SSLParameters getSupportedSSLParameters();
|
||||
|
||||
public X509Certificate[] getCertificateChain(String alias);
|
||||
|
||||
public X509Certificate[] getAcceptedIssuers();
|
||||
}
|
||||
916
java/org/apache/tomcat/util/net/SSLHostConfig.java
Normal file
916
java/org/apache/tomcat/util/net/SSLHostConfig.java
Normal file
@@ -0,0 +1,916 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.security.KeyStore;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.compat.JreCompat;
|
||||
import org.apache.tomcat.util.net.openssl.OpenSSLConf;
|
||||
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
|
||||
import org.apache.tomcat.util.net.openssl.ciphers.OpenSSLCipherConfigurationParser;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Represents the TLS configuration for a virtual host.
|
||||
*/
|
||||
public class SSLHostConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Log log = LogFactory.getLog(SSLHostConfig.class);
|
||||
private static final StringManager sm = StringManager.getManager(SSLHostConfig.class);
|
||||
|
||||
private static final String DEFAULT_CIPHERS = "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA";
|
||||
|
||||
protected static final String DEFAULT_SSL_HOST_NAME = "_default_";
|
||||
protected static final Set<String> SSL_PROTO_ALL_SET = new HashSet<>();
|
||||
|
||||
static {
|
||||
/* Default used if protocols are not configured, also used if
|
||||
* protocols="All"
|
||||
*/
|
||||
SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_SSLv2Hello);
|
||||
SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_TLSv1);
|
||||
SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_TLSv1_1);
|
||||
SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_TLSv1_2);
|
||||
SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_TLSv1_3);
|
||||
}
|
||||
|
||||
private Type configType = null;
|
||||
|
||||
private String hostName = DEFAULT_SSL_HOST_NAME;
|
||||
|
||||
private transient Long openSslConfContext = Long.valueOf(0);
|
||||
// OpenSSL can handle multiple certs in a single config so the reference to
|
||||
// the context is here at the virtual host level. JSSE can't so the
|
||||
// reference is held on the certificate.
|
||||
private transient Long openSslContext = Long.valueOf(0);
|
||||
|
||||
// Configuration properties
|
||||
|
||||
// Internal
|
||||
private String[] enabledCiphers;
|
||||
private String[] enabledProtocols;
|
||||
private ObjectName oname;
|
||||
// Need to know if TLS 1.3 has been explicitly requested as a warning needs
|
||||
// to generated if it is explicitly requested for a JVM that does not
|
||||
// support it. Uses a set so it is extensible for TLS 1.4 etc.
|
||||
private Set<String> explicitlyRequestedProtocols = new HashSet<>();
|
||||
// Nested
|
||||
private SSLHostConfigCertificate defaultCertificate = null;
|
||||
private Set<SSLHostConfigCertificate> certificates = new LinkedHashSet<>(4);
|
||||
// Common
|
||||
private String certificateRevocationListFile;
|
||||
private CertificateVerification certificateVerification = CertificateVerification.NONE;
|
||||
private int certificateVerificationDepth = 10;
|
||||
// Used to track if certificateVerificationDepth has been explicitly set
|
||||
private boolean certificateVerificationDepthConfigured = false;
|
||||
private String ciphers;
|
||||
private LinkedHashSet<Cipher> cipherList = null;
|
||||
private List<String> jsseCipherNames = null;
|
||||
private String honorCipherOrder = null;
|
||||
private Set<String> protocols = new HashSet<>();
|
||||
// Values <0 mean use the implementation default
|
||||
private int sessionCacheSize = -1;
|
||||
private int sessionTimeout = 86400;
|
||||
// JSSE
|
||||
private String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
|
||||
private boolean revocationEnabled = false;
|
||||
private String sslProtocol = Constants.SSL_PROTO_TLS;
|
||||
private String trustManagerClassName;
|
||||
private String truststoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||
private String truststoreFile = System.getProperty("javax.net.ssl.trustStore");
|
||||
private String truststorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
|
||||
private String truststoreProvider = System.getProperty("javax.net.ssl.trustStoreProvider");
|
||||
private String truststoreType = System.getProperty("javax.net.ssl.trustStoreType");
|
||||
private transient KeyStore truststore = null;
|
||||
// OpenSSL
|
||||
private String certificateRevocationListPath;
|
||||
private String caCertificateFile;
|
||||
private String caCertificatePath;
|
||||
private boolean disableCompression = true;
|
||||
private boolean disableSessionTickets = false;
|
||||
private boolean insecureRenegotiation = false;
|
||||
private OpenSSLConf openSslConf = null;
|
||||
|
||||
public SSLHostConfig() {
|
||||
// Set defaults that can't be (easily) set when defining the fields.
|
||||
setProtocols(Constants.SSL_PROTO_ALL);
|
||||
}
|
||||
|
||||
|
||||
public Long getOpenSslConfContext() {
|
||||
return openSslConfContext;
|
||||
}
|
||||
|
||||
|
||||
public void setOpenSslConfContext(Long openSslConfContext) {
|
||||
this.openSslConfContext = openSslConfContext;
|
||||
}
|
||||
|
||||
|
||||
public Long getOpenSslContext() {
|
||||
return openSslContext;
|
||||
}
|
||||
|
||||
|
||||
public void setOpenSslContext(Long openSslContext) {
|
||||
this.openSslContext = openSslContext;
|
||||
}
|
||||
|
||||
|
||||
// Expose in String form for JMX
|
||||
public String getConfigType() {
|
||||
return configType.name();
|
||||
}
|
||||
|
||||
|
||||
void setProperty(String name, Type configType) {
|
||||
if (this.configType == null) {
|
||||
this.configType = configType;
|
||||
} else {
|
||||
if (configType != this.configType) {
|
||||
log.warn(sm.getString("sslHostConfig.mismatch",
|
||||
name, getHostName(), configType, this.configType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------- Internal properties
|
||||
|
||||
/**
|
||||
* @see SSLUtil#getEnabledProtocols()
|
||||
*
|
||||
* @return The protocols enabled for this TLS virtual host
|
||||
*/
|
||||
public String[] getEnabledProtocols() {
|
||||
return enabledProtocols;
|
||||
}
|
||||
|
||||
|
||||
public void setEnabledProtocols(String[] enabledProtocols) {
|
||||
this.enabledProtocols = enabledProtocols;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see SSLUtil#getEnabledCiphers()
|
||||
*
|
||||
* @return The ciphers enabled for this TLS virtual host
|
||||
*/
|
||||
public String[] getEnabledCiphers() {
|
||||
return enabledCiphers;
|
||||
}
|
||||
|
||||
|
||||
public void setEnabledCiphers(String[] enabledCiphers) {
|
||||
this.enabledCiphers = enabledCiphers;
|
||||
}
|
||||
|
||||
|
||||
public ObjectName getObjectName() {
|
||||
return oname;
|
||||
}
|
||||
|
||||
|
||||
public void setObjectName(ObjectName oname) {
|
||||
this.oname = oname;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------- Nested configuration elements
|
||||
|
||||
private void registerDefaultCertificate() {
|
||||
if (defaultCertificate == null) {
|
||||
SSLHostConfigCertificate defaultCertificate = new SSLHostConfigCertificate(
|
||||
this, SSLHostConfigCertificate.Type.UNDEFINED);
|
||||
addCertificate(defaultCertificate);
|
||||
this.defaultCertificate = defaultCertificate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addCertificate(SSLHostConfigCertificate certificate) {
|
||||
// Need to make sure that if there is more than one certificate, none of
|
||||
// them have a type of undefined.
|
||||
if (certificates.size() == 0) {
|
||||
certificates.add(certificate);
|
||||
return;
|
||||
}
|
||||
|
||||
if (certificates.size() == 1 &&
|
||||
certificates.iterator().next().getType() == SSLHostConfigCertificate.Type.UNDEFINED ||
|
||||
certificate.getType() == SSLHostConfigCertificate.Type.UNDEFINED) {
|
||||
// Invalid config
|
||||
throw new IllegalArgumentException(sm.getString("sslHostConfig.certificate.notype"));
|
||||
}
|
||||
|
||||
certificates.add(certificate);
|
||||
}
|
||||
|
||||
|
||||
public OpenSSLConf getOpenSslConf() {
|
||||
return openSslConf;
|
||||
}
|
||||
|
||||
|
||||
public void setOpenSslConf(OpenSSLConf conf) {
|
||||
if (conf == null) {
|
||||
throw new IllegalArgumentException(sm.getString("sslHostConfig.opensslconf.null"));
|
||||
} else if (openSslConf != null) {
|
||||
throw new IllegalArgumentException(sm.getString("sslHostConfig.opensslconf.alreadySet"));
|
||||
}
|
||||
setProperty("<OpenSSLConf>", Type.OPENSSL);
|
||||
openSslConf = conf;
|
||||
}
|
||||
|
||||
|
||||
public Set<SSLHostConfigCertificate> getCertificates() {
|
||||
return getCertificates(false);
|
||||
}
|
||||
|
||||
|
||||
public Set<SSLHostConfigCertificate> getCertificates(boolean createDefaultIfEmpty) {
|
||||
if (certificates.size() == 0 && createDefaultIfEmpty) {
|
||||
registerDefaultCertificate();
|
||||
}
|
||||
return certificates;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------- Common configuration properties
|
||||
|
||||
// TODO: This certificate setter can be removed once it is no longer
|
||||
// necessary to support the old configuration attributes (Tomcat 10?).
|
||||
|
||||
public String getCertificateKeyPassword() {
|
||||
if (defaultCertificate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return defaultCertificate.getCertificateKeyPassword();
|
||||
}
|
||||
}
|
||||
public void setCertificateKeyPassword(String certificateKeyPassword) {
|
||||
registerDefaultCertificate();
|
||||
defaultCertificate.setCertificateKeyPassword(certificateKeyPassword);
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateRevocationListFile(String certificateRevocationListFile) {
|
||||
this.certificateRevocationListFile = certificateRevocationListFile;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateRevocationListFile() {
|
||||
return certificateRevocationListFile;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateVerification(String certificateVerification) {
|
||||
try {
|
||||
this.certificateVerification =
|
||||
CertificateVerification.fromString(certificateVerification);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// If the specified value is not recognised, default to the
|
||||
// strictest possible option.
|
||||
this.certificateVerification = CertificateVerification.REQUIRED;
|
||||
throw iae;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public CertificateVerification getCertificateVerification() {
|
||||
return certificateVerification;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateVerificationAsString(String certificateVerification) {
|
||||
setCertificateVerification(certificateVerification);
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateVerificationAsString() {
|
||||
return certificateVerification.toString();
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateVerificationDepth(int certificateVerificationDepth) {
|
||||
this.certificateVerificationDepth = certificateVerificationDepth;
|
||||
certificateVerificationDepthConfigured = true;
|
||||
}
|
||||
|
||||
|
||||
public int getCertificateVerificationDepth() {
|
||||
return certificateVerificationDepth;
|
||||
}
|
||||
|
||||
|
||||
public boolean isCertificateVerificationDepthConfigured() {
|
||||
return certificateVerificationDepthConfigured;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the new cipher configuration. Note: Regardless of the format used to
|
||||
* set the configuration, it is always stored in OpenSSL format.
|
||||
*
|
||||
* @param ciphersList The new cipher configuration in OpenSSL or JSSE format
|
||||
*/
|
||||
public void setCiphers(String ciphersList) {
|
||||
// Ciphers is stored in OpenSSL format. Convert the provided value if
|
||||
// necessary.
|
||||
if (ciphersList != null && !ciphersList.contains(":")) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// Not obviously in OpenSSL format. May be a single OpenSSL or JSSE
|
||||
// cipher name. May be a comma separated list of cipher names
|
||||
String ciphers[] = ciphersList.split(",");
|
||||
for (String cipher : ciphers) {
|
||||
String trimmed = cipher.trim();
|
||||
if (trimmed.length() > 0) {
|
||||
String openSSLName = OpenSSLCipherConfigurationParser.jsseToOpenSSL(trimmed);
|
||||
if (openSSLName == null) {
|
||||
// Not a JSSE name. Maybe an OpenSSL name or alias
|
||||
openSSLName = trimmed;
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
sb.append(':');
|
||||
}
|
||||
sb.append(openSSLName);
|
||||
}
|
||||
}
|
||||
this.ciphers = sb.toString();
|
||||
} else {
|
||||
this.ciphers = ciphersList;
|
||||
}
|
||||
this.cipherList = null;
|
||||
this.jsseCipherNames = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return An OpenSSL cipher string for the current configuration.
|
||||
*/
|
||||
public String getCiphers() {
|
||||
if (ciphers == null) {
|
||||
if (!JreCompat.isJre8Available() && Type.JSSE.equals(configType)) {
|
||||
ciphers = DEFAULT_CIPHERS + ":!DHE";
|
||||
} else {
|
||||
ciphers = DEFAULT_CIPHERS;
|
||||
}
|
||||
|
||||
}
|
||||
return ciphers;
|
||||
}
|
||||
|
||||
|
||||
public LinkedHashSet<Cipher> getCipherList() {
|
||||
if (cipherList == null) {
|
||||
cipherList = OpenSSLCipherConfigurationParser.parse(getCiphers());
|
||||
}
|
||||
return cipherList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the list of JSSE cipher names for the current configuration.
|
||||
* Ciphers included in the configuration but not supported by JSSE will be
|
||||
* excluded from this list.
|
||||
*
|
||||
* @return A list of the JSSE cipher names
|
||||
*/
|
||||
public List<String> getJsseCipherNames() {
|
||||
if (jsseCipherNames == null) {
|
||||
jsseCipherNames = OpenSSLCipherConfigurationParser.convertForJSSE(getCipherList());
|
||||
}
|
||||
return jsseCipherNames;
|
||||
}
|
||||
|
||||
|
||||
public void setHonorCipherOrder(String honorCipherOrder) {
|
||||
this.honorCipherOrder = honorCipherOrder;
|
||||
}
|
||||
|
||||
|
||||
public String getHonorCipherOrder() {
|
||||
return honorCipherOrder;
|
||||
}
|
||||
|
||||
|
||||
public void setHostName(String hostName) {
|
||||
this.hostName = hostName;
|
||||
}
|
||||
|
||||
|
||||
public String getHostName() {
|
||||
return hostName;
|
||||
}
|
||||
|
||||
|
||||
public void setProtocols(String input) {
|
||||
protocols.clear();
|
||||
explicitlyRequestedProtocols.clear();
|
||||
|
||||
// List of protocol names, separated by ",", "+" or "-".
|
||||
// Semantics is adding ("+") or removing ("-") from left
|
||||
// to right, starting with an empty protocol set.
|
||||
// Tokens are individual protocol names or "all" for a
|
||||
// default set of supported protocols.
|
||||
// Separator "," is only kept for compatibility and has the
|
||||
// same semantics as "+", except that it warns about a potentially
|
||||
// missing "+" or "-".
|
||||
|
||||
// Split using a positive lookahead to keep the separator in
|
||||
// the capture so we can check which case it is.
|
||||
for (String value: input.split("(?=[-+,])")) {
|
||||
String trimmed = value.trim();
|
||||
// Ignore token which only consists of prefix character
|
||||
if (trimmed.length() > 1) {
|
||||
if (trimmed.charAt(0) == '+') {
|
||||
trimmed = trimmed.substring(1).trim();
|
||||
if (trimmed.equalsIgnoreCase(Constants.SSL_PROTO_ALL)) {
|
||||
protocols.addAll(SSL_PROTO_ALL_SET);
|
||||
} else {
|
||||
protocols.add(trimmed);
|
||||
explicitlyRequestedProtocols.add(trimmed);
|
||||
}
|
||||
} else if (trimmed.charAt(0) == '-') {
|
||||
trimmed = trimmed.substring(1).trim();
|
||||
if (trimmed.equalsIgnoreCase(Constants.SSL_PROTO_ALL)) {
|
||||
protocols.removeAll(SSL_PROTO_ALL_SET);
|
||||
} else {
|
||||
protocols.remove(trimmed);
|
||||
explicitlyRequestedProtocols.remove(trimmed);
|
||||
}
|
||||
} else {
|
||||
if (trimmed.charAt(0) == ',') {
|
||||
trimmed = trimmed.substring(1).trim();
|
||||
}
|
||||
if (!protocols.isEmpty()) {
|
||||
log.warn(sm.getString("sslHostConfig.prefix_missing",
|
||||
trimmed, getHostName()));
|
||||
}
|
||||
if (trimmed.equalsIgnoreCase(Constants.SSL_PROTO_ALL)) {
|
||||
protocols.addAll(SSL_PROTO_ALL_SET);
|
||||
} else {
|
||||
protocols.add(trimmed);
|
||||
explicitlyRequestedProtocols.add(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getProtocols() {
|
||||
return protocols;
|
||||
}
|
||||
|
||||
|
||||
boolean isExplicitlyRequestedProtocol(String protocol) {
|
||||
return explicitlyRequestedProtocols.contains(protocol);
|
||||
}
|
||||
|
||||
|
||||
public void setSessionCacheSize(int sessionCacheSize) {
|
||||
this.sessionCacheSize = sessionCacheSize;
|
||||
}
|
||||
|
||||
|
||||
public int getSessionCacheSize() {
|
||||
return sessionCacheSize;
|
||||
}
|
||||
|
||||
|
||||
public void setSessionTimeout(int sessionTimeout) {
|
||||
this.sessionTimeout = sessionTimeout;
|
||||
}
|
||||
|
||||
|
||||
public int getSessionTimeout() {
|
||||
return sessionTimeout;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------- JSSE specific configuration properties
|
||||
|
||||
// TODO: These certificate setters can be removed once it is no longer
|
||||
// necessary to support the old configuration attributes (Tomcat 10?).
|
||||
|
||||
public String getCertificateKeyAlias() {
|
||||
if (defaultCertificate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return defaultCertificate.getCertificateKeyAlias();
|
||||
}
|
||||
}
|
||||
public void setCertificateKeyAlias(String certificateKeyAlias) {
|
||||
registerDefaultCertificate();
|
||||
defaultCertificate.setCertificateKeyAlias(certificateKeyAlias);
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeystoreFile() {
|
||||
if (defaultCertificate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return defaultCertificate.getCertificateKeystoreFile();
|
||||
}
|
||||
}
|
||||
public void setCertificateKeystoreFile(String certificateKeystoreFile) {
|
||||
registerDefaultCertificate();
|
||||
defaultCertificate.setCertificateKeystoreFile(certificateKeystoreFile);
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeystorePassword() {
|
||||
if (defaultCertificate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return defaultCertificate.getCertificateKeystorePassword();
|
||||
}
|
||||
}
|
||||
public void setCertificateKeystorePassword(String certificateKeystorePassword) {
|
||||
registerDefaultCertificate();
|
||||
defaultCertificate.setCertificateKeystorePassword(certificateKeystorePassword);
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeystoreProvider() {
|
||||
if (defaultCertificate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return defaultCertificate.getCertificateKeystoreProvider();
|
||||
}
|
||||
}
|
||||
public void setCertificateKeystoreProvider(String certificateKeystoreProvider) {
|
||||
registerDefaultCertificate();
|
||||
defaultCertificate.setCertificateKeystoreProvider(certificateKeystoreProvider);
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeystoreType() {
|
||||
if (defaultCertificate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return defaultCertificate.getCertificateKeystoreType();
|
||||
}
|
||||
}
|
||||
public void setCertificateKeystoreType(String certificateKeystoreType) {
|
||||
registerDefaultCertificate();
|
||||
defaultCertificate.setCertificateKeystoreType(certificateKeystoreType);
|
||||
}
|
||||
|
||||
|
||||
public void setKeyManagerAlgorithm(String keyManagerAlgorithm) {
|
||||
setProperty("keyManagerAlgorithm", Type.JSSE);
|
||||
this.keyManagerAlgorithm = keyManagerAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
public String getKeyManagerAlgorithm() {
|
||||
return keyManagerAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
public void setRevocationEnabled(boolean revocationEnabled) {
|
||||
setProperty("revocationEnabled", Type.JSSE);
|
||||
this.revocationEnabled = revocationEnabled;
|
||||
}
|
||||
|
||||
|
||||
public boolean getRevocationEnabled() {
|
||||
return revocationEnabled;
|
||||
}
|
||||
|
||||
|
||||
public void setSslProtocol(String sslProtocol) {
|
||||
setProperty("sslProtocol", Type.JSSE);
|
||||
this.sslProtocol = sslProtocol;
|
||||
}
|
||||
|
||||
|
||||
public String getSslProtocol() {
|
||||
return sslProtocol;
|
||||
}
|
||||
|
||||
|
||||
public void setTrustManagerClassName(String trustManagerClassName) {
|
||||
setProperty("trustManagerClassName", Type.JSSE);
|
||||
this.trustManagerClassName = trustManagerClassName;
|
||||
}
|
||||
|
||||
|
||||
public String getTrustManagerClassName() {
|
||||
return trustManagerClassName;
|
||||
}
|
||||
|
||||
|
||||
public void setTruststoreAlgorithm(String truststoreAlgorithm) {
|
||||
setProperty("truststoreAlgorithm", Type.JSSE);
|
||||
this.truststoreAlgorithm = truststoreAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
public String getTruststoreAlgorithm() {
|
||||
return truststoreAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
public void setTruststoreFile(String truststoreFile) {
|
||||
setProperty("truststoreFile", Type.JSSE);
|
||||
this.truststoreFile = truststoreFile;
|
||||
}
|
||||
|
||||
|
||||
public String getTruststoreFile() {
|
||||
return truststoreFile;
|
||||
}
|
||||
|
||||
|
||||
public void setTruststorePassword(String truststorePassword) {
|
||||
setProperty("truststorePassword", Type.JSSE);
|
||||
this.truststorePassword = truststorePassword;
|
||||
}
|
||||
|
||||
|
||||
public String getTruststorePassword() {
|
||||
return truststorePassword;
|
||||
}
|
||||
|
||||
|
||||
public void setTruststoreProvider(String truststoreProvider) {
|
||||
setProperty("truststoreProvider", Type.JSSE);
|
||||
this.truststoreProvider = truststoreProvider;
|
||||
}
|
||||
|
||||
|
||||
public String getTruststoreProvider() {
|
||||
if (truststoreProvider == null) {
|
||||
Set<SSLHostConfigCertificate> certificates = getCertificates();
|
||||
if (certificates.size() == 1) {
|
||||
return certificates.iterator().next().getCertificateKeystoreProvider();
|
||||
}
|
||||
return SSLHostConfigCertificate.DEFAULT_KEYSTORE_PROVIDER;
|
||||
} else {
|
||||
return truststoreProvider;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setTruststoreType(String truststoreType) {
|
||||
setProperty("truststoreType", Type.JSSE);
|
||||
this.truststoreType = truststoreType;
|
||||
}
|
||||
|
||||
|
||||
public String getTruststoreType() {
|
||||
if (truststoreType == null) {
|
||||
Set<SSLHostConfigCertificate> certificates = getCertificates();
|
||||
if (certificates.size() == 1) {
|
||||
String keystoreType = certificates.iterator().next().getCertificateKeystoreType();
|
||||
// Don't use keystore type as the default if we know it is not
|
||||
// going to be used as a trust store type
|
||||
if (!"PKCS12".equalsIgnoreCase(keystoreType)) {
|
||||
return keystoreType;
|
||||
}
|
||||
}
|
||||
return SSLHostConfigCertificate.DEFAULT_KEYSTORE_TYPE;
|
||||
} else {
|
||||
return truststoreType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setTrustStore(KeyStore truststore) {
|
||||
this.truststore = truststore;
|
||||
}
|
||||
|
||||
|
||||
public KeyStore getTruststore() throws IOException {
|
||||
KeyStore result = truststore;
|
||||
if (result == null) {
|
||||
if (truststoreFile != null){
|
||||
try {
|
||||
result = SSLUtilBase.getStore(getTruststoreType(), getTruststoreProvider(),
|
||||
getTruststoreFile(), getTruststorePassword());
|
||||
} catch (IOException ioe) {
|
||||
Throwable cause = ioe.getCause();
|
||||
if (cause instanceof UnrecoverableKeyException) {
|
||||
// Log a warning we had a password issue
|
||||
log.warn(sm.getString("jsse.invalid_truststore_password"),
|
||||
cause);
|
||||
// Re-try
|
||||
result = SSLUtilBase.getStore(getTruststoreType(), getTruststoreProvider(),
|
||||
getTruststoreFile(), null);
|
||||
} else {
|
||||
// Something else went wrong - re-throw
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------- OpenSSL specific configuration properties
|
||||
|
||||
// TODO: These certificate setters can be removed once it is no longer
|
||||
// necessary to support the old configuration attributes (Tomcat 10?).
|
||||
|
||||
public String getCertificateChainFile() {
|
||||
if (defaultCertificate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return defaultCertificate.getCertificateChainFile();
|
||||
}
|
||||
}
|
||||
public void setCertificateChainFile(String certificateChainFile) {
|
||||
registerDefaultCertificate();
|
||||
defaultCertificate.setCertificateChainFile(certificateChainFile);
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateFile() {
|
||||
if (defaultCertificate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return defaultCertificate.getCertificateFile();
|
||||
}
|
||||
}
|
||||
public void setCertificateFile(String certificateFile) {
|
||||
registerDefaultCertificate();
|
||||
defaultCertificate.setCertificateFile(certificateFile);
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeyFile() {
|
||||
if (defaultCertificate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return defaultCertificate.getCertificateKeyFile();
|
||||
}
|
||||
}
|
||||
public void setCertificateKeyFile(String certificateKeyFile) {
|
||||
registerDefaultCertificate();
|
||||
defaultCertificate.setCertificateKeyFile(certificateKeyFile);
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateRevocationListPath(String certificateRevocationListPath) {
|
||||
setProperty("certificateRevocationListPath", Type.OPENSSL);
|
||||
this.certificateRevocationListPath = certificateRevocationListPath;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateRevocationListPath() {
|
||||
return certificateRevocationListPath;
|
||||
}
|
||||
|
||||
|
||||
public void setCaCertificateFile(String caCertificateFile) {
|
||||
setProperty("caCertificateFile", Type.OPENSSL);
|
||||
this.caCertificateFile = caCertificateFile;
|
||||
}
|
||||
|
||||
|
||||
public String getCaCertificateFile() {
|
||||
return caCertificateFile;
|
||||
}
|
||||
|
||||
|
||||
public void setCaCertificatePath(String caCertificatePath) {
|
||||
setProperty("caCertificatePath", Type.OPENSSL);
|
||||
this.caCertificatePath = caCertificatePath;
|
||||
}
|
||||
|
||||
|
||||
public String getCaCertificatePath() {
|
||||
return caCertificatePath;
|
||||
}
|
||||
|
||||
|
||||
public void setDisableCompression(boolean disableCompression) {
|
||||
setProperty("disableCompression", Type.OPENSSL);
|
||||
this.disableCompression = disableCompression;
|
||||
}
|
||||
|
||||
|
||||
public boolean getDisableCompression() {
|
||||
return disableCompression;
|
||||
}
|
||||
|
||||
|
||||
public void setDisableSessionTickets(boolean disableSessionTickets) {
|
||||
setProperty("disableSessionTickets", Type.OPENSSL);
|
||||
this.disableSessionTickets = disableSessionTickets;
|
||||
}
|
||||
|
||||
|
||||
public boolean getDisableSessionTickets() {
|
||||
return disableSessionTickets;
|
||||
}
|
||||
|
||||
|
||||
public void setInsecureRenegotiation(boolean insecureRenegotiation) {
|
||||
setProperty("insecureRenegotiation", Type.OPENSSL);
|
||||
this.insecureRenegotiation = insecureRenegotiation;
|
||||
}
|
||||
|
||||
|
||||
public boolean getInsecureRenegotiation() {
|
||||
return insecureRenegotiation;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Support methods
|
||||
|
||||
public static String adjustRelativePath(String path) throws FileNotFoundException {
|
||||
// Empty or null path can't point to anything useful. The assumption is
|
||||
// that the value is deliberately empty / null so leave it that way.
|
||||
if (path == null || path.length() == 0) {
|
||||
return path;
|
||||
}
|
||||
String newPath = path;
|
||||
File f = new File(newPath);
|
||||
if ( !f.isAbsolute()) {
|
||||
newPath = System.getProperty(Constants.CATALINA_BASE_PROP) + File.separator + newPath;
|
||||
f = new File(newPath);
|
||||
}
|
||||
if (!f.exists()) {
|
||||
throw new FileNotFoundException(sm.getString("sslHostConfig.fileNotFound", newPath));
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------- Inner classes
|
||||
|
||||
public enum Type {
|
||||
JSSE,
|
||||
OPENSSL
|
||||
}
|
||||
|
||||
|
||||
public enum CertificateVerification {
|
||||
NONE,
|
||||
OPTIONAL_NO_CA,
|
||||
OPTIONAL,
|
||||
REQUIRED;
|
||||
|
||||
public static CertificateVerification fromString(String value) {
|
||||
if ("true".equalsIgnoreCase(value) ||
|
||||
"yes".equalsIgnoreCase(value) ||
|
||||
"require".equalsIgnoreCase(value) ||
|
||||
"required".equalsIgnoreCase(value)) {
|
||||
return REQUIRED;
|
||||
} else if ("optional".equalsIgnoreCase(value) ||
|
||||
"want".equalsIgnoreCase(value)) {
|
||||
return OPTIONAL;
|
||||
} else if ("optionalNoCA".equalsIgnoreCase(value) ||
|
||||
"optional_no_ca".equalsIgnoreCase(value)) {
|
||||
return OPTIONAL_NO_CA;
|
||||
} else if ("false".equalsIgnoreCase(value) ||
|
||||
"no".equalsIgnoreCase(value) ||
|
||||
"none".equalsIgnoreCase(value)) {
|
||||
return NONE;
|
||||
} else {
|
||||
// Could be a typo. Don't default to NONE since that is not
|
||||
// secure. Force user to fix config. Could default to REQUIRED
|
||||
// instead.
|
||||
throw new IllegalArgumentException(
|
||||
sm.getString("sslHostConfig.certificateVerificationInvalid", value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
298
java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java
Normal file
298
java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.security.KeyStore;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.net.openssl.ciphers.Authentication;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
public class SSLHostConfigCertificate implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Log log = LogFactory.getLog(SSLHostConfigCertificate.class);
|
||||
private static final StringManager sm = StringManager.getManager(SSLHostConfigCertificate.class);
|
||||
|
||||
public static final Type DEFAULT_TYPE = Type.UNDEFINED;
|
||||
|
||||
static final String DEFAULT_KEYSTORE_PROVIDER =
|
||||
System.getProperty("javax.net.ssl.keyStoreProvider");
|
||||
static final String DEFAULT_KEYSTORE_TYPE =
|
||||
System.getProperty("javax.net.ssl.keyStoreType", "JKS");
|
||||
|
||||
// Internal
|
||||
private ObjectName oname;
|
||||
|
||||
// OpenSSL can handle multiple certs in a single config so the reference to
|
||||
// the context is at the virtual host level. JSSE can't so the reference is
|
||||
// held here on the certificate.
|
||||
private transient SSLContext sslContext;
|
||||
|
||||
// Common
|
||||
private final SSLHostConfig sslHostConfig;
|
||||
private final Type type;
|
||||
private String certificateKeyPassword = null;
|
||||
|
||||
// JSSE
|
||||
private String certificateKeyAlias;
|
||||
private String certificateKeystorePassword = "changeit";
|
||||
private String certificateKeystoreFile = System.getProperty("user.home")+"/.keystore";
|
||||
private String certificateKeystoreProvider = DEFAULT_KEYSTORE_PROVIDER;
|
||||
private String certificateKeystoreType = DEFAULT_KEYSTORE_TYPE;
|
||||
private transient KeyStore certificateKeystore = null;
|
||||
private transient X509KeyManager certificateKeyManager = null;
|
||||
|
||||
// OpenSSL
|
||||
private String certificateChainFile;
|
||||
private String certificateFile;
|
||||
private String certificateKeyFile;
|
||||
|
||||
// Certificate store type
|
||||
private StoreType storeType = null;
|
||||
|
||||
public SSLHostConfigCertificate() {
|
||||
this(null, Type.UNDEFINED);
|
||||
}
|
||||
|
||||
public SSLHostConfigCertificate(SSLHostConfig sslHostConfig, Type type) {
|
||||
this.sslHostConfig = sslHostConfig;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
public SSLContext getSslContext() {
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
|
||||
public void setSslContext(SSLContext sslContext) {
|
||||
this.sslContext = sslContext;
|
||||
}
|
||||
|
||||
|
||||
public SSLHostConfig getSSLHostConfig() {
|
||||
return sslHostConfig;
|
||||
}
|
||||
|
||||
|
||||
// Internal
|
||||
|
||||
public ObjectName getObjectName() {
|
||||
return oname;
|
||||
}
|
||||
|
||||
|
||||
public void setObjectName(ObjectName oname) {
|
||||
this.oname = oname;
|
||||
}
|
||||
|
||||
|
||||
// Common
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeyPassword() {
|
||||
return certificateKeyPassword;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateKeyPassword(String certificateKeyPassword) {
|
||||
this.certificateKeyPassword = certificateKeyPassword;
|
||||
}
|
||||
|
||||
|
||||
// JSSE
|
||||
|
||||
public void setCertificateKeyAlias(String certificateKeyAlias) {
|
||||
sslHostConfig.setProperty(
|
||||
"Certificate.certificateKeyAlias", SSLHostConfig.Type.JSSE);
|
||||
this.certificateKeyAlias = certificateKeyAlias;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeyAlias() {
|
||||
return certificateKeyAlias;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateKeystoreFile(String certificateKeystoreFile) {
|
||||
sslHostConfig.setProperty(
|
||||
"Certificate.certificateKeystoreFile", SSLHostConfig.Type.JSSE);
|
||||
setStoreType("Certificate.certificateKeystoreFile", StoreType.KEYSTORE);
|
||||
this.certificateKeystoreFile = certificateKeystoreFile;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeystoreFile() {
|
||||
return certificateKeystoreFile;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateKeystorePassword(String certificateKeystorePassword) {
|
||||
sslHostConfig.setProperty(
|
||||
"Certificate.certificateKeystorePassword", SSLHostConfig.Type.JSSE);
|
||||
setStoreType("Certificate.certificateKeystorePassword", StoreType.KEYSTORE);
|
||||
this.certificateKeystorePassword = certificateKeystorePassword;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeystorePassword() {
|
||||
return certificateKeystorePassword;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateKeystoreProvider(String certificateKeystoreProvider) {
|
||||
sslHostConfig.setProperty(
|
||||
"Certificate.certificateKeystoreProvider", SSLHostConfig.Type.JSSE);
|
||||
setStoreType("Certificate.certificateKeystoreProvider", StoreType.KEYSTORE);
|
||||
this.certificateKeystoreProvider = certificateKeystoreProvider;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeystoreProvider() {
|
||||
return certificateKeystoreProvider;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateKeystoreType(String certificateKeystoreType) {
|
||||
sslHostConfig.setProperty(
|
||||
"Certificate.certificateKeystoreType", SSLHostConfig.Type.JSSE);
|
||||
setStoreType("Certificate.certificateKeystoreType", StoreType.KEYSTORE);
|
||||
this.certificateKeystoreType = certificateKeystoreType;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeystoreType() {
|
||||
return certificateKeystoreType;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateKeystore(KeyStore certificateKeystore) {
|
||||
this.certificateKeystore = certificateKeystore;
|
||||
}
|
||||
|
||||
|
||||
public KeyStore getCertificateKeystore() throws IOException {
|
||||
KeyStore result = certificateKeystore;
|
||||
|
||||
if (result == null && storeType == StoreType.KEYSTORE) {
|
||||
result = SSLUtilBase.getStore(getCertificateKeystoreType(),
|
||||
getCertificateKeystoreProvider(), getCertificateKeystoreFile(),
|
||||
getCertificateKeystorePassword());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateKeyManager(X509KeyManager certificateKeyManager) {
|
||||
this.certificateKeyManager = certificateKeyManager;
|
||||
}
|
||||
|
||||
|
||||
public X509KeyManager getCertificateKeyManager() {
|
||||
return certificateKeyManager;
|
||||
}
|
||||
|
||||
|
||||
// OpenSSL
|
||||
|
||||
public void setCertificateChainFile(String certificateChainFile) {
|
||||
setStoreType("Certificate.certificateChainFile", StoreType.PEM);
|
||||
this.certificateChainFile = certificateChainFile;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateChainFile() {
|
||||
return certificateChainFile;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateFile(String certificateFile) {
|
||||
setStoreType("Certificate.certificateFile", StoreType.PEM);
|
||||
this.certificateFile = certificateFile;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateFile() {
|
||||
return certificateFile;
|
||||
}
|
||||
|
||||
|
||||
public void setCertificateKeyFile(String certificateKeyFile) {
|
||||
setStoreType("Certificate.certificateKeyFile", StoreType.PEM);
|
||||
this.certificateKeyFile = certificateKeyFile;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateKeyFile() {
|
||||
return certificateKeyFile;
|
||||
}
|
||||
|
||||
|
||||
private void setStoreType(String name, StoreType type) {
|
||||
if (storeType == null) {
|
||||
storeType = type;
|
||||
} else if (storeType != type) {
|
||||
log.warn(sm.getString("sslHostConfigCertificate.mismatch",
|
||||
name, sslHostConfig.getHostName(), type, this.storeType));
|
||||
}
|
||||
}
|
||||
|
||||
// Nested types
|
||||
|
||||
public enum Type {
|
||||
|
||||
UNDEFINED,
|
||||
RSA(Authentication.RSA),
|
||||
DSA(Authentication.DSS),
|
||||
EC(Authentication.ECDH, Authentication.ECDSA);
|
||||
|
||||
private final Set<Authentication> compatibleAuthentications;
|
||||
|
||||
private Type(Authentication... authentications) {
|
||||
compatibleAuthentications = new HashSet<>();
|
||||
if (authentications != null) {
|
||||
for (Authentication authentication : authentications) {
|
||||
compatibleAuthentications.add(authentication);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCompatibleWith(Authentication au) {
|
||||
return compatibleAuthentications.contains(au);
|
||||
}
|
||||
}
|
||||
|
||||
enum StoreType {
|
||||
KEYSTORE,
|
||||
PEM
|
||||
}
|
||||
}
|
||||
72
java/org/apache/tomcat/util/net/SSLImplementation.java
Normal file
72
java/org/apache/tomcat/util/net/SSLImplementation.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.net.jsse.JSSEImplementation;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Provides a factory and base implementation for the Tomcat specific mechanism
|
||||
* that allows alternative SSL/TLS implementations to be used without requiring
|
||||
* the implementation of a full JSSE provider.
|
||||
*/
|
||||
public abstract class SSLImplementation {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SSLImplementation.class);
|
||||
private static final StringManager sm = StringManager.getManager(SSLImplementation.class);
|
||||
|
||||
/**
|
||||
* Obtain an instance (not a singleton) of the implementation with the given
|
||||
* class name.
|
||||
*
|
||||
* @param className The class name of the required implementation or null to
|
||||
* use the default (currently {@link JSSEImplementation}.
|
||||
*
|
||||
* @return An instance of the required implementation
|
||||
*
|
||||
* @throws ClassNotFoundException If an instance of the requested class
|
||||
* cannot be created
|
||||
*/
|
||||
public static SSLImplementation getInstance(String className)
|
||||
throws ClassNotFoundException {
|
||||
if (className == null)
|
||||
return new JSSEImplementation();
|
||||
|
||||
try {
|
||||
Class<?> clazz = Class.forName(className);
|
||||
return (SSLImplementation) clazz.getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
String msg = sm.getString("sslImplementation.cnfe", className);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(msg, e);
|
||||
}
|
||||
throw new ClassNotFoundException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract SSLSupport getSSLSupport(SSLSession session);
|
||||
|
||||
public abstract SSLUtil getSSLUtil(SSLHostConfigCertificate certificate);
|
||||
|
||||
public abstract boolean isAlpnSupported();
|
||||
}
|
||||
29
java/org/apache/tomcat/util/net/SSLSessionManager.java
Normal file
29
java/org/apache/tomcat/util/net/SSLSessionManager.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
/**
|
||||
* Defines an interface used to manage SSL sessions. The manager operates on a
|
||||
* single session.
|
||||
*/
|
||||
public interface SSLSessionManager {
|
||||
/**
|
||||
* Invalidate the SSL session
|
||||
*/
|
||||
public void invalidateSession();
|
||||
}
|
||||
125
java/org/apache/tomcat/util/net/SSLSupport.java
Normal file
125
java/org/apache/tomcat/util/net/SSLSupport.java
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* Defines an interface to interact with SSL sessions.
|
||||
*/
|
||||
public interface SSLSupport {
|
||||
/**
|
||||
* The Request attribute key for the cipher suite.
|
||||
*/
|
||||
public static final String CIPHER_SUITE_KEY =
|
||||
"javax.servlet.request.cipher_suite";
|
||||
|
||||
/**
|
||||
* The Request attribute key for the key size.
|
||||
*/
|
||||
public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size";
|
||||
|
||||
/**
|
||||
* The Request attribute key for the client certificate chain.
|
||||
*/
|
||||
public static final String CERTIFICATE_KEY =
|
||||
"javax.servlet.request.X509Certificate";
|
||||
|
||||
/**
|
||||
* The Request attribute key for the session id.
|
||||
* This one is a Tomcat extension to the Servlet spec.
|
||||
*/
|
||||
public static final String SESSION_ID_KEY =
|
||||
"javax.servlet.request.ssl_session_id";
|
||||
|
||||
/**
|
||||
* The request attribute key for the session manager.
|
||||
* This one is a Tomcat extension to the Servlet spec.
|
||||
*/
|
||||
public static final String SESSION_MGR =
|
||||
"javax.servlet.request.ssl_session_mgr";
|
||||
|
||||
/**
|
||||
* The request attribute key under which the String indicating the protocol
|
||||
* that created the SSL socket is recorded - e.g. TLSv1 or TLSv1.2 etc.
|
||||
*/
|
||||
public static final String PROTOCOL_VERSION_KEY =
|
||||
"org.apache.tomcat.util.net.secure_protocol_version";
|
||||
|
||||
/**
|
||||
* The cipher suite being used on this connection.
|
||||
*
|
||||
* @return The name of the cipher suite as returned by the SSL/TLS
|
||||
* implementation
|
||||
*
|
||||
* @throws IOException If an error occurs trying to obtain the cipher suite
|
||||
*/
|
||||
public String getCipherSuite() throws IOException;
|
||||
|
||||
/**
|
||||
* The client certificate chain (if any).
|
||||
*
|
||||
* @return The certificate chain presented by the client with the peer's
|
||||
* certificate first, followed by those of any certificate
|
||||
* authorities
|
||||
*
|
||||
* @throws IOException If an error occurs trying to obtain the certificate
|
||||
* chain
|
||||
*/
|
||||
public X509Certificate[] getPeerCertificateChain() throws IOException;
|
||||
|
||||
/**
|
||||
* Get the keysize.
|
||||
*
|
||||
* What we're supposed to put here is ill-defined by the
|
||||
* Servlet spec (S 4.7 again). There are at least 4 potential
|
||||
* values that might go here:
|
||||
*
|
||||
* (a) The size of the encryption key
|
||||
* (b) The size of the MAC key
|
||||
* (c) The size of the key-exchange key
|
||||
* (d) The size of the signature key used by the server
|
||||
*
|
||||
* Unfortunately, all of these values are nonsensical.
|
||||
*
|
||||
* @return The effective key size for the current cipher suite
|
||||
*
|
||||
* @throws IOException If an error occurs trying to obtain the key size
|
||||
*/
|
||||
public Integer getKeySize() throws IOException;
|
||||
|
||||
/**
|
||||
* The current session Id.
|
||||
*
|
||||
* @return The current SSL/TLS session ID
|
||||
*
|
||||
* @throws IOException If an error occurs trying to obtain the session ID
|
||||
*/
|
||||
public String getSessionId() throws IOException;
|
||||
|
||||
/**
|
||||
* @return the protocol String indicating how the SSL socket was created
|
||||
* e.g. TLSv1 or TLSv1.2 etc.
|
||||
*
|
||||
* @throws IOException If an error occurs trying to obtain the protocol
|
||||
* information from the socket
|
||||
*/
|
||||
public String getProtocol() throws IOException;
|
||||
}
|
||||
|
||||
82
java/org/apache/tomcat/util/net/SSLUtil.java
Normal file
82
java/org/apache/tomcat/util/net/SSLUtil.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
|
||||
/**
|
||||
* Provides a common interface for {@link SSLImplementation}s to create the
|
||||
* necessary JSSE implementation objects for TLS connections created via the
|
||||
* JSSE API.
|
||||
*/
|
||||
public interface SSLUtil {
|
||||
|
||||
public SSLContext createSSLContext(List<String> negotiableProtocols) throws Exception;
|
||||
|
||||
public KeyManager[] getKeyManagers() throws Exception;
|
||||
|
||||
public TrustManager[] getTrustManagers() throws Exception;
|
||||
|
||||
public void configureSessionContext(SSLSessionContext sslSessionContext);
|
||||
|
||||
/**
|
||||
* The set of enabled protocols is the intersection of the implemented
|
||||
* protocols and the configured protocols. If no protocols are explicitly
|
||||
* configured, then all of the implemented protocols will be included in the
|
||||
* returned array.
|
||||
*
|
||||
* @return The protocols currently enabled and available for clients to
|
||||
* select from for the associated connection
|
||||
*
|
||||
* @throws IllegalArgumentException If there is no intersection between the
|
||||
* implemented and configured protocols
|
||||
*/
|
||||
public String[] getEnabledProtocols() throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* The set of enabled ciphers is the intersection of the implemented ciphers
|
||||
* and the configured ciphers. If no ciphers are explicitly configured, then
|
||||
* the default ciphers will be included in the returned array.
|
||||
* <p>
|
||||
* The ciphers used during the TLS handshake may be further restricted by
|
||||
* the {@link #getEnabledProtocols()} and the certificates.
|
||||
*
|
||||
* @return The ciphers currently enabled and available for clients to select
|
||||
* from for the associated connection
|
||||
*
|
||||
* @throws IllegalArgumentException If there is no intersection between the
|
||||
* implemented and configured ciphers
|
||||
*/
|
||||
public String[] getEnabledCiphers() throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Optional interface that can be implemented by
|
||||
* {@link javax.net.ssl.SSLEngine}s to indicate that they support ALPN and
|
||||
* can provided the protocol agreed with the client.
|
||||
*/
|
||||
public interface ProtocolInfo {
|
||||
/**
|
||||
* ALPN information.
|
||||
* @return the protocol selected using ALPN
|
||||
*/
|
||||
public String getNegotiatedProtocol();
|
||||
}
|
||||
}
|
||||
542
java/org/apache/tomcat/util/net/SSLUtilBase.java
Normal file
542
java/org/apache/tomcat/util/net/SSLUtilBase.java
Normal file
@@ -0,0 +1,542 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.CRL;
|
||||
import java.security.cert.CRLException;
|
||||
import java.security.cert.CertPathParameters;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertStoreParameters;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateExpiredException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
import java.security.cert.CollectionCertStoreParameters;
|
||||
import java.security.cert.PKIXBuilderParameters;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.net.ssl.CertPathTrustManagerParameters;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.ManagerFactoryParameters;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.compat.JreCompat;
|
||||
import org.apache.tomcat.util.file.ConfigFileLoader;
|
||||
import org.apache.tomcat.util.net.SSLHostConfig.CertificateVerification;
|
||||
import org.apache.tomcat.util.net.jsse.JSSEKeyManager;
|
||||
import org.apache.tomcat.util.net.jsse.PEMFile;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
import org.apache.tomcat.util.security.KeyStoreUtil;
|
||||
|
||||
/**
|
||||
* Common base class for {@link SSLUtil} implementations.
|
||||
*/
|
||||
public abstract class SSLUtilBase implements SSLUtil {
|
||||
|
||||
private static final Log log = LogFactory.getLog(SSLUtilBase.class);
|
||||
private static final StringManager sm = StringManager.getManager(SSLUtilBase.class);
|
||||
|
||||
protected final SSLHostConfig sslHostConfig;
|
||||
protected final SSLHostConfigCertificate certificate;
|
||||
|
||||
private final String[] enabledProtocols;
|
||||
private final String[] enabledCiphers;
|
||||
|
||||
|
||||
protected SSLUtilBase(SSLHostConfigCertificate certificate) {
|
||||
this(certificate, true);
|
||||
}
|
||||
|
||||
|
||||
protected SSLUtilBase(SSLHostConfigCertificate certificate, boolean warnTls13) {
|
||||
this.certificate = certificate;
|
||||
this.sslHostConfig = certificate.getSSLHostConfig();
|
||||
|
||||
// Calculate the enabled protocols
|
||||
Set<String> configuredProtocols = sslHostConfig.getProtocols();
|
||||
Set<String> implementedProtocols = getImplementedProtocols();
|
||||
// If TLSv1.3 is not implemented and not explicitly requested we can
|
||||
// ignore it. It is included in the defaults so it may be configured.
|
||||
if (!implementedProtocols.contains(Constants.SSL_PROTO_TLSv1_3) &&
|
||||
!sslHostConfig.isExplicitlyRequestedProtocol(Constants.SSL_PROTO_TLSv1_3)) {
|
||||
configuredProtocols.remove(Constants.SSL_PROTO_TLSv1_3);
|
||||
}
|
||||
// Newer JREs are dropping support for SSLv2Hello. If it is not
|
||||
// implemented and not explicitly requested we can ignore it. It is
|
||||
// included in the defaults so it may be configured.
|
||||
if (!implementedProtocols.contains(Constants.SSL_PROTO_SSLv2Hello) &&
|
||||
!sslHostConfig.isExplicitlyRequestedProtocol(Constants.SSL_PROTO_SSLv2Hello)) {
|
||||
configuredProtocols.remove(Constants.SSL_PROTO_SSLv2Hello);
|
||||
}
|
||||
|
||||
List<String> enabledProtocols =
|
||||
getEnabled("protocols", getLog(), warnTls13, configuredProtocols, implementedProtocols);
|
||||
if (enabledProtocols.contains("SSLv3")) {
|
||||
log.warn(sm.getString("jsse.ssl3"));
|
||||
}
|
||||
this.enabledProtocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
|
||||
|
||||
if (enabledProtocols.contains(Constants.SSL_PROTO_TLSv1_3) &&
|
||||
sslHostConfig.getCertificateVerification() == CertificateVerification.OPTIONAL &&
|
||||
!isTls13RenegAuthAvailable() && warnTls13) {
|
||||
log.warn(sm.getString("jsse.tls13.auth"));
|
||||
}
|
||||
|
||||
// Calculate the enabled ciphers
|
||||
List<String> configuredCiphers = sslHostConfig.getJsseCipherNames();
|
||||
Set<String> implementedCiphers = getImplementedCiphers();
|
||||
List<String> enabledCiphers =
|
||||
getEnabled("ciphers", getLog(), false, configuredCiphers, implementedCiphers);
|
||||
this.enabledCiphers = enabledCiphers.toArray(new String[enabledCiphers.size()]);
|
||||
}
|
||||
|
||||
|
||||
static <T> List<T> getEnabled(String name, Log log, boolean warnOnSkip, Collection<T> configured,
|
||||
Collection<T> implemented) {
|
||||
|
||||
List<T> enabled = new ArrayList<>();
|
||||
|
||||
if (implemented.size() == 0) {
|
||||
// Unable to determine the list of available protocols. This will
|
||||
// have been logged previously.
|
||||
// Use the configuredProtocols and hope they work. If not, an error
|
||||
// will be generated when the list is used. Not ideal but no more
|
||||
// can be done at this point.
|
||||
enabled.addAll(configured);
|
||||
} else {
|
||||
enabled.addAll(configured);
|
||||
enabled.retainAll(implemented);
|
||||
|
||||
if (enabled.isEmpty()) {
|
||||
// Don't use the defaults in this case. They may be less secure
|
||||
// than the configuration the user intended.
|
||||
// Force the failure of the connector
|
||||
throw new IllegalArgumentException(
|
||||
sm.getString("sslUtilBase.noneSupported", name, configured));
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("sslUtilBase.active", name, enabled));
|
||||
}
|
||||
if (log.isDebugEnabled() || warnOnSkip) {
|
||||
if (enabled.size() != configured.size()) {
|
||||
List<T> skipped = new ArrayList<>();
|
||||
skipped.addAll(configured);
|
||||
skipped.removeAll(enabled);
|
||||
String msg = sm.getString("sslUtilBase.skipped", name, skipped);
|
||||
if (warnOnSkip) {
|
||||
log.warn(msg);
|
||||
} else {
|
||||
log.debug(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Gets the key- or truststore with the specified type, path, and password.
|
||||
*/
|
||||
static KeyStore getStore(String type, String provider, String path,
|
||||
String pass) throws IOException {
|
||||
|
||||
KeyStore ks = null;
|
||||
InputStream istream = null;
|
||||
try {
|
||||
if (provider == null) {
|
||||
ks = KeyStore.getInstance(type);
|
||||
} else {
|
||||
ks = KeyStore.getInstance(type, provider);
|
||||
}
|
||||
if ("DKS".equalsIgnoreCase(type)) {
|
||||
URI uri = ConfigFileLoader.getURI(path);
|
||||
ks.load(JreCompat.getInstance().getDomainLoadStoreParameter(uri));
|
||||
} else {
|
||||
// Some key store types (e.g. hardware) expect the InputStream
|
||||
// to be null
|
||||
if(!("PKCS11".equalsIgnoreCase(type) ||
|
||||
"".equalsIgnoreCase(path)) ||
|
||||
"NONE".equalsIgnoreCase(path)) {
|
||||
istream = ConfigFileLoader.getInputStream(path);
|
||||
}
|
||||
|
||||
// The digester cannot differentiate between null and "".
|
||||
// Unfortunately, some key stores behave differently with null
|
||||
// and "".
|
||||
// JKS key stores treat null and "" interchangeably.
|
||||
// PKCS12 key stores (Java 7 onwards) don't return the cert if
|
||||
// null is used.
|
||||
// Key stores that do not use passwords expect null
|
||||
// Therefore:
|
||||
// - generally use null if pass is null or ""
|
||||
// - for JKS or PKCS12 only use null if pass is null
|
||||
// (because JKS will auto-switch to PKCS12)
|
||||
char[] storePass = null;
|
||||
if (pass != null && (!"".equals(pass) ||
|
||||
"JKS".equalsIgnoreCase(type) || "PKCS12".equalsIgnoreCase(type))) {
|
||||
storePass = pass.toCharArray();
|
||||
}
|
||||
KeyStoreUtil.load(ks, istream, storePass);
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
throw fnfe;
|
||||
} catch (IOException ioe) {
|
||||
// May be expected when working with a trust store
|
||||
// Re-throw. Caller will catch and log as required
|
||||
throw ioe;
|
||||
} catch(Exception ex) {
|
||||
String msg = sm.getString("jsse.keystore_load_failed", type, path,
|
||||
ex.getMessage());
|
||||
log.error(msg, ex);
|
||||
throw new IOException(msg);
|
||||
} finally {
|
||||
if (istream != null) {
|
||||
try {
|
||||
istream.close();
|
||||
} catch (IOException ioe) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ks;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final SSLContext createSSLContext(List<String> negotiableProtocols) throws Exception {
|
||||
SSLContext sslContext = createSSLContextInternal(negotiableProtocols);
|
||||
sslContext.init(getKeyManagers(), getTrustManagers(), null);
|
||||
|
||||
SSLSessionContext sessionContext = sslContext.getServerSessionContext();
|
||||
if (sessionContext != null) {
|
||||
configureSessionContext(sessionContext);
|
||||
}
|
||||
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void configureSessionContext(SSLSessionContext sslSessionContext) {
|
||||
// <0 - don't set anything - use the implementation default
|
||||
if (sslHostConfig.getSessionCacheSize() >= 0) {
|
||||
sslSessionContext.setSessionCacheSize(sslHostConfig.getSessionCacheSize());
|
||||
}
|
||||
|
||||
// <0 - don't set anything - use the implementation default
|
||||
if (sslHostConfig.getSessionTimeout() >= 0) {
|
||||
sslSessionContext.setSessionTimeout(sslHostConfig.getSessionTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public KeyManager[] getKeyManagers() throws Exception {
|
||||
String keyAlias = certificate.getCertificateKeyAlias();
|
||||
String algorithm = sslHostConfig.getKeyManagerAlgorithm();
|
||||
String keyPass = certificate.getCertificateKeyPassword();
|
||||
// This has to be here as it can't be moved to SSLHostConfig since the
|
||||
// defaults vary between JSSE and OpenSSL.
|
||||
if (keyPass == null) {
|
||||
keyPass = certificate.getCertificateKeystorePassword();
|
||||
}
|
||||
|
||||
KeyStore ks = certificate.getCertificateKeystore();
|
||||
KeyStore ksUsed = ks;
|
||||
|
||||
/*
|
||||
* Use an in memory key store where possible.
|
||||
* For PEM format keys and certificates, it allows them to be imported
|
||||
* into the expected format.
|
||||
* For Java key stores with PKCS8 encoded keys (e.g. JKS files), it
|
||||
* enables Tomcat to handle the case where multiple keys exist in the
|
||||
* key store, each with a different password. The KeyManagerFactory
|
||||
* can't handle that so using an in memory key store with just the
|
||||
* required key works around that.
|
||||
* Other keys stores (hardware, MS, etc.) will be used as is.
|
||||
*/
|
||||
|
||||
char[] keyPassArray = keyPass.toCharArray();
|
||||
|
||||
if (ks == null) {
|
||||
if (certificate.getCertificateFile() == null) {
|
||||
throw new IOException(sm.getString("jsse.noCertFile"));
|
||||
}
|
||||
|
||||
PEMFile privateKeyFile = new PEMFile(
|
||||
certificate.getCertificateKeyFile() != null ? certificate.getCertificateKeyFile() : certificate.getCertificateFile(),
|
||||
keyPass);
|
||||
PEMFile certificateFile = new PEMFile(certificate.getCertificateFile());
|
||||
|
||||
Collection<Certificate> chain = new ArrayList<>();
|
||||
chain.addAll(certificateFile.getCertificates());
|
||||
if (certificate.getCertificateChainFile() != null) {
|
||||
PEMFile certificateChainFile = new PEMFile(certificate.getCertificateChainFile());
|
||||
chain.addAll(certificateChainFile.getCertificates());
|
||||
}
|
||||
|
||||
if (keyAlias == null) {
|
||||
keyAlias = "tomcat";
|
||||
}
|
||||
|
||||
// Switch to in-memory key store
|
||||
ksUsed = KeyStore.getInstance("JKS");
|
||||
ksUsed.load(null, null);
|
||||
ksUsed.setKeyEntry(keyAlias, privateKeyFile.getPrivateKey(), keyPass.toCharArray(),
|
||||
chain.toArray(new Certificate[chain.size()]));
|
||||
} else {
|
||||
if (keyAlias != null && !ks.isKeyEntry(keyAlias)) {
|
||||
throw new IOException(sm.getString("jsse.alias_no_key_entry", keyAlias));
|
||||
} else if (keyAlias == null) {
|
||||
Enumeration<String> aliases = ks.aliases();
|
||||
if (!aliases.hasMoreElements()) {
|
||||
throw new IOException(sm.getString("jsse.noKeys"));
|
||||
}
|
||||
while (aliases.hasMoreElements() && keyAlias == null) {
|
||||
keyAlias = aliases.nextElement();
|
||||
if (!ks.isKeyEntry(keyAlias)) {
|
||||
keyAlias = null;
|
||||
}
|
||||
}
|
||||
if (keyAlias == null) {
|
||||
throw new IOException(sm.getString("jsse.alias_no_key_entry", (Object) null));
|
||||
}
|
||||
}
|
||||
|
||||
Key k = ks.getKey(keyAlias, keyPassArray);
|
||||
if (k != null && !"DKS".equalsIgnoreCase(certificate.getCertificateKeystoreType()) &&
|
||||
"PKCS#8".equalsIgnoreCase(k.getFormat())) {
|
||||
// Switch to in-memory key store
|
||||
String provider = certificate.getCertificateKeystoreProvider();
|
||||
if (provider == null) {
|
||||
ksUsed = KeyStore.getInstance(certificate.getCertificateKeystoreType());
|
||||
} else {
|
||||
ksUsed = KeyStore.getInstance(certificate.getCertificateKeystoreType(),
|
||||
provider);
|
||||
}
|
||||
ksUsed.load(null, null);
|
||||
ksUsed.setKeyEntry(keyAlias, k, keyPassArray, ks.getCertificateChain(keyAlias));
|
||||
}
|
||||
// Non-PKCS#8 key stores will use the original key store
|
||||
}
|
||||
|
||||
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
|
||||
kmf.init(ksUsed, keyPassArray);
|
||||
|
||||
KeyManager[] kms = kmf.getKeyManagers();
|
||||
|
||||
// Only need to filter keys by alias if there are key managers to filter
|
||||
// and the original key store was used. The in memory key stores only
|
||||
// have a single key so don't need filtering
|
||||
if (kms != null && ksUsed == ks) {
|
||||
String alias = keyAlias;
|
||||
// JKS keystores always convert the alias name to lower case
|
||||
if ("JKS".equals(certificate.getCertificateKeystoreType())) {
|
||||
alias = alias.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
for(int i = 0; i < kms.length; i++) {
|
||||
kms[i] = new JSSEKeyManager((X509KeyManager)kms[i], alias);
|
||||
}
|
||||
}
|
||||
|
||||
return kms;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getEnabledProtocols() {
|
||||
return enabledProtocols;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getEnabledCiphers() {
|
||||
return enabledCiphers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TrustManager[] getTrustManagers() throws Exception {
|
||||
|
||||
String className = sslHostConfig.getTrustManagerClassName();
|
||||
if(className != null && className.length() > 0) {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
Class<?> clazz = classLoader.loadClass(className);
|
||||
if(!(TrustManager.class.isAssignableFrom(clazz))){
|
||||
throw new InstantiationException(sm.getString(
|
||||
"jsse.invalidTrustManagerClassName", className));
|
||||
}
|
||||
Object trustManagerObject = clazz.getConstructor().newInstance();
|
||||
TrustManager trustManager = (TrustManager) trustManagerObject;
|
||||
return new TrustManager[]{ trustManager };
|
||||
}
|
||||
|
||||
TrustManager[] tms = null;
|
||||
|
||||
KeyStore trustStore = sslHostConfig.getTruststore();
|
||||
if (trustStore != null) {
|
||||
checkTrustStoreEntries(trustStore);
|
||||
String algorithm = sslHostConfig.getTruststoreAlgorithm();
|
||||
String crlf = sslHostConfig.getCertificateRevocationListFile();
|
||||
boolean revocationEnabled = sslHostConfig.getRevocationEnabled();
|
||||
|
||||
if ("PKIX".equalsIgnoreCase(algorithm)) {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
|
||||
CertPathParameters params = getParameters(crlf, trustStore, revocationEnabled);
|
||||
ManagerFactoryParameters mfp = new CertPathTrustManagerParameters(params);
|
||||
tmf.init(mfp);
|
||||
tms = tmf.getTrustManagers();
|
||||
} else {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
|
||||
tmf.init(trustStore);
|
||||
tms = tmf.getTrustManagers();
|
||||
if (crlf != null && crlf.length() > 0) {
|
||||
throw new CRLException(sm.getString("jsseUtil.noCrlSupport", algorithm));
|
||||
}
|
||||
// Only warn if the attribute has been explicitly configured
|
||||
if (sslHostConfig.isCertificateVerificationDepthConfigured()) {
|
||||
log.warn(sm.getString("jsseUtil.noVerificationDepth", algorithm));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tms;
|
||||
}
|
||||
|
||||
|
||||
private void checkTrustStoreEntries(KeyStore trustStore) throws Exception {
|
||||
Enumeration<String> aliases = trustStore.aliases();
|
||||
if (aliases != null) {
|
||||
Date now = new Date();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
if (trustStore.isCertificateEntry(alias)) {
|
||||
Certificate cert = trustStore.getCertificate(alias);
|
||||
if (cert instanceof X509Certificate) {
|
||||
try {
|
||||
((X509Certificate) cert).checkValidity(now);
|
||||
} catch (CertificateExpiredException | CertificateNotYetValidException e) {
|
||||
String msg = sm.getString("jsseUtil.trustedCertNotValid", alias,
|
||||
((X509Certificate) cert).getSubjectDN(), e.getMessage());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(msg, e);
|
||||
} else {
|
||||
log.warn(msg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jsseUtil.trustedCertNotChecked", alias));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the initialization parameters for the TrustManager.
|
||||
* Currently, only the default <code>PKIX</code> is supported.
|
||||
*
|
||||
* @param crlf The path to the CRL file.
|
||||
* @param trustStore The configured TrustStore.
|
||||
* @param revocationEnabled Should the JSSE provider perform revocation
|
||||
* checks? Ignored if {@code crlf} is non-null.
|
||||
* Configuration of revocation checks are expected
|
||||
* to be via proprietary JSSE provider methods.
|
||||
* @return The parameters including the CRLs and TrustStore.
|
||||
* @throws Exception An error occurred
|
||||
*/
|
||||
protected CertPathParameters getParameters(String crlf, KeyStore trustStore,
|
||||
boolean revocationEnabled) throws Exception {
|
||||
|
||||
PKIXBuilderParameters xparams =
|
||||
new PKIXBuilderParameters(trustStore, new X509CertSelector());
|
||||
if (crlf != null && crlf.length() > 0) {
|
||||
Collection<? extends CRL> crls = getCRLs(crlf);
|
||||
CertStoreParameters csp = new CollectionCertStoreParameters(crls);
|
||||
CertStore store = CertStore.getInstance("Collection", csp);
|
||||
xparams.addCertStore(store);
|
||||
xparams.setRevocationEnabled(true);
|
||||
} else {
|
||||
xparams.setRevocationEnabled(revocationEnabled);
|
||||
}
|
||||
xparams.setMaxPathLength(sslHostConfig.getCertificateVerificationDepth());
|
||||
return xparams;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the collection of CRLs.
|
||||
* @param crlf The path to the CRL file.
|
||||
* @return the CRLs collection
|
||||
* @throws IOException Error reading CRL file
|
||||
* @throws CRLException CRL error
|
||||
* @throws CertificateException Error processing certificate
|
||||
*/
|
||||
protected Collection<? extends CRL> getCRLs(String crlf)
|
||||
throws IOException, CRLException, CertificateException {
|
||||
|
||||
Collection<? extends CRL> crls = null;
|
||||
try {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
try (InputStream is = ConfigFileLoader.getInputStream(crlf)) {
|
||||
crls = cf.generateCRLs(is);
|
||||
}
|
||||
} catch(IOException iex) {
|
||||
throw iex;
|
||||
} catch(CRLException crle) {
|
||||
throw crle;
|
||||
} catch(CertificateException ce) {
|
||||
throw ce;
|
||||
}
|
||||
return crls;
|
||||
}
|
||||
|
||||
|
||||
protected abstract Set<String> getImplementedProtocols();
|
||||
protected abstract Set<String> getImplementedCiphers();
|
||||
protected abstract Log getLog();
|
||||
protected abstract boolean isTls13RenegAuthAvailable();
|
||||
protected abstract SSLContext createSSLContextInternal(List<String> negotiableProtocols) throws Exception;
|
||||
}
|
||||
1229
java/org/apache/tomcat/util/net/SecureNio2Channel.java
Normal file
1229
java/org/apache/tomcat/util/net/SecureNio2Channel.java
Normal file
File diff suppressed because it is too large
Load Diff
876
java/org/apache/tomcat/util/net/SecureNioChannel.java
Normal file
876
java/org/apache/tomcat/util/net/SecureNioChannel.java
Normal file
@@ -0,0 +1,876 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
import javax.net.ssl.SSLEngineResult.Status;
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.buf.ByteBufferUtils;
|
||||
import org.apache.tomcat.util.compat.JreCompat;
|
||||
import org.apache.tomcat.util.net.TLSClientHelloExtractor.ExtractorResult;
|
||||
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Implementation of a secure socket channel
|
||||
*/
|
||||
public class SecureNioChannel extends NioChannel {
|
||||
|
||||
private static final Log log = LogFactory.getLog(SecureNioChannel.class);
|
||||
private static final StringManager sm = StringManager.getManager(SecureNioChannel.class);
|
||||
|
||||
// Value determined by observation of what the SSL Engine requested in
|
||||
// various scenarios
|
||||
private static final int DEFAULT_NET_BUFFER_SIZE = 16921;
|
||||
|
||||
protected ByteBuffer netInBuffer;
|
||||
protected ByteBuffer netOutBuffer;
|
||||
|
||||
protected SSLEngine sslEngine;
|
||||
|
||||
protected boolean sniComplete = false;
|
||||
|
||||
protected boolean handshakeComplete = false;
|
||||
protected HandshakeStatus handshakeStatus; //gets set by handshake
|
||||
|
||||
protected boolean closed = false;
|
||||
protected boolean closing = false;
|
||||
|
||||
protected NioSelectorPool pool;
|
||||
private final NioEndpoint endpoint;
|
||||
|
||||
public SecureNioChannel(SocketChannel channel, SocketBufferHandler bufHandler,
|
||||
NioSelectorPool pool, NioEndpoint endpoint) {
|
||||
super(channel, bufHandler);
|
||||
|
||||
// Create the network buffers (these hold the encrypted data).
|
||||
if (endpoint.getSocketProperties().getDirectSslBuffer()) {
|
||||
netInBuffer = ByteBuffer.allocateDirect(DEFAULT_NET_BUFFER_SIZE);
|
||||
netOutBuffer = ByteBuffer.allocateDirect(DEFAULT_NET_BUFFER_SIZE);
|
||||
} else {
|
||||
netInBuffer = ByteBuffer.allocate(DEFAULT_NET_BUFFER_SIZE);
|
||||
netOutBuffer = ByteBuffer.allocate(DEFAULT_NET_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
// selector pool for blocking operations
|
||||
this.pool = pool;
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() throws IOException {
|
||||
super.reset();
|
||||
sslEngine = null;
|
||||
sniComplete = false;
|
||||
handshakeComplete = false;
|
||||
closed = false;
|
||||
closing = false;
|
||||
netInBuffer.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
super.free();
|
||||
if (endpoint.getSocketProperties().getDirectSslBuffer()) {
|
||||
ByteBufferUtils.cleanDirectBuffer(netInBuffer);
|
||||
ByteBufferUtils.cleanDirectBuffer(netOutBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================================
|
||||
// NIO SSL METHODS
|
||||
//===========================================================================================
|
||||
|
||||
/**
|
||||
* Flush the channel.
|
||||
*
|
||||
* @param block Should a blocking write be used?
|
||||
* @param s The selector to use for blocking, if null then a busy
|
||||
* write will be initiated
|
||||
* @param timeout The timeout for this write operation in milliseconds,
|
||||
* -1 means no timeout
|
||||
* @return <code>true</code> if the network buffer has been flushed out and
|
||||
* is empty else <code>false</code>
|
||||
* @throws IOException If an I/O error occurs during the operation
|
||||
*/
|
||||
@Override
|
||||
public boolean flush(boolean block, Selector s, long timeout) throws IOException {
|
||||
if (!block) {
|
||||
flush(netOutBuffer);
|
||||
} else {
|
||||
pool.write(netOutBuffer, this, s, timeout, block);
|
||||
}
|
||||
return !netOutBuffer.hasRemaining();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the buffer to the network, non blocking
|
||||
* @param buf ByteBuffer
|
||||
* @return boolean true if the buffer has been emptied out, false otherwise
|
||||
* @throws IOException An IO error occurred writing data
|
||||
*/
|
||||
protected boolean flush(ByteBuffer buf) throws IOException {
|
||||
int remaining = buf.remaining();
|
||||
if (remaining > 0) {
|
||||
return (sc.write(buf) >= remaining);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs SSL handshake, non blocking, but performs NEED_TASK on the same
|
||||
* thread. Hence, you should never call this method using your Acceptor
|
||||
* thread, as you would slow down your system significantly. If the return
|
||||
* value from this method is positive, the selection key should be
|
||||
* registered interestOps given by the return value.
|
||||
*
|
||||
* @param read boolean - true if the underlying channel is readable
|
||||
* @param write boolean - true if the underlying channel is writable
|
||||
*
|
||||
* @return 0 if hand shake is complete, -1 if an error (other than an
|
||||
* IOException) occurred, otherwise it returns a SelectionKey
|
||||
* interestOps value
|
||||
*
|
||||
* @throws IOException If an I/O error occurs during the handshake or if the
|
||||
* handshake fails during wrapping or unwrapping
|
||||
*/
|
||||
@Override
|
||||
public int handshake(boolean read, boolean write) throws IOException {
|
||||
if (handshakeComplete) {
|
||||
return 0; //we have done our initial handshake
|
||||
}
|
||||
|
||||
if (!sniComplete) {
|
||||
int sniResult = processSNI();
|
||||
if (sniResult == 0) {
|
||||
sniComplete = true;
|
||||
} else {
|
||||
return sniResult;
|
||||
}
|
||||
}
|
||||
|
||||
if (!flush(netOutBuffer)) return SelectionKey.OP_WRITE; //we still have data to write
|
||||
|
||||
SSLEngineResult handshake = null;
|
||||
|
||||
while (!handshakeComplete) {
|
||||
switch ( handshakeStatus ) {
|
||||
case NOT_HANDSHAKING: {
|
||||
//should never happen
|
||||
throw new IOException(sm.getString("channel.nio.ssl.notHandshaking"));
|
||||
}
|
||||
case FINISHED: {
|
||||
if (endpoint.hasNegotiableProtocols()) {
|
||||
if (sslEngine instanceof SSLUtil.ProtocolInfo) {
|
||||
socketWrapper.setNegotiatedProtocol(
|
||||
((SSLUtil.ProtocolInfo) sslEngine).getNegotiatedProtocol());
|
||||
} else if (JreCompat.isJre9Available()) {
|
||||
socketWrapper.setNegotiatedProtocol(
|
||||
JreCompat.getInstance().getApplicationProtocol(sslEngine));
|
||||
}
|
||||
}
|
||||
//we are complete if we have delivered the last package
|
||||
handshakeComplete = !netOutBuffer.hasRemaining();
|
||||
//return 0 if we are complete, otherwise we still have data to write
|
||||
return handshakeComplete?0:SelectionKey.OP_WRITE;
|
||||
}
|
||||
case NEED_WRAP: {
|
||||
//perform the wrap function
|
||||
try {
|
||||
handshake = handshakeWrap(write);
|
||||
} catch (SSLException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("channel.nio.ssl.wrapException"), e);
|
||||
}
|
||||
handshake = handshakeWrap(write);
|
||||
}
|
||||
if (handshake.getStatus() == Status.OK) {
|
||||
if (handshakeStatus == HandshakeStatus.NEED_TASK)
|
||||
handshakeStatus = tasks();
|
||||
} else if (handshake.getStatus() == Status.CLOSED) {
|
||||
flush(netOutBuffer);
|
||||
return -1;
|
||||
} else {
|
||||
//wrap should always work with our buffers
|
||||
throw new IOException(sm.getString("channel.nio.ssl.unexpectedStatusDuringWrap", handshake.getStatus()));
|
||||
}
|
||||
if ( handshakeStatus != HandshakeStatus.NEED_UNWRAP || (!flush(netOutBuffer)) ) {
|
||||
//should actually return OP_READ if we have NEED_UNWRAP
|
||||
return SelectionKey.OP_WRITE;
|
||||
}
|
||||
//fall down to NEED_UNWRAP on the same call, will result in a
|
||||
//BUFFER_UNDERFLOW if it needs data
|
||||
}
|
||||
//$FALL-THROUGH$
|
||||
case NEED_UNWRAP: {
|
||||
//perform the unwrap function
|
||||
handshake = handshakeUnwrap(read);
|
||||
if ( handshake.getStatus() == Status.OK ) {
|
||||
if (handshakeStatus == HandshakeStatus.NEED_TASK)
|
||||
handshakeStatus = tasks();
|
||||
} else if ( handshake.getStatus() == Status.BUFFER_UNDERFLOW ){
|
||||
//read more data, reregister for OP_READ
|
||||
return SelectionKey.OP_READ;
|
||||
} else {
|
||||
throw new IOException(sm.getString("channel.nio.ssl.unexpectedStatusDuringWrap", handshake.getStatus()));
|
||||
}//switch
|
||||
break;
|
||||
}
|
||||
case NEED_TASK: {
|
||||
handshakeStatus = tasks();
|
||||
break;
|
||||
}
|
||||
default: throw new IllegalStateException(sm.getString("channel.nio.ssl.invalidStatus", handshakeStatus));
|
||||
}
|
||||
}
|
||||
// Handshake is complete if this point is reached
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Peeks at the initial network bytes to determine if the SNI extension is
|
||||
* present and, if it is, what host name has been requested. Based on the
|
||||
* provided host name, configure the SSLEngine for this connection.
|
||||
*
|
||||
* @return 0 if SNI processing is complete, -1 if an error (other than an
|
||||
* IOException) occurred, otherwise it returns a SelectionKey
|
||||
* interestOps value
|
||||
*
|
||||
* @throws IOException If an I/O error occurs during the SNI processing
|
||||
*/
|
||||
private int processSNI() throws IOException {
|
||||
// Read some data into the network input buffer so we can peek at it.
|
||||
int bytesRead = sc.read(netInBuffer);
|
||||
if (bytesRead == -1) {
|
||||
// Reached end of stream before SNI could be processed.
|
||||
return -1;
|
||||
}
|
||||
TLSClientHelloExtractor extractor = new TLSClientHelloExtractor(netInBuffer);
|
||||
|
||||
while (extractor.getResult() == ExtractorResult.UNDERFLOW &&
|
||||
netInBuffer.capacity() < endpoint.getSniParseLimit()) {
|
||||
// extractor needed more data to process but netInBuffer was full so
|
||||
// expand the buffer and read some more data.
|
||||
int newLimit = Math.min(netInBuffer.capacity() * 2, endpoint.getSniParseLimit());
|
||||
log.info(sm.getString("channel.nio.ssl.expandNetInBuffer",
|
||||
Integer.toString(newLimit)));
|
||||
|
||||
netInBuffer = ByteBufferUtils.expand(netInBuffer, newLimit);
|
||||
sc.read(netInBuffer);
|
||||
extractor = new TLSClientHelloExtractor(netInBuffer);
|
||||
}
|
||||
|
||||
String hostName = null;
|
||||
List<Cipher> clientRequestedCiphers = null;
|
||||
List<String> clientRequestedApplicationProtocols = null;
|
||||
switch (extractor.getResult()) {
|
||||
case COMPLETE:
|
||||
hostName = extractor.getSNIValue();
|
||||
clientRequestedApplicationProtocols =
|
||||
extractor.getClientRequestedApplicationProtocols();
|
||||
//$FALL-THROUGH$ to set the client requested ciphers
|
||||
case NOT_PRESENT:
|
||||
clientRequestedCiphers = extractor.getClientRequestedCiphers();
|
||||
break;
|
||||
case NEED_READ:
|
||||
return SelectionKey.OP_READ;
|
||||
case UNDERFLOW:
|
||||
// Unable to buffer enough data to read SNI extension data
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("channel.nio.ssl.sniDefault"));
|
||||
}
|
||||
hostName = endpoint.getDefaultSSLHostConfigName();
|
||||
clientRequestedCiphers = Collections.emptyList();
|
||||
break;
|
||||
case NON_SECURE:
|
||||
netOutBuffer.clear();
|
||||
netOutBuffer.put(TLSClientHelloExtractor.USE_TLS_RESPONSE);
|
||||
netOutBuffer.flip();
|
||||
flushOutbound();
|
||||
throw new IOException(sm.getString("channel.nio.ssl.foundHttp"));
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("channel.nio.ssl.sniHostName", sc, hostName));
|
||||
}
|
||||
|
||||
sslEngine = endpoint.createSSLEngine(hostName, clientRequestedCiphers,
|
||||
clientRequestedApplicationProtocols);
|
||||
|
||||
// Ensure the application buffers (which have to be created earlier) are
|
||||
// big enough.
|
||||
getBufHandler().expand(sslEngine.getSession().getApplicationBufferSize());
|
||||
if (netOutBuffer.capacity() < sslEngine.getSession().getApplicationBufferSize()) {
|
||||
// Info for now as we may need to increase DEFAULT_NET_BUFFER_SIZE
|
||||
log.info(sm.getString("channel.nio.ssl.expandNetOutBuffer",
|
||||
Integer.toString(sslEngine.getSession().getApplicationBufferSize())));
|
||||
}
|
||||
netInBuffer = ByteBufferUtils.expand(netInBuffer, sslEngine.getSession().getPacketBufferSize());
|
||||
netOutBuffer = ByteBufferUtils.expand(netOutBuffer, sslEngine.getSession().getPacketBufferSize());
|
||||
|
||||
// Set limit and position to expected values
|
||||
netOutBuffer.position(0);
|
||||
netOutBuffer.limit(0);
|
||||
|
||||
// Initiate handshake
|
||||
sslEngine.beginHandshake();
|
||||
handshakeStatus = sslEngine.getHandshakeStatus();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Force a blocking handshake to take place for this key.
|
||||
* This requires that both network and application buffers have been emptied out prior to this call taking place, or a
|
||||
* IOException will be thrown.
|
||||
* @param timeout - timeout in milliseconds for each socket operation
|
||||
* @throws IOException - if an IO exception occurs or if application or network buffers contain data
|
||||
* @throws SocketTimeoutException - if a socket operation timed out
|
||||
*/
|
||||
@SuppressWarnings("null") // key cannot be null
|
||||
public void rehandshake(long timeout) throws IOException {
|
||||
//validate the network buffers are empty
|
||||
if (netInBuffer.position() > 0 && netInBuffer.position()<netInBuffer.limit()) throw new IOException(sm.getString("channel.nio.ssl.netInputNotEmpty"));
|
||||
if (netOutBuffer.position() > 0 && netOutBuffer.position()<netOutBuffer.limit()) throw new IOException(sm.getString("channel.nio.ssl.netOutputNotEmpty"));
|
||||
if (!getBufHandler().isReadBufferEmpty()) throw new IOException(sm.getString("channel.nio.ssl.appInputNotEmpty"));
|
||||
if (!getBufHandler().isWriteBufferEmpty()) throw new IOException(sm.getString("channel.nio.ssl.appOutputNotEmpty"));
|
||||
handshakeComplete = false;
|
||||
boolean isReadable = false;
|
||||
boolean isWriteable = false;
|
||||
boolean handshaking = true;
|
||||
Selector selector = null;
|
||||
SelectionKey key = null;
|
||||
try {
|
||||
sslEngine.beginHandshake();
|
||||
handshakeStatus = sslEngine.getHandshakeStatus();
|
||||
while (handshaking) {
|
||||
int hsStatus = this.handshake(isReadable, isWriteable);
|
||||
switch (hsStatus) {
|
||||
case -1 : throw new EOFException(sm.getString("channel.nio.ssl.eofDuringHandshake"));
|
||||
case 0 : handshaking = false; break;
|
||||
default : {
|
||||
long now = System.currentTimeMillis();
|
||||
if (selector==null) {
|
||||
selector = Selector.open();
|
||||
key = getIOChannel().register(selector, hsStatus);
|
||||
} else {
|
||||
key.interestOps(hsStatus); // null warning suppressed
|
||||
}
|
||||
int keyCount = selector.select(timeout);
|
||||
if (keyCount == 0 && ((System.currentTimeMillis()-now) >= timeout)) {
|
||||
throw new SocketTimeoutException(sm.getString("channel.nio.ssl.timeoutDuringHandshake"));
|
||||
}
|
||||
isReadable = key.isReadable();
|
||||
isWriteable = key.isWritable();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException x) {
|
||||
closeSilently();
|
||||
throw x;
|
||||
} catch (Exception cx) {
|
||||
closeSilently();
|
||||
IOException x = new IOException(cx);
|
||||
throw x;
|
||||
} finally {
|
||||
if (key != null) {
|
||||
try {
|
||||
key.cancel();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
if (selector != null) {
|
||||
try {
|
||||
selector.close();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes all the tasks needed on the same thread.
|
||||
* @return the status
|
||||
*/
|
||||
protected SSLEngineResult.HandshakeStatus tasks() {
|
||||
Runnable r = null;
|
||||
while ((r = sslEngine.getDelegatedTask()) != null) {
|
||||
r.run();
|
||||
}
|
||||
return sslEngine.getHandshakeStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the WRAP function
|
||||
* @param doWrite boolean
|
||||
* @return the result
|
||||
* @throws IOException An IO error occurred
|
||||
*/
|
||||
protected SSLEngineResult handshakeWrap(boolean doWrite) throws IOException {
|
||||
//this should never be called with a network buffer that contains data
|
||||
//so we can clear it here.
|
||||
netOutBuffer.clear();
|
||||
//perform the wrap
|
||||
getBufHandler().configureWriteBufferForRead();
|
||||
SSLEngineResult result = sslEngine.wrap(getBufHandler().getWriteBuffer(), netOutBuffer);
|
||||
//prepare the results to be written
|
||||
netOutBuffer.flip();
|
||||
//set the status
|
||||
handshakeStatus = result.getHandshakeStatus();
|
||||
//optimization, if we do have a writable channel, write it now
|
||||
if (doWrite) {
|
||||
flush(netOutBuffer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform handshake unwrap
|
||||
* @param doread boolean
|
||||
* @return the result
|
||||
* @throws IOException An IO error occurred
|
||||
*/
|
||||
protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {
|
||||
|
||||
if (netInBuffer.position() == netInBuffer.limit()) {
|
||||
//clear the buffer if we have emptied it out on data
|
||||
netInBuffer.clear();
|
||||
}
|
||||
if (doread) {
|
||||
//if we have data to read, read it
|
||||
int read = sc.read(netInBuffer);
|
||||
if (read == -1) {
|
||||
throw new IOException(sm.getString("channel.nio.ssl.eofDuringHandshake"));
|
||||
}
|
||||
}
|
||||
SSLEngineResult result;
|
||||
boolean cont = false;
|
||||
//loop while we can perform pure SSLEngine data
|
||||
do {
|
||||
//prepare the buffer with the incoming data
|
||||
netInBuffer.flip();
|
||||
//call unwrap
|
||||
getBufHandler().configureReadBufferForWrite();
|
||||
result = sslEngine.unwrap(netInBuffer, getBufHandler().getReadBuffer());
|
||||
//compact the buffer, this is an optional method, wonder what would happen if we didn't
|
||||
netInBuffer.compact();
|
||||
//read in the status
|
||||
handshakeStatus = result.getHandshakeStatus();
|
||||
if ( result.getStatus() == SSLEngineResult.Status.OK &&
|
||||
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
|
||||
//execute tasks if we need to
|
||||
handshakeStatus = tasks();
|
||||
}
|
||||
//perform another unwrap?
|
||||
cont = result.getStatus() == SSLEngineResult.Status.OK &&
|
||||
handshakeStatus == HandshakeStatus.NEED_UNWRAP;
|
||||
}while ( cont );
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an SSL close message, will not physically close the connection here.
|
||||
* <br>To close the connection, you could do something like
|
||||
* <pre><code>
|
||||
* close();
|
||||
* while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
|
||||
* if ( isOpen() ) close(true); //forces a close if you timed out
|
||||
* </code></pre>
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws IOException if there is data on the outgoing network buffer and
|
||||
* we are unable to flush it
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (closing) {
|
||||
return;
|
||||
}
|
||||
closing = true;
|
||||
sslEngine.closeOutbound();
|
||||
|
||||
if (!flush(netOutBuffer)) {
|
||||
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"));
|
||||
}
|
||||
//prep the buffer for the close message
|
||||
netOutBuffer.clear();
|
||||
//perform the close, since we called sslEngine.closeOutbound
|
||||
SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer);
|
||||
//we should be in a close state
|
||||
if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) {
|
||||
throw new IOException(sm.getString("channel.nio.ssl.invalidCloseState"));
|
||||
}
|
||||
//prepare the buffer for writing
|
||||
netOutBuffer.flip();
|
||||
//if there is data to be written
|
||||
flush(netOutBuffer);
|
||||
|
||||
//is the channel closed?
|
||||
closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close(boolean force) throws IOException {
|
||||
try {
|
||||
close();
|
||||
} finally {
|
||||
if (force || closed) {
|
||||
closed = true;
|
||||
sc.socket().close();
|
||||
sc.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void closeSilently() {
|
||||
try {
|
||||
close(true);
|
||||
} catch (IOException ioe) {
|
||||
// This is expected - swallowing the exception is the reason this
|
||||
// method exists. Log at debug in case someone is interested.
|
||||
log.debug(sm.getString("channel.nio.ssl.closeSilentError"), ioe);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a sequence of bytes from this channel into the given buffer.
|
||||
*
|
||||
* @param dst The buffer into which bytes are to be transferred
|
||||
* @return The number of bytes read, possibly zero, or <code>-1</code> if
|
||||
* the channel has reached end-of-stream
|
||||
* @throws IOException If some other I/O error occurs
|
||||
* @throws IllegalArgumentException if the destination buffer is different
|
||||
* than getBufHandler().getReadBuffer()
|
||||
*/
|
||||
@Override
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
//are we in the middle of closing or closed?
|
||||
if (closing || closed) {
|
||||
return -1;
|
||||
}
|
||||
//did we finish our handshake?
|
||||
if (!handshakeComplete) {
|
||||
throw new IllegalStateException(sm.getString("channel.nio.ssl.incompleteHandshake"));
|
||||
}
|
||||
|
||||
//read from the network
|
||||
int netread = sc.read(netInBuffer);
|
||||
//did we reach EOF? if so send EOF up one layer.
|
||||
if (netread == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//the data read
|
||||
int read = 0;
|
||||
//the SSL engine result
|
||||
SSLEngineResult unwrap;
|
||||
do {
|
||||
//prepare the buffer
|
||||
netInBuffer.flip();
|
||||
//unwrap the data
|
||||
unwrap = sslEngine.unwrap(netInBuffer, dst);
|
||||
//compact the buffer
|
||||
netInBuffer.compact();
|
||||
|
||||
if (unwrap.getStatus() == Status.OK || unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
|
||||
//we did receive some data, add it to our total
|
||||
read += unwrap.bytesProduced();
|
||||
//perform any tasks if needed
|
||||
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
tasks();
|
||||
}
|
||||
//if we need more network data, then bail out for now.
|
||||
if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
|
||||
break;
|
||||
}
|
||||
} else if (unwrap.getStatus() == Status.BUFFER_OVERFLOW) {
|
||||
if (read > 0) {
|
||||
// Buffer overflow can happen if we have read data. Return
|
||||
// so the destination buffer can be emptied before another
|
||||
// read is attempted
|
||||
break;
|
||||
} else {
|
||||
// The SSL session has increased the required buffer size
|
||||
// since the buffer was created.
|
||||
if (dst == getBufHandler().getReadBuffer()) {
|
||||
// This is the normal case for this code
|
||||
getBufHandler().expand(sslEngine.getSession().getApplicationBufferSize());
|
||||
dst = getBufHandler().getReadBuffer();
|
||||
} else if (dst == getAppReadBufHandler().getByteBuffer()) {
|
||||
getAppReadBufHandler()
|
||||
.expand(sslEngine.getSession().getApplicationBufferSize());
|
||||
dst = getAppReadBufHandler().getByteBuffer();
|
||||
} else {
|
||||
// Can't expand the buffer as there is no way to signal
|
||||
// to the caller that the buffer has been replaced.
|
||||
throw new IOException(
|
||||
sm.getString("channel.nio.ssl.unwrapFailResize", unwrap.getStatus()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Something else went wrong
|
||||
throw new IOException(sm.getString("channel.nio.ssl.unwrapFail", unwrap.getStatus()));
|
||||
}
|
||||
} while (netInBuffer.position() != 0); //continue to unwrapping as long as the input buffer has stuff
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read(ByteBuffer[] dsts, int offset, int length)
|
||||
throws IOException {
|
||||
//are we in the middle of closing or closed?
|
||||
if (closing || closed) {
|
||||
return -1;
|
||||
}
|
||||
//did we finish our handshake?
|
||||
if (!handshakeComplete) {
|
||||
throw new IllegalStateException(sm.getString("channel.nio.ssl.incompleteHandshake"));
|
||||
}
|
||||
|
||||
//read from the network
|
||||
int netread = sc.read(netInBuffer);
|
||||
//did we reach EOF? if so send EOF up one layer.
|
||||
if (netread == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//the data read
|
||||
int read = 0;
|
||||
//the SSL engine result
|
||||
SSLEngineResult unwrap;
|
||||
boolean processOverflow = false;
|
||||
do {
|
||||
boolean useOverflow = false;
|
||||
if (processOverflow) {
|
||||
useOverflow = true;
|
||||
}
|
||||
processOverflow = false;
|
||||
//prepare the buffer
|
||||
netInBuffer.flip();
|
||||
//unwrap the data
|
||||
unwrap = sslEngine.unwrap(netInBuffer, dsts, offset, length);
|
||||
//compact the buffer
|
||||
netInBuffer.compact();
|
||||
|
||||
if (unwrap.getStatus() == Status.OK || unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
|
||||
//we did receive some data, add it to our total
|
||||
read += unwrap.bytesProduced();
|
||||
if (useOverflow) {
|
||||
// Remove the data read into the overflow buffer
|
||||
read -= getBufHandler().getReadBuffer().position();
|
||||
}
|
||||
//perform any tasks if needed
|
||||
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
tasks();
|
||||
}
|
||||
//if we need more network data, then bail out for now.
|
||||
if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
|
||||
break;
|
||||
}
|
||||
} else if (unwrap.getStatus() == Status.BUFFER_OVERFLOW) {
|
||||
if (read > 0) {
|
||||
// Buffer overflow can happen if we have read data. Return
|
||||
// so the destination buffer can be emptied before another
|
||||
// read is attempted
|
||||
break;
|
||||
} else {
|
||||
ByteBuffer readBuffer = getBufHandler().getReadBuffer();
|
||||
boolean found = false;
|
||||
boolean resized = true;
|
||||
for (int i = 0; i < length; i++) {
|
||||
// The SSL session has increased the required buffer size
|
||||
// since the buffer was created.
|
||||
if (dsts[offset + i] == getBufHandler().getReadBuffer()) {
|
||||
getBufHandler().expand(sslEngine.getSession().getApplicationBufferSize());
|
||||
if (dsts[offset + i] == getBufHandler().getReadBuffer()) {
|
||||
resized = false;
|
||||
}
|
||||
dsts[offset + i] = getBufHandler().getReadBuffer();
|
||||
found = true;
|
||||
} else if (getAppReadBufHandler() != null && dsts[offset + i] == getAppReadBufHandler().getByteBuffer()) {
|
||||
getAppReadBufHandler().expand(sslEngine.getSession().getApplicationBufferSize());
|
||||
if (dsts[offset + i] == getAppReadBufHandler().getByteBuffer()) {
|
||||
resized = false;
|
||||
}
|
||||
dsts[offset + i] = getAppReadBufHandler().getByteBuffer();
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if (!resized) {
|
||||
throw new IOException(sm.getString("channel.nio.ssl.unwrapFail", unwrap.getStatus()));
|
||||
}
|
||||
} else {
|
||||
// Add the main read buffer in the destinations and try again
|
||||
ByteBuffer[] dsts2 = new ByteBuffer[dsts.length + 1];
|
||||
int dstOffset = 0;
|
||||
for (int i = 0; i < dsts.length + 1; i++) {
|
||||
if (i == offset + length) {
|
||||
dsts2[i] = readBuffer;
|
||||
dstOffset = -1;
|
||||
} else {
|
||||
dsts2[i] = dsts[i + dstOffset];
|
||||
}
|
||||
}
|
||||
dsts = dsts2;
|
||||
length++;
|
||||
getBufHandler().configureReadBufferForWrite();
|
||||
processOverflow = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Something else went wrong
|
||||
throw new IOException(sm.getString("channel.nio.ssl.unwrapFail", unwrap.getStatus()));
|
||||
}
|
||||
} while (netInBuffer.position() != 0 || processOverflow); //continue to unwrapping as long as the input buffer has stuff
|
||||
return read;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a sequence of bytes to this channel from the given buffer.
|
||||
*
|
||||
* @param src The buffer from which bytes are to be retrieved
|
||||
* @return The number of bytes written, possibly zero
|
||||
* @throws IOException If some other I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
checkInterruptStatus();
|
||||
if (src == this.netOutBuffer) {
|
||||
//we can get here through a recursive call
|
||||
//by using the NioBlockingSelector
|
||||
int written = sc.write(src);
|
||||
return written;
|
||||
} else {
|
||||
// Are we closing or closed?
|
||||
if (closing || closed) {
|
||||
throw new IOException(sm.getString("channel.nio.ssl.closing"));
|
||||
}
|
||||
|
||||
if (!flush(netOutBuffer)) {
|
||||
// We haven't emptied out the buffer yet
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The data buffer is empty, we can reuse the entire buffer.
|
||||
netOutBuffer.clear();
|
||||
|
||||
SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
|
||||
// The number of bytes written
|
||||
int written = result.bytesConsumed();
|
||||
netOutBuffer.flip();
|
||||
|
||||
if (result.getStatus() == Status.OK) {
|
||||
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks();
|
||||
} else {
|
||||
throw new IOException(sm.getString("channel.nio.ssl.wrapFail", result.getStatus()));
|
||||
}
|
||||
|
||||
// Force a flush
|
||||
flush(netOutBuffer);
|
||||
|
||||
return written;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long write(ByteBuffer[] srcs, int offset, int length)
|
||||
throws IOException {
|
||||
checkInterruptStatus();
|
||||
// Are we closing or closed?
|
||||
if (closing || closed) {
|
||||
throw new IOException(sm.getString("channel.nio.ssl.closing"));
|
||||
}
|
||||
|
||||
if (!flush(netOutBuffer)) {
|
||||
// We haven't emptied out the buffer yet
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The data buffer is empty, we can reuse the entire buffer.
|
||||
netOutBuffer.clear();
|
||||
|
||||
SSLEngineResult result = sslEngine.wrap(srcs, offset, length, netOutBuffer);
|
||||
// The number of bytes written
|
||||
int written = result.bytesConsumed();
|
||||
netOutBuffer.flip();
|
||||
|
||||
if (result.getStatus() == Status.OK) {
|
||||
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks();
|
||||
} else {
|
||||
throw new IOException(sm.getString("channel.nio.ssl.wrapFail", result.getStatus()));
|
||||
}
|
||||
|
||||
// Force a flush
|
||||
flush(netOutBuffer);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOutboundRemaining() {
|
||||
return netOutBuffer.remaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flushOutbound() throws IOException {
|
||||
int remaining = netOutBuffer.remaining();
|
||||
flush(netOutBuffer);
|
||||
int remaining2= netOutBuffer.remaining();
|
||||
return remaining2 < remaining;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHandshakeComplete() {
|
||||
return handshakeComplete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosing() {
|
||||
return closing;
|
||||
}
|
||||
|
||||
public SSLEngine getSslEngine() {
|
||||
return sslEngine;
|
||||
}
|
||||
|
||||
public ByteBuffer getEmptyBuf() {
|
||||
return emptyBuf;
|
||||
}
|
||||
}
|
||||
54
java/org/apache/tomcat/util/net/SendfileDataBase.java
Normal file
54
java/org/apache/tomcat/util/net/SendfileDataBase.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
public abstract class SendfileDataBase {
|
||||
|
||||
/**
|
||||
* Is the current request being processed on a keep-alive connection? This
|
||||
* determines if the socket is closed once the send file completes or if
|
||||
* processing continues with the next request on the connection or waiting
|
||||
* for that next request to arrive.
|
||||
*/
|
||||
public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE;
|
||||
|
||||
/**
|
||||
* The full path to the file that contains the data to be written to the
|
||||
* socket.
|
||||
*/
|
||||
public final String fileName;
|
||||
|
||||
/**
|
||||
* The position of the next byte in the file to be written to the socket.
|
||||
* This is initialised to the start point and then updated as the file is
|
||||
* written.
|
||||
*/
|
||||
public long pos;
|
||||
|
||||
/**
|
||||
* The number of bytes remaining to be written from the file (from the
|
||||
* current {@link #pos}. This is initialised to the end point - the start
|
||||
* point and then updated as the file is written.
|
||||
*/
|
||||
public long length;
|
||||
|
||||
public SendfileDataBase(String filename, long pos, long length) {
|
||||
this.fileName = filename;
|
||||
this.pos = pos;
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
39
java/org/apache/tomcat/util/net/SendfileKeepAliveState.java
Normal file
39
java/org/apache/tomcat/util/net/SendfileKeepAliveState.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
public enum SendfileKeepAliveState {
|
||||
|
||||
/**
|
||||
* Keep-alive is not in use. The socket can be closed when the response has
|
||||
* been written.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Keep-alive is in use and there is pipelined data in the input buffer to
|
||||
* be read as soon as the current response has been written.
|
||||
*/
|
||||
PIPELINED,
|
||||
|
||||
/**
|
||||
* Keep-alive is in use. The socket should be added to the poller (or
|
||||
* equivalent) to await more data as soon as the current response has been
|
||||
* written.
|
||||
*/
|
||||
OPEN
|
||||
}
|
||||
37
java/org/apache/tomcat/util/net/SendfileState.java
Normal file
37
java/org/apache/tomcat/util/net/SendfileState.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
public enum SendfileState {
|
||||
|
||||
/**
|
||||
* The sending of the file has started but has not completed. Sendfile is
|
||||
* still using the socket.
|
||||
*/
|
||||
PENDING,
|
||||
|
||||
/**
|
||||
* The file has been fully sent. Sendfile is no longer using the socket.
|
||||
*/
|
||||
DONE,
|
||||
|
||||
/**
|
||||
* Something went wrong. The file may or may not have been sent. The socket
|
||||
* is in an unknown state.
|
||||
*/
|
||||
ERROR
|
||||
}
|
||||
167
java/org/apache/tomcat/util/net/SocketBufferHandler.java
Normal file
167
java/org/apache/tomcat/util/net/SocketBufferHandler.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.tomcat.util.buf.ByteBufferUtils;
|
||||
|
||||
public class SocketBufferHandler {
|
||||
|
||||
private volatile boolean readBufferConfiguredForWrite = true;
|
||||
private volatile ByteBuffer readBuffer;
|
||||
|
||||
private volatile boolean writeBufferConfiguredForWrite = true;
|
||||
private volatile ByteBuffer writeBuffer;
|
||||
|
||||
private final boolean direct;
|
||||
|
||||
public SocketBufferHandler(int readBufferSize, int writeBufferSize,
|
||||
boolean direct) {
|
||||
this.direct = direct;
|
||||
if (direct) {
|
||||
readBuffer = ByteBuffer.allocateDirect(readBufferSize);
|
||||
writeBuffer = ByteBuffer.allocateDirect(writeBufferSize);
|
||||
} else {
|
||||
readBuffer = ByteBuffer.allocate(readBufferSize);
|
||||
writeBuffer = ByteBuffer.allocate(writeBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void configureReadBufferForWrite() {
|
||||
setReadBufferConfiguredForWrite(true);
|
||||
}
|
||||
|
||||
|
||||
public void configureReadBufferForRead() {
|
||||
setReadBufferConfiguredForWrite(false);
|
||||
}
|
||||
|
||||
|
||||
private void setReadBufferConfiguredForWrite(boolean readBufferConFiguredForWrite) {
|
||||
// NO-OP if buffer is already in correct state
|
||||
if (this.readBufferConfiguredForWrite != readBufferConFiguredForWrite) {
|
||||
if (readBufferConFiguredForWrite) {
|
||||
// Switching to write
|
||||
int remaining = readBuffer.remaining();
|
||||
if (remaining == 0) {
|
||||
readBuffer.clear();
|
||||
} else {
|
||||
readBuffer.compact();
|
||||
}
|
||||
} else {
|
||||
// Switching to read
|
||||
readBuffer.flip();
|
||||
}
|
||||
this.readBufferConfiguredForWrite = readBufferConFiguredForWrite;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ByteBuffer getReadBuffer() {
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
|
||||
public boolean isReadBufferEmpty() {
|
||||
if (readBufferConfiguredForWrite) {
|
||||
return readBuffer.position() == 0;
|
||||
} else {
|
||||
return readBuffer.remaining() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void configureWriteBufferForWrite() {
|
||||
setWriteBufferConfiguredForWrite(true);
|
||||
}
|
||||
|
||||
|
||||
public void configureWriteBufferForRead() {
|
||||
setWriteBufferConfiguredForWrite(false);
|
||||
}
|
||||
|
||||
|
||||
private void setWriteBufferConfiguredForWrite(boolean writeBufferConfiguredForWrite) {
|
||||
// NO-OP if buffer is already in correct state
|
||||
if (this.writeBufferConfiguredForWrite != writeBufferConfiguredForWrite) {
|
||||
if (writeBufferConfiguredForWrite) {
|
||||
// Switching to write
|
||||
int remaining = writeBuffer.remaining();
|
||||
if (remaining == 0) {
|
||||
writeBuffer.clear();
|
||||
} else {
|
||||
writeBuffer.compact();
|
||||
writeBuffer.position(remaining);
|
||||
writeBuffer.limit(writeBuffer.capacity());
|
||||
}
|
||||
} else {
|
||||
// Switching to read
|
||||
writeBuffer.flip();
|
||||
}
|
||||
this.writeBufferConfiguredForWrite = writeBufferConfiguredForWrite;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isWriteBufferWritable() {
|
||||
if (writeBufferConfiguredForWrite) {
|
||||
return writeBuffer.hasRemaining();
|
||||
} else {
|
||||
return writeBuffer.remaining() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ByteBuffer getWriteBuffer() {
|
||||
return writeBuffer;
|
||||
}
|
||||
|
||||
|
||||
public boolean isWriteBufferEmpty() {
|
||||
if (writeBufferConfiguredForWrite) {
|
||||
return writeBuffer.position() == 0;
|
||||
} else {
|
||||
return writeBuffer.remaining() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void reset() {
|
||||
readBuffer.clear();
|
||||
readBufferConfiguredForWrite = true;
|
||||
writeBuffer.clear();
|
||||
writeBufferConfiguredForWrite = true;
|
||||
}
|
||||
|
||||
|
||||
public void expand(int newSize) {
|
||||
configureReadBufferForWrite();
|
||||
readBuffer = ByteBufferUtils.expand(readBuffer, newSize);
|
||||
configureWriteBufferForWrite();
|
||||
writeBuffer = ByteBufferUtils.expand(writeBuffer, newSize);
|
||||
}
|
||||
|
||||
public void free() {
|
||||
if (direct) {
|
||||
ByteBufferUtils.cleanDirectBuffer(readBuffer);
|
||||
ByteBufferUtils.cleanDirectBuffer(writeBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
73
java/org/apache/tomcat/util/net/SocketEvent.java
Normal file
73
java/org/apache/tomcat/util/net/SocketEvent.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
/**
|
||||
* Defines events that occur per socket that require further processing by the
|
||||
* container. Usually these events are triggered by the socket implementation
|
||||
* but they may be triggered by the container.
|
||||
*/
|
||||
public enum SocketEvent {
|
||||
|
||||
/**
|
||||
* Data is available to be read.
|
||||
*/
|
||||
OPEN_READ,
|
||||
|
||||
/**
|
||||
* The socket is ready to be written to.
|
||||
*/
|
||||
OPEN_WRITE,
|
||||
|
||||
/**
|
||||
* The associated Connector/Endpoint is stopping and the connection/socket
|
||||
* needs to be closed cleanly.
|
||||
*/
|
||||
STOP,
|
||||
|
||||
/**
|
||||
* A timeout has occurred and the connection needs to be closed cleanly.
|
||||
* Currently this is only used by the Servlet 3.0 async processing.
|
||||
*/
|
||||
TIMEOUT,
|
||||
|
||||
/**
|
||||
* The client has disconnected.
|
||||
*/
|
||||
DISCONNECT,
|
||||
|
||||
/**
|
||||
* An error has occurred on a non-container thread and processing needs to
|
||||
* return to the container for any necessary clean-up. Examples of where
|
||||
* this is used include:
|
||||
* <ul>
|
||||
* <li>by NIO2 to signal the failure of a completion handler</li>
|
||||
* <li>by the container to signal an I/O error on a non-container thread
|
||||
* during Servlet 3.0 asynchronous processing.</li>
|
||||
* </ul>
|
||||
*/
|
||||
ERROR,
|
||||
|
||||
/**
|
||||
* A client attempted to establish a connection but failed. Examples of
|
||||
* where this is used include:
|
||||
* <ul>
|
||||
* <li>TLS handshake failures</li>
|
||||
* </ul>
|
||||
*/
|
||||
CONNECT_FAIL
|
||||
}
|
||||
55
java/org/apache/tomcat/util/net/SocketProcessorBase.java
Normal file
55
java/org/apache/tomcat/util/net/SocketProcessorBase.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class SocketProcessorBase<S> implements Runnable {
|
||||
|
||||
protected SocketWrapperBase<S> socketWrapper;
|
||||
protected SocketEvent event;
|
||||
|
||||
public SocketProcessorBase(SocketWrapperBase<S> socketWrapper, SocketEvent event) {
|
||||
reset(socketWrapper, event);
|
||||
}
|
||||
|
||||
|
||||
public void reset(SocketWrapperBase<S> socketWrapper, SocketEvent event) {
|
||||
Objects.requireNonNull(event);
|
||||
this.socketWrapper = socketWrapper;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void run() {
|
||||
synchronized (socketWrapper) {
|
||||
// It is possible that processing may be triggered for read and
|
||||
// write at the same time. The sync above makes sure that processing
|
||||
// does not occur in parallel. The test below ensures that if the
|
||||
// first event to be processed results in the socket being closed,
|
||||
// the subsequent events are not processed.
|
||||
if (socketWrapper.isClosed()) {
|
||||
return;
|
||||
}
|
||||
doRun();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected abstract void doRun();
|
||||
}
|
||||
441
java/org/apache/tomcat/util/net/SocketProperties.java
Normal file
441
java/org/apache/tomcat/util/net/SocketProperties.java
Normal file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.channels.AsynchronousServerSocketChannel;
|
||||
import java.nio.channels.AsynchronousSocketChannel;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Properties that can be set in the <Connector> element
|
||||
* in server.xml. All properties are prefixed with "socket."
|
||||
* and are currently only working for the Nio connector
|
||||
*/
|
||||
public class SocketProperties {
|
||||
|
||||
/**
|
||||
* Enable/disable socket processor cache, this bounded cache stores
|
||||
* SocketProcessor objects to reduce GC
|
||||
* Default is 500
|
||||
* -1 is unlimited
|
||||
* 0 is disabled
|
||||
*/
|
||||
protected int processorCache = 500;
|
||||
|
||||
/**
|
||||
* Enable/disable poller event cache, this bounded cache stores
|
||||
* PollerEvent objects to reduce GC for the poller
|
||||
* Default is 500
|
||||
* -1 is unlimited
|
||||
* 0 is disabled
|
||||
* >0 the max number of objects to keep in cache.
|
||||
*/
|
||||
protected int eventCache = 500;
|
||||
|
||||
/**
|
||||
* Enable/disable direct buffers for the network buffers
|
||||
* Default value is disabled
|
||||
*/
|
||||
protected boolean directBuffer = false;
|
||||
|
||||
/**
|
||||
* Enable/disable direct buffers for the network buffers for SSL
|
||||
* Default value is disabled
|
||||
*/
|
||||
protected boolean directSslBuffer = false;
|
||||
|
||||
/**
|
||||
* Socket receive buffer size in bytes (SO_RCVBUF).
|
||||
* JVM default used if not set.
|
||||
*/
|
||||
protected Integer rxBufSize = null;
|
||||
|
||||
/**
|
||||
* Socket send buffer size in bytes (SO_SNDBUF).
|
||||
* JVM default used if not set.
|
||||
*/
|
||||
protected Integer txBufSize = null;
|
||||
|
||||
/**
|
||||
* The application read buffer size in bytes.
|
||||
* Default value is rxBufSize
|
||||
*/
|
||||
protected int appReadBufSize = 8192;
|
||||
|
||||
/**
|
||||
* The application write buffer size in bytes
|
||||
* Default value is txBufSize
|
||||
*/
|
||||
protected int appWriteBufSize = 8192;
|
||||
|
||||
/**
|
||||
* NioChannel pool size for the endpoint,
|
||||
* this value is how many channels
|
||||
* -1 means unlimited cached, 0 means no cache
|
||||
* Default value is 500
|
||||
*/
|
||||
protected int bufferPool = 500;
|
||||
|
||||
/**
|
||||
* Buffer pool size in bytes to be cached
|
||||
* -1 means unlimited, 0 means no cache
|
||||
* Default value is 100MB (1024*1024*100 bytes)
|
||||
*/
|
||||
protected int bufferPoolSize = 1024*1024*100;
|
||||
|
||||
/**
|
||||
* TCP_NO_DELAY option. JVM default used if not set.
|
||||
*/
|
||||
protected Boolean tcpNoDelay = Boolean.TRUE;
|
||||
|
||||
/**
|
||||
* SO_KEEPALIVE option. JVM default used if not set.
|
||||
*/
|
||||
protected Boolean soKeepAlive = null;
|
||||
|
||||
/**
|
||||
* OOBINLINE option. JVM default used if not set.
|
||||
*/
|
||||
protected Boolean ooBInline = null;
|
||||
|
||||
/**
|
||||
* SO_REUSEADDR option. JVM default used if not set.
|
||||
*/
|
||||
protected Boolean soReuseAddress = null;
|
||||
|
||||
/**
|
||||
* SO_LINGER option, paired with the <code>soLingerTime</code> value.
|
||||
* JVM defaults used unless both attributes are set.
|
||||
*/
|
||||
protected Boolean soLingerOn = null;
|
||||
|
||||
/**
|
||||
* SO_LINGER option, paired with the <code>soLingerOn</code> value.
|
||||
* JVM defaults used unless both attributes are set.
|
||||
*/
|
||||
protected Integer soLingerTime = null;
|
||||
|
||||
/**
|
||||
* SO_TIMEOUT option. default is 20000.
|
||||
*/
|
||||
protected Integer soTimeout = Integer.valueOf(20000);
|
||||
|
||||
/**
|
||||
* Performance preferences according to
|
||||
* http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)
|
||||
* All three performance attributes must be set or the JVM defaults will be
|
||||
* used.
|
||||
*/
|
||||
protected Integer performanceConnectionTime = null;
|
||||
|
||||
/**
|
||||
* Performance preferences according to
|
||||
* http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)
|
||||
* All three performance attributes must be set or the JVM defaults will be
|
||||
* used.
|
||||
*/
|
||||
protected Integer performanceLatency = null;
|
||||
|
||||
/**
|
||||
* Performance preferences according to
|
||||
* http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)
|
||||
* All three performance attributes must be set or the JVM defaults will be
|
||||
* used.
|
||||
*/
|
||||
protected Integer performanceBandwidth = null;
|
||||
|
||||
/**
|
||||
* The minimum frequency of the timeout interval to avoid excess load from
|
||||
* the poller during high traffic
|
||||
*/
|
||||
protected long timeoutInterval = 1000;
|
||||
|
||||
/**
|
||||
* Timeout in milliseconds for an unlock to take place.
|
||||
*/
|
||||
protected int unlockTimeout = 250;
|
||||
|
||||
private ObjectName oname = null;
|
||||
|
||||
|
||||
public void setProperties(Socket socket) throws SocketException{
|
||||
if (rxBufSize != null)
|
||||
socket.setReceiveBufferSize(rxBufSize.intValue());
|
||||
if (txBufSize != null)
|
||||
socket.setSendBufferSize(txBufSize.intValue());
|
||||
if (ooBInline !=null)
|
||||
socket.setOOBInline(ooBInline.booleanValue());
|
||||
if (soKeepAlive != null)
|
||||
socket.setKeepAlive(soKeepAlive.booleanValue());
|
||||
if (performanceConnectionTime != null && performanceLatency != null &&
|
||||
performanceBandwidth != null)
|
||||
socket.setPerformancePreferences(
|
||||
performanceConnectionTime.intValue(),
|
||||
performanceLatency.intValue(),
|
||||
performanceBandwidth.intValue());
|
||||
if (soReuseAddress != null)
|
||||
socket.setReuseAddress(soReuseAddress.booleanValue());
|
||||
if (soLingerOn != null && soLingerTime != null)
|
||||
socket.setSoLinger(soLingerOn.booleanValue(),
|
||||
soLingerTime.intValue());
|
||||
if (soTimeout != null && soTimeout.intValue() >= 0)
|
||||
socket.setSoTimeout(soTimeout.intValue());
|
||||
if (tcpNoDelay != null) {
|
||||
try {
|
||||
socket.setTcpNoDelay(tcpNoDelay.booleanValue());
|
||||
} catch (SocketException e) {
|
||||
// Some socket types may not support this option which is set by default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setProperties(ServerSocket socket) throws SocketException{
|
||||
if (rxBufSize != null)
|
||||
socket.setReceiveBufferSize(rxBufSize.intValue());
|
||||
if (performanceConnectionTime != null && performanceLatency != null &&
|
||||
performanceBandwidth != null)
|
||||
socket.setPerformancePreferences(
|
||||
performanceConnectionTime.intValue(),
|
||||
performanceLatency.intValue(),
|
||||
performanceBandwidth.intValue());
|
||||
if (soReuseAddress != null)
|
||||
socket.setReuseAddress(soReuseAddress.booleanValue());
|
||||
if (soTimeout != null && soTimeout.intValue() >= 0)
|
||||
socket.setSoTimeout(soTimeout.intValue());
|
||||
}
|
||||
|
||||
public void setProperties(AsynchronousSocketChannel socket) throws IOException {
|
||||
if (rxBufSize != null)
|
||||
socket.setOption(StandardSocketOptions.SO_RCVBUF, rxBufSize);
|
||||
if (txBufSize != null)
|
||||
socket.setOption(StandardSocketOptions.SO_SNDBUF, txBufSize);
|
||||
if (soKeepAlive != null)
|
||||
socket.setOption(StandardSocketOptions.SO_KEEPALIVE, soKeepAlive);
|
||||
if (soReuseAddress != null)
|
||||
socket.setOption(StandardSocketOptions.SO_REUSEADDR, soReuseAddress);
|
||||
if (soLingerOn != null && soLingerOn.booleanValue() && soLingerTime != null)
|
||||
socket.setOption(StandardSocketOptions.SO_LINGER, soLingerTime);
|
||||
if (tcpNoDelay != null)
|
||||
socket.setOption(StandardSocketOptions.TCP_NODELAY, tcpNoDelay);
|
||||
}
|
||||
|
||||
public void setProperties(AsynchronousServerSocketChannel socket) throws IOException {
|
||||
if (rxBufSize != null)
|
||||
socket.setOption(StandardSocketOptions.SO_RCVBUF, rxBufSize);
|
||||
if (soReuseAddress != null)
|
||||
socket.setOption(StandardSocketOptions.SO_REUSEADDR, soReuseAddress);
|
||||
}
|
||||
|
||||
public boolean getDirectBuffer() {
|
||||
return directBuffer;
|
||||
}
|
||||
|
||||
public boolean getDirectSslBuffer() {
|
||||
return directSslBuffer;
|
||||
}
|
||||
|
||||
public boolean getOoBInline() {
|
||||
return ooBInline.booleanValue();
|
||||
}
|
||||
|
||||
public int getPerformanceBandwidth() {
|
||||
return performanceBandwidth.intValue();
|
||||
}
|
||||
|
||||
public int getPerformanceConnectionTime() {
|
||||
return performanceConnectionTime.intValue();
|
||||
}
|
||||
|
||||
public int getPerformanceLatency() {
|
||||
return performanceLatency.intValue();
|
||||
}
|
||||
|
||||
public int getRxBufSize() {
|
||||
return rxBufSize.intValue();
|
||||
}
|
||||
|
||||
public boolean getSoKeepAlive() {
|
||||
return soKeepAlive.booleanValue();
|
||||
}
|
||||
|
||||
public boolean getSoLingerOn() {
|
||||
return soLingerOn.booleanValue();
|
||||
}
|
||||
|
||||
public int getSoLingerTime() {
|
||||
return soLingerTime.intValue();
|
||||
}
|
||||
|
||||
public boolean getSoReuseAddress() {
|
||||
return soReuseAddress.booleanValue();
|
||||
}
|
||||
|
||||
public int getSoTimeout() {
|
||||
return soTimeout.intValue();
|
||||
}
|
||||
|
||||
public boolean getTcpNoDelay() {
|
||||
return tcpNoDelay.booleanValue();
|
||||
}
|
||||
|
||||
public int getTxBufSize() {
|
||||
return txBufSize.intValue();
|
||||
}
|
||||
|
||||
public int getBufferPool() {
|
||||
return bufferPool;
|
||||
}
|
||||
|
||||
public int getBufferPoolSize() {
|
||||
return bufferPoolSize;
|
||||
}
|
||||
|
||||
public int getEventCache() {
|
||||
return eventCache;
|
||||
}
|
||||
|
||||
public int getAppReadBufSize() {
|
||||
return appReadBufSize;
|
||||
}
|
||||
|
||||
public int getAppWriteBufSize() {
|
||||
return appWriteBufSize;
|
||||
}
|
||||
|
||||
public int getProcessorCache() {
|
||||
return processorCache;
|
||||
}
|
||||
|
||||
public long getTimeoutInterval() {
|
||||
return timeoutInterval;
|
||||
}
|
||||
|
||||
public int getDirectBufferPool() {
|
||||
return bufferPool;
|
||||
}
|
||||
|
||||
public void setPerformanceConnectionTime(int performanceConnectionTime) {
|
||||
this.performanceConnectionTime =
|
||||
Integer.valueOf(performanceConnectionTime);
|
||||
}
|
||||
|
||||
public void setTxBufSize(int txBufSize) {
|
||||
this.txBufSize = Integer.valueOf(txBufSize);
|
||||
}
|
||||
|
||||
public void setTcpNoDelay(boolean tcpNoDelay) {
|
||||
this.tcpNoDelay = Boolean.valueOf(tcpNoDelay);
|
||||
}
|
||||
|
||||
public void setSoTimeout(int soTimeout) {
|
||||
this.soTimeout = Integer.valueOf(soTimeout);
|
||||
}
|
||||
|
||||
public void setSoReuseAddress(boolean soReuseAddress) {
|
||||
this.soReuseAddress = Boolean.valueOf(soReuseAddress);
|
||||
}
|
||||
|
||||
public void setSoLingerTime(int soLingerTime) {
|
||||
this.soLingerTime = Integer.valueOf(soLingerTime);
|
||||
}
|
||||
|
||||
public void setSoKeepAlive(boolean soKeepAlive) {
|
||||
this.soKeepAlive = Boolean.valueOf(soKeepAlive);
|
||||
}
|
||||
|
||||
public void setRxBufSize(int rxBufSize) {
|
||||
this.rxBufSize = Integer.valueOf(rxBufSize);
|
||||
}
|
||||
|
||||
public void setPerformanceLatency(int performanceLatency) {
|
||||
this.performanceLatency = Integer.valueOf(performanceLatency);
|
||||
}
|
||||
|
||||
public void setPerformanceBandwidth(int performanceBandwidth) {
|
||||
this.performanceBandwidth = Integer.valueOf(performanceBandwidth);
|
||||
}
|
||||
|
||||
public void setOoBInline(boolean ooBInline) {
|
||||
this.ooBInline = Boolean.valueOf(ooBInline);
|
||||
}
|
||||
|
||||
public void setDirectBuffer(boolean directBuffer) {
|
||||
this.directBuffer = directBuffer;
|
||||
}
|
||||
|
||||
public void setDirectSslBuffer(boolean directSslBuffer) {
|
||||
this.directSslBuffer = directSslBuffer;
|
||||
}
|
||||
|
||||
public void setSoLingerOn(boolean soLingerOn) {
|
||||
this.soLingerOn = Boolean.valueOf(soLingerOn);
|
||||
}
|
||||
|
||||
public void setBufferPool(int bufferPool) {
|
||||
this.bufferPool = bufferPool;
|
||||
}
|
||||
|
||||
public void setBufferPoolSize(int bufferPoolSize) {
|
||||
this.bufferPoolSize = bufferPoolSize;
|
||||
}
|
||||
|
||||
public void setEventCache(int eventCache) {
|
||||
this.eventCache = eventCache;
|
||||
}
|
||||
|
||||
public void setAppReadBufSize(int appReadBufSize) {
|
||||
this.appReadBufSize = appReadBufSize;
|
||||
}
|
||||
|
||||
public void setAppWriteBufSize(int appWriteBufSize) {
|
||||
this.appWriteBufSize = appWriteBufSize;
|
||||
}
|
||||
|
||||
public void setProcessorCache(int processorCache) {
|
||||
this.processorCache = processorCache;
|
||||
}
|
||||
|
||||
public void setTimeoutInterval(long timeoutInterval) {
|
||||
this.timeoutInterval = timeoutInterval;
|
||||
}
|
||||
|
||||
public void setDirectBufferPool(int directBufferPool) {
|
||||
this.bufferPool = directBufferPool;
|
||||
}
|
||||
|
||||
public int getUnlockTimeout() {
|
||||
return unlockTimeout;
|
||||
}
|
||||
|
||||
public void setUnlockTimeout(int unlockTimeout) {
|
||||
this.unlockTimeout = unlockTimeout;
|
||||
}
|
||||
|
||||
void setObjectName(ObjectName oname) {
|
||||
this.oname = oname;
|
||||
}
|
||||
|
||||
ObjectName getObjectName() {
|
||||
return oname;
|
||||
}
|
||||
}
|
||||
1428
java/org/apache/tomcat/util/net/SocketWrapperBase.java
Normal file
1428
java/org/apache/tomcat/util/net/SocketWrapperBase.java
Normal file
File diff suppressed because it is too large
Load Diff
366
java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java
Normal file
366
java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.http.parser.HttpParser;
|
||||
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* This class extracts the SNI host name and ALPN protocols from a TLS
|
||||
* client-hello message.
|
||||
*/
|
||||
public class TLSClientHelloExtractor {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TLSClientHelloExtractor.class);
|
||||
private static final StringManager sm = StringManager.getManager(TLSClientHelloExtractor.class);
|
||||
|
||||
private final ExtractorResult result;
|
||||
private final List<Cipher> clientRequestedCiphers;
|
||||
private final String sniValue;
|
||||
private final List<String> clientRequestedApplicationProtocols;
|
||||
|
||||
private static final int TLS_RECORD_HEADER_LEN = 5;
|
||||
|
||||
private static final int TLS_EXTENSION_SERVER_NAME = 0;
|
||||
private static final int TLS_EXTENSION_ALPN = 16;
|
||||
|
||||
public static byte[] USE_TLS_RESPONSE = ("HTTP/1.1 400 \r\n" +
|
||||
"Content-Type: text/plain;charset=UTF-8\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n" +
|
||||
"Bad Request\r\n" +
|
||||
"This combination of host and port requires TLS.\r\n").getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
|
||||
/**
|
||||
* Creates the instance of the parser and processes the provided buffer. The
|
||||
* buffer position and limit will be modified during the execution of this
|
||||
* method but they will be returned to the original values before the method
|
||||
* exits.
|
||||
*
|
||||
* @param netInBuffer The buffer containing the TLS data to process
|
||||
* @throws IOException If the client hello message is malformed
|
||||
*/
|
||||
public TLSClientHelloExtractor(ByteBuffer netInBuffer) throws IOException {
|
||||
// Buffer is in write mode at this point. Record the current position so
|
||||
// the buffer state can be restored at the end of this method.
|
||||
int pos = netInBuffer.position();
|
||||
int limit = netInBuffer.limit();
|
||||
ExtractorResult result = ExtractorResult.NOT_PRESENT;
|
||||
List<Cipher> clientRequestedCiphers = new ArrayList<>();
|
||||
List<String> clientRequestedApplicationProtocols = new ArrayList<>();
|
||||
String sniValue = null;
|
||||
try {
|
||||
// Switch to read mode.
|
||||
netInBuffer.flip();
|
||||
|
||||
// A complete TLS record header is required before we can figure out
|
||||
// how many bytes there are in the record.
|
||||
if (!isAvailable(netInBuffer, TLS_RECORD_HEADER_LEN)) {
|
||||
result = handleIncompleteRead(netInBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isTLSHandshake(netInBuffer)) {
|
||||
// Is the client trying to use clear text HTTP?
|
||||
if (isHttp(netInBuffer)) {
|
||||
result = ExtractorResult.NON_SECURE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAllRecordAvailable(netInBuffer)) {
|
||||
result = handleIncompleteRead(netInBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isClientHello(netInBuffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAllClientHelloAvailable(netInBuffer)) {
|
||||
// Client hello didn't fit into single TLS record.
|
||||
// Treat this as not present.
|
||||
log.warn(sm.getString("sniExtractor.clientHelloTooBig"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Protocol Version
|
||||
skipBytes(netInBuffer, 2);
|
||||
// Random
|
||||
skipBytes(netInBuffer, 32);
|
||||
// Session ID (single byte for length)
|
||||
skipBytes(netInBuffer, (netInBuffer.get() & 0xFF));
|
||||
|
||||
// Cipher Suites
|
||||
// (2 bytes for length, each cipher ID is 2 bytes)
|
||||
int cipherCount = netInBuffer.getChar() / 2;
|
||||
for (int i = 0; i < cipherCount; i++) {
|
||||
int cipherId = netInBuffer.getChar();
|
||||
clientRequestedCiphers.add(Cipher.valueOf(cipherId));
|
||||
}
|
||||
|
||||
// Compression methods (single byte for length)
|
||||
skipBytes(netInBuffer, (netInBuffer.get() & 0xFF));
|
||||
|
||||
if (!netInBuffer.hasRemaining()) {
|
||||
// No more data means no extensions present
|
||||
return;
|
||||
}
|
||||
|
||||
// Extension length
|
||||
skipBytes(netInBuffer, 2);
|
||||
// Read the extensions until we run out of data or find the data
|
||||
// we need
|
||||
while (netInBuffer.hasRemaining() &&
|
||||
(sniValue == null || clientRequestedApplicationProtocols.size() == 0)) {
|
||||
// Extension type is two byte
|
||||
char extensionType = netInBuffer.getChar();
|
||||
// Extension size is another two bytes
|
||||
char extensionDataSize = netInBuffer.getChar();
|
||||
switch (extensionType) {
|
||||
case TLS_EXTENSION_SERVER_NAME: {
|
||||
sniValue = readSniExtension(netInBuffer);
|
||||
break;
|
||||
}
|
||||
case TLS_EXTENSION_ALPN:
|
||||
readAlpnExtension(netInBuffer, clientRequestedApplicationProtocols);
|
||||
break;
|
||||
default: {
|
||||
skipBytes(netInBuffer, extensionDataSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
result = ExtractorResult.COMPLETE;
|
||||
} catch (BufferUnderflowException | IllegalArgumentException e) {
|
||||
throw new IOException(sm.getString("sniExtractor.clientHelloInvalid"), e);
|
||||
} finally {
|
||||
this.result = result;
|
||||
this.clientRequestedCiphers = clientRequestedCiphers;
|
||||
this.clientRequestedApplicationProtocols = clientRequestedApplicationProtocols;
|
||||
this.sniValue = sniValue;
|
||||
// Whatever happens, return the buffer to its original state
|
||||
netInBuffer.limit(limit);
|
||||
netInBuffer.position(pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ExtractorResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public String getSNIValue() {
|
||||
if (result == ExtractorResult.COMPLETE) {
|
||||
return sniValue;
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<Cipher> getClientRequestedCiphers() {
|
||||
if (result == ExtractorResult.COMPLETE || result == ExtractorResult.NOT_PRESENT) {
|
||||
return clientRequestedCiphers;
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<String> getClientRequestedApplicationProtocols() {
|
||||
if (result == ExtractorResult.COMPLETE || result == ExtractorResult.NOT_PRESENT) {
|
||||
return clientRequestedApplicationProtocols;
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static ExtractorResult handleIncompleteRead(ByteBuffer bb) {
|
||||
if (bb.limit() == bb.capacity()) {
|
||||
// Buffer not big enough
|
||||
return ExtractorResult.UNDERFLOW;
|
||||
} else {
|
||||
// Need to read more data into buffer
|
||||
return ExtractorResult.NEED_READ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static boolean isAvailable(ByteBuffer bb, int size) {
|
||||
if (bb.remaining() < size) {
|
||||
bb.position(bb.limit());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isTLSHandshake(ByteBuffer bb) {
|
||||
// For a TLS client hello the first byte must be 22 - handshake
|
||||
if (bb.get() != 22) {
|
||||
return false;
|
||||
}
|
||||
// Next two bytes are major/minor version. We need at least 3.1.
|
||||
byte b2 = bb.get();
|
||||
byte b3 = bb.get();
|
||||
if (b2 < 3 || b2 == 3 && b3 == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isHttp(ByteBuffer bb) {
|
||||
// Based on code in Http11InputBuffer
|
||||
// Note: The actual request is not important. This code only checks that
|
||||
// the buffer contains a correctly formatted HTTP request line.
|
||||
// The method, target and protocol are not validated.
|
||||
byte chr = 0;
|
||||
bb.position(0);
|
||||
|
||||
// Skip blank lines
|
||||
do {
|
||||
if (!bb.hasRemaining()) {
|
||||
return false;
|
||||
}
|
||||
chr = bb.get();
|
||||
} while (chr == '\r' || chr == '\n');
|
||||
|
||||
// Read the method
|
||||
do {
|
||||
if (!HttpParser.isToken(chr) || !bb.hasRemaining()) {
|
||||
return false;
|
||||
}
|
||||
chr = bb.get();
|
||||
} while (chr != ' ' && chr != '\t');
|
||||
|
||||
// Whitespace between method and target
|
||||
while (chr == ' ' || chr == '\t') {
|
||||
if (!bb.hasRemaining()) {
|
||||
return false;
|
||||
}
|
||||
chr = bb.get();
|
||||
}
|
||||
|
||||
// Read the target
|
||||
while (chr != ' ' && chr != '\t') {
|
||||
if (HttpParser.isNotRequestTarget(chr) || !bb.hasRemaining()) {
|
||||
return false;
|
||||
}
|
||||
chr = bb.get();
|
||||
}
|
||||
|
||||
// Whitespace between target and protocol
|
||||
while (chr == ' ' || chr == '\t') {
|
||||
if (!bb.hasRemaining()) {
|
||||
return false;
|
||||
}
|
||||
chr = bb.get();
|
||||
}
|
||||
|
||||
// Read protocol
|
||||
do {
|
||||
if (!HttpParser.isHttpProtocol(chr) || !bb.hasRemaining()) {
|
||||
return false;
|
||||
}
|
||||
chr = bb.get();
|
||||
|
||||
} while (chr != '\r' && chr != '\n');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isAllRecordAvailable(ByteBuffer bb) {
|
||||
// Next two bytes (unsigned) are the size of the record. We need all of
|
||||
// it.
|
||||
int size = bb.getChar();
|
||||
return isAvailable(bb, size);
|
||||
}
|
||||
|
||||
|
||||
private static boolean isClientHello(ByteBuffer bb) {
|
||||
// Client hello is handshake type 1
|
||||
if (bb.get() == 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isAllClientHelloAvailable(ByteBuffer bb) {
|
||||
// Next three bytes (unsigned) are the size of the client hello. We need
|
||||
// all of it.
|
||||
int size = ((bb.get() & 0xFF) << 16) + ((bb.get() & 0xFF) << 8) + (bb.get() & 0xFF);
|
||||
return isAvailable(bb, size);
|
||||
}
|
||||
|
||||
|
||||
private static void skipBytes(ByteBuffer bb, int size) {
|
||||
bb.position(bb.position() + size);
|
||||
}
|
||||
|
||||
|
||||
private static String readSniExtension(ByteBuffer bb) {
|
||||
// First 2 bytes are size of server name list (only expecting one)
|
||||
// Next byte is type (0 for hostname)
|
||||
skipBytes(bb, 3);
|
||||
// Next 2 bytes are length of host name
|
||||
char serverNameSize = bb.getChar();
|
||||
byte[] serverNameBytes = new byte[serverNameSize];
|
||||
bb.get(serverNameBytes);
|
||||
return new String(serverNameBytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
|
||||
private static void readAlpnExtension(ByteBuffer bb, List<String> protocolNames) {
|
||||
// First 2 bytes are size of the protocol list
|
||||
char toRead = bb.getChar();
|
||||
byte[] inputBuffer = new byte[255];
|
||||
while (toRead > 0) {
|
||||
// Each list entry has one byte for length followed by a string of
|
||||
// that length
|
||||
int len = bb.get() & 0xFF;
|
||||
bb.get(inputBuffer, 0, len);
|
||||
protocolNames.add(new String(inputBuffer, 0, len, StandardCharsets.UTF_8));
|
||||
toRead--;
|
||||
toRead -= len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum ExtractorResult {
|
||||
COMPLETE,
|
||||
NOT_PRESENT,
|
||||
UNDERFLOW,
|
||||
NEED_READ,
|
||||
NON_SECURE
|
||||
}
|
||||
}
|
||||
144
java/org/apache/tomcat/util/net/WriteBuffer.java
Normal file
144
java/org/apache/tomcat/util/net/WriteBuffer.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
|
||||
import org.apache.tomcat.util.buf.ByteBufferHolder;
|
||||
|
||||
/**
|
||||
* Provides an expandable set of buffers for writes. Non-blocking writes can be
|
||||
* of any size and may not be able to be written immediately or wholly contained
|
||||
* in the buffer used to perform the writes to the next layer. This class
|
||||
* provides a buffering capability to allow such writes to return immediately
|
||||
* and also allows for the user provided buffers to be re-used / recycled as
|
||||
* required.
|
||||
*/
|
||||
public class WriteBuffer {
|
||||
|
||||
private final int bufferSize;
|
||||
|
||||
private final LinkedBlockingDeque<ByteBufferHolder> buffers = new LinkedBlockingDeque<>();
|
||||
|
||||
public WriteBuffer(int bufferSize) {
|
||||
this.bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
|
||||
void add(byte[] buf, int offset, int length) {
|
||||
ByteBufferHolder holder = getByteBufferHolder(length);
|
||||
holder.getBuf().put(buf, offset, length);
|
||||
}
|
||||
|
||||
|
||||
public void add(ByteBuffer from) {
|
||||
ByteBufferHolder holder = getByteBufferHolder(from.remaining());
|
||||
holder.getBuf().put(from);
|
||||
}
|
||||
|
||||
|
||||
private ByteBufferHolder getByteBufferHolder(int capacity) {
|
||||
ByteBufferHolder holder = buffers.peekLast();
|
||||
if (holder == null || holder.isFlipped() || holder.getBuf().remaining() < capacity) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(Math.max(bufferSize, capacity));
|
||||
holder = new ByteBufferHolder(buffer, false);
|
||||
buffers.add(holder);
|
||||
}
|
||||
return holder;
|
||||
}
|
||||
|
||||
|
||||
public boolean isEmpty() {
|
||||
return buffers.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create an array of ByteBuffers from the current WriteBuffer, prefixing
|
||||
* that array with the provided ByteBuffers.
|
||||
*
|
||||
* @param prefixes The additional ByteBuffers to add to the start of the
|
||||
* array
|
||||
*
|
||||
* @return an array of ByteBuffers from the current WriteBuffer prefixed by
|
||||
* the provided ByteBuffers
|
||||
*/
|
||||
ByteBuffer[] toArray(ByteBuffer... prefixes) {
|
||||
List<ByteBuffer> result = new ArrayList<>();
|
||||
for (ByteBuffer prefix : prefixes) {
|
||||
if (prefix.hasRemaining()) {
|
||||
result.add(prefix);
|
||||
}
|
||||
}
|
||||
for (ByteBufferHolder buffer : buffers) {
|
||||
buffer.flip();
|
||||
result.add(buffer.getBuf());
|
||||
}
|
||||
buffers.clear();
|
||||
return result.toArray(new ByteBuffer[result.size()]);
|
||||
}
|
||||
|
||||
|
||||
boolean write(SocketWrapperBase<?> socketWrapper, boolean blocking) throws IOException {
|
||||
Iterator<ByteBufferHolder> bufIter = buffers.iterator();
|
||||
boolean dataLeft = false;
|
||||
while (!dataLeft && bufIter.hasNext()) {
|
||||
ByteBufferHolder buffer = bufIter.next();
|
||||
buffer.flip();
|
||||
if (blocking) {
|
||||
socketWrapper.writeBlocking(buffer.getBuf());
|
||||
} else {
|
||||
socketWrapper.writeNonBlockingInternal(buffer.getBuf());
|
||||
}
|
||||
if (buffer.getBuf().remaining() == 0) {
|
||||
bufIter.remove();
|
||||
} else {
|
||||
dataLeft = true;
|
||||
}
|
||||
}
|
||||
return dataLeft;
|
||||
}
|
||||
|
||||
|
||||
public boolean write(Sink sink, boolean blocking) throws IOException {
|
||||
Iterator<ByteBufferHolder> bufIter = buffers.iterator();
|
||||
boolean dataLeft = false;
|
||||
while (!dataLeft && bufIter.hasNext()) {
|
||||
ByteBufferHolder buffer = bufIter.next();
|
||||
buffer.flip();
|
||||
dataLeft = sink.writeFromBuffer(buffer.getBuf(), blocking);
|
||||
if (!dataLeft) {
|
||||
bufIter.remove();
|
||||
}
|
||||
}
|
||||
return dataLeft;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface implemented by clients of the WriteBuffer to enable data to be
|
||||
* written back out from the buffer.
|
||||
*/
|
||||
public interface Sink {
|
||||
boolean writeFromBuffer(ByteBuffer buffer, boolean block) throws IOException;
|
||||
}
|
||||
}
|
||||
57
java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java
Normal file
57
java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.jsse;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.apache.tomcat.util.compat.JreCompat;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
|
||||
import org.apache.tomcat.util.net.SSLImplementation;
|
||||
import org.apache.tomcat.util.net.SSLSupport;
|
||||
import org.apache.tomcat.util.net.SSLUtil;
|
||||
|
||||
/* JSSEImplementation:
|
||||
|
||||
Concrete implementation class for JSSE
|
||||
|
||||
@author EKR
|
||||
*/
|
||||
|
||||
public class JSSEImplementation extends SSLImplementation {
|
||||
|
||||
public JSSEImplementation() {
|
||||
// Make sure the keySizeCache is loaded now as part of connector startup
|
||||
// else the cache will be populated on first use which will slow that
|
||||
// request down.
|
||||
JSSESupport.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLSupport getSSLSupport(SSLSession session) {
|
||||
return new JSSESupport(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLUtil getSSLUtil(SSLHostConfigCertificate certificate) {
|
||||
return new JSSEUtil(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlpnSupported() {
|
||||
return JreCompat.isJre9Available();
|
||||
}
|
||||
}
|
||||
123
java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java
Normal file
123
java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.jsse;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
|
||||
/**
|
||||
* X509KeyManager which allows selection of a specific keypair and certificate
|
||||
* chain (identified by their keystore alias name) to be used by the server to
|
||||
* authenticate itself to SSL clients.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*/
|
||||
public final class JSSEKeyManager extends X509ExtendedKeyManager {
|
||||
|
||||
private X509KeyManager delegate;
|
||||
private String serverKeyAlias;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param mgr The X509KeyManager used as a delegate
|
||||
* @param serverKeyAlias The alias name of the server's keypair and
|
||||
* supporting certificate chain
|
||||
*/
|
||||
public JSSEKeyManager(X509KeyManager mgr, String serverKeyAlias) {
|
||||
super();
|
||||
this.delegate = mgr;
|
||||
this.serverKeyAlias = serverKeyAlias;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the server key alias that was provided in the constructor or the
|
||||
* result from {@link X509KeyManager#chooseServerAlias(String, Principal[],
|
||||
* Socket)} for the delegate if no alias is specified.
|
||||
*/
|
||||
@Override
|
||||
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
|
||||
if (serverKeyAlias != null) {
|
||||
return serverKeyAlias;
|
||||
}
|
||||
|
||||
return delegate.chooseServerAlias(keyType, issuers, socket);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the server key alias that was provided in the constructor or the
|
||||
* result from {@link X509ExtendedKeyManager#chooseEngineServerAlias(String,
|
||||
* Principal[], SSLEngine)} for the delegate if no alias is specified.
|
||||
*/
|
||||
@Override
|
||||
public String chooseEngineServerAlias(String keyType, Principal[] issuers,
|
||||
SSLEngine engine) {
|
||||
if (serverKeyAlias!=null) {
|
||||
return serverKeyAlias;
|
||||
}
|
||||
|
||||
return super.chooseEngineServerAlias(keyType, issuers, engine);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String chooseClientAlias(String[] keyType, Principal[] issuers,
|
||||
Socket socket) {
|
||||
return delegate.chooseClientAlias(keyType, issuers, socket);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(String alias) {
|
||||
return delegate.getCertificateChain(alias);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getClientAliases(String keyType, Principal[] issuers) {
|
||||
return delegate.getClientAliases(keyType, issuers);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getServerAliases(String keyType, Principal[] issuers) {
|
||||
return delegate.getServerAliases(keyType, issuers);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PrivateKey getPrivateKey(String alias) {
|
||||
return delegate.getPrivateKey(alias);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers,
|
||||
SSLEngine engine) {
|
||||
return delegate.chooseClientAlias(keyType, issuers, null);
|
||||
}
|
||||
}
|
||||
110
java/org/apache/tomcat/util/net/jsse/JSSESSLContext.java
Normal file
110
java/org/apache/tomcat/util/net/jsse/JSSESSLContext.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.jsse;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.apache.tomcat.util.net.SSLContext;
|
||||
|
||||
class JSSESSLContext implements SSLContext {
|
||||
|
||||
private javax.net.ssl.SSLContext context;
|
||||
private KeyManager[] kms;
|
||||
private TrustManager[] tms;
|
||||
|
||||
JSSESSLContext(String protocol) throws NoSuchAlgorithmException {
|
||||
context = javax.net.ssl.SSLContext.getInstance(protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(KeyManager[] kms, TrustManager[] tms, SecureRandom sr)
|
||||
throws KeyManagementException {
|
||||
this.kms = kms;
|
||||
this.tms = tms;
|
||||
context.init(kms, tms, sr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLSessionContext getServerSessionContext() {
|
||||
return context.getServerSessionContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngine createSSLEngine() {
|
||||
return context.createSSLEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLServerSocketFactory getServerSocketFactory() {
|
||||
return context.getServerSocketFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLParameters getSupportedSSLParameters() {
|
||||
return context.getSupportedSSLParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(String alias) {
|
||||
X509Certificate[] result = null;
|
||||
if (kms != null) {
|
||||
for (int i = 0; i < kms.length && result == null; i++) {
|
||||
if (kms[i] instanceof X509KeyManager) {
|
||||
result = ((X509KeyManager) kms[i]).getCertificateChain(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
Set<X509Certificate> certs = new HashSet<>();
|
||||
if (tms != null) {
|
||||
for (TrustManager tm : tms) {
|
||||
if (tm instanceof X509TrustManager) {
|
||||
X509Certificate[] accepted = ((X509TrustManager) tm).getAcceptedIssuers();
|
||||
if (accepted != null) {
|
||||
for (X509Certificate c : accepted) {
|
||||
certs.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return certs.toArray(new X509Certificate[certs.size()]);
|
||||
}
|
||||
}
|
||||
191
java/org/apache/tomcat/util/net/jsse/JSSESupport.java
Normal file
191
java/org/apache/tomcat/util/net/jsse/JSSESupport.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.jsse;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.net.SSLSessionManager;
|
||||
import org.apache.tomcat.util.net.SSLSupport;
|
||||
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/** JSSESupport
|
||||
|
||||
Concrete implementation class for JSSE
|
||||
Support classes.
|
||||
|
||||
This will only work with JDK 1.2 and up since it
|
||||
depends on JDK 1.2's certificate support
|
||||
|
||||
@author EKR
|
||||
@author Craig R. McClanahan
|
||||
Parts cribbed from JSSECertCompat
|
||||
Parts cribbed from CertificatesValve
|
||||
*/
|
||||
public class JSSESupport implements SSLSupport, SSLSessionManager {
|
||||
|
||||
private static final Log log = LogFactory.getLog(JSSESupport.class);
|
||||
|
||||
private static final StringManager sm = StringManager.getManager(JSSESupport.class);
|
||||
|
||||
private static final Map<String,Integer> keySizeCache = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (Cipher cipher : Cipher.values()) {
|
||||
for (String jsseName : cipher.getJsseNames()) {
|
||||
keySizeCache.put(jsseName, Integer.valueOf(cipher.getStrength_bits()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NO-OP method provided to make it easy for other classes in this package
|
||||
* to trigger the loading of this class and the population of the
|
||||
* keySizeCache.
|
||||
*/
|
||||
static void init() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
private SSLSession session;
|
||||
|
||||
|
||||
public JSSESupport(SSLSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCipherSuite() throws IOException {
|
||||
// Look up the current SSLSession
|
||||
if (session == null)
|
||||
return null;
|
||||
return session.getCipherSuite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.security.cert.X509Certificate[] getPeerCertificateChain() throws IOException {
|
||||
// Look up the current SSLSession
|
||||
if (session == null)
|
||||
return null;
|
||||
|
||||
Certificate [] certs=null;
|
||||
try {
|
||||
certs = session.getPeerCertificates();
|
||||
} catch( Throwable t ) {
|
||||
log.debug(sm.getString("jsseSupport.clientCertError"), t);
|
||||
return null;
|
||||
}
|
||||
if( certs==null ) return null;
|
||||
|
||||
java.security.cert.X509Certificate [] x509Certs =
|
||||
new java.security.cert.X509Certificate[certs.length];
|
||||
for(int i=0; i < certs.length; i++) {
|
||||
if (certs[i] instanceof java.security.cert.X509Certificate ) {
|
||||
// always currently true with the JSSE 1.1.x
|
||||
x509Certs[i] = (java.security.cert.X509Certificate) certs[i];
|
||||
} else {
|
||||
try {
|
||||
byte [] buffer = certs[i].getEncoded();
|
||||
CertificateFactory cf =
|
||||
CertificateFactory.getInstance("X.509");
|
||||
ByteArrayInputStream stream =
|
||||
new ByteArrayInputStream(buffer);
|
||||
x509Certs[i] = (java.security.cert.X509Certificate)
|
||||
cf.generateCertificate(stream);
|
||||
} catch(Exception ex) {
|
||||
log.info(sm.getString(
|
||||
"jsseSupport.certTranslationError", certs[i]), ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if(log.isTraceEnabled())
|
||||
log.trace("Cert #" + i + " = " + x509Certs[i]);
|
||||
}
|
||||
if(x509Certs.length < 1)
|
||||
return null;
|
||||
return x509Certs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* This returns the effective bits for the current cipher suite.
|
||||
*/
|
||||
@Override
|
||||
public Integer getKeySize() throws IOException {
|
||||
// Look up the current SSLSession
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return keySizeCache.get(session.getCipherSuite());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSessionId()
|
||||
throws IOException {
|
||||
// Look up the current SSLSession
|
||||
if (session == null)
|
||||
return null;
|
||||
// Expose ssl_session (getId)
|
||||
byte [] ssl_session = session.getId();
|
||||
if ( ssl_session == null)
|
||||
return null;
|
||||
StringBuilder buf=new StringBuilder();
|
||||
for(int x=0; x<ssl_session.length; x++) {
|
||||
String digit=Integer.toHexString(ssl_session[x]);
|
||||
if (digit.length()<2) buf.append('0');
|
||||
if (digit.length()>2) digit=digit.substring(digit.length()-2);
|
||||
buf.append(digit);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
public void setSession(SSLSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invalidate the session this support object is associated with.
|
||||
*/
|
||||
@Override
|
||||
public void invalidateSession() {
|
||||
session.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() throws IOException {
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
return session.getProtocol();
|
||||
}
|
||||
}
|
||||
|
||||
147
java/org/apache/tomcat/util/net/jsse/JSSEUtil.java
Normal file
147
java/org/apache/tomcat/util/net/jsse/JSSEUtil.java
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.jsse;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.compat.JreVendor;
|
||||
import org.apache.tomcat.util.net.Constants;
|
||||
import org.apache.tomcat.util.net.SSLContext;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
|
||||
import org.apache.tomcat.util.net.SSLUtilBase;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* SSLUtil implementation for JSSE.
|
||||
*
|
||||
* @author Harish Prabandham
|
||||
* @author Costin Manolache
|
||||
* @author Stefan Freyr Stefansson
|
||||
* @author EKR
|
||||
* @author Jan Luehe
|
||||
*/
|
||||
public class JSSEUtil extends SSLUtilBase {
|
||||
|
||||
private static final Log log = LogFactory.getLog(JSSEUtil.class);
|
||||
private static final StringManager sm = StringManager.getManager(JSSEUtil.class);
|
||||
|
||||
private static final Set<String> implementedProtocols;
|
||||
private static final Set<String> implementedCiphers;
|
||||
|
||||
static {
|
||||
SSLContext context;
|
||||
try {
|
||||
context = new JSSESSLContext(Constants.SSL_PROTO_TLS);
|
||||
context.init(null, null, null);
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
// This is fatal for the connector so throw an exception to prevent
|
||||
// it from starting
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
String[] implementedProtocolsArray = context.getSupportedSSLParameters().getProtocols();
|
||||
implementedProtocols = new HashSet<>(implementedProtocolsArray.length);
|
||||
|
||||
// Filter out SSLv2 from the list of implemented protocols (just in case
|
||||
// we are running on a JVM that supports it) since it is no longer
|
||||
// considered secure but allow SSLv2Hello.
|
||||
// Note SSLv3 is allowed despite known insecurities because some users
|
||||
// still have a requirement for it.
|
||||
for (String protocol : implementedProtocolsArray) {
|
||||
String protocolUpper = protocol.toUpperCase(Locale.ENGLISH);
|
||||
if (!"SSLV2HELLO".equals(protocolUpper) && !"SSLV3".equals(protocolUpper)) {
|
||||
if (protocolUpper.contains("SSL")) {
|
||||
log.debug(sm.getString("jsse.excludeProtocol", protocol));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
implementedProtocols.add(protocol);
|
||||
}
|
||||
|
||||
if (implementedProtocols.size() == 0) {
|
||||
log.warn(sm.getString("jsse.noDefaultProtocols"));
|
||||
}
|
||||
|
||||
String[] implementedCipherSuiteArray = context.getSupportedSSLParameters().getCipherSuites();
|
||||
// The IBM JRE will accept cipher suites names SSL_xxx or TLS_xxx but
|
||||
// only returns the SSL_xxx form for supported cipher suites. Therefore
|
||||
// need to filter the requested cipher suites using both forms with an
|
||||
// IBM JRE.
|
||||
if (JreVendor.IS_IBM_JVM) {
|
||||
implementedCiphers = new HashSet<>(implementedCipherSuiteArray.length * 2);
|
||||
for (String name : implementedCipherSuiteArray) {
|
||||
implementedCiphers.add(name);
|
||||
if (name.startsWith("SSL")) {
|
||||
implementedCiphers.add("TLS" + name.substring(3));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
implementedCiphers = new HashSet<>(implementedCipherSuiteArray.length);
|
||||
implementedCiphers.addAll(Arrays.asList(implementedCipherSuiteArray));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public JSSEUtil (SSLHostConfigCertificate certificate) {
|
||||
this(certificate, true);
|
||||
}
|
||||
|
||||
|
||||
public JSSEUtil (SSLHostConfigCertificate certificate, boolean warnOnSkip) {
|
||||
super(certificate, warnOnSkip);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Log getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Set<String> getImplementedProtocols() {
|
||||
return implementedProtocols;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Set<String> getImplementedCiphers() {
|
||||
return implementedCiphers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean isTls13RenegAuthAvailable() {
|
||||
// TLS 1.3 does not support authentication after the initial handshake
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SSLContext createSSLContextInternal(List<String> negotiableProtocols)
|
||||
throws NoSuchAlgorithmException {
|
||||
return new JSSESSLContext(sslHostConfig.getSslProtocol());
|
||||
}
|
||||
}
|
||||
35
java/org/apache/tomcat/util/net/jsse/LocalStrings.properties
Normal file
35
java/org/apache/tomcat/util/net/jsse/LocalStrings.properties
Normal file
@@ -0,0 +1,35 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
jsse.alias_no_key_entry=Alias name [{0}] does not identify a key entry
|
||||
jsse.excludeProtocol=The SSL protocol [{0}] which is supported in this JRE was excluded from the protocols available to Tomcat
|
||||
jsse.invalidTrustManagerClassName=The trustManagerClassName provided [{0}] does not implement javax.net.ssl.TrustManager
|
||||
jsse.noCertFile=SSLHostConfig attribute certificateFile must be defined when using an SSL connector
|
||||
jsse.noDefaultProtocols=Unable to determine a default for sslEnabledProtocols. Set an explicit value to ensure the connector can start.
|
||||
jsse.noKeys=No aliases for private keys found in key store
|
||||
jsse.openssl.effectiveCiphers=Ciphers used: [{0}]
|
||||
jsse.openssl.unknownElement=Unknown element in cipher string: [{0}]
|
||||
jsse.pemParseError=Unable to parse the key from [{0}]
|
||||
|
||||
jsseSupport.certTranslationError=Error translating certificate [{0}]
|
||||
jsseSupport.clientCertError=Error trying to obtain a certificate from the client
|
||||
|
||||
jsseUtil.noCrlSupport=The truststoreProvider [{0}] does not support the certificateRevocationFile configuration option
|
||||
jsseUtil.noVerificationDepth=The truststoreProvider [{0}] does not support the certificateVerificationDepth configuration option
|
||||
jsseUtil.trustedCertNotChecked=The validity dates of the trusted certificate with alias [{0}] were not checked as the certificate was of an unknown type
|
||||
jsseUtil.trustedCertNotValid=The trusted certificate with alias [{0}] and DN [{1}] is not valid due to [{2}]. Certificates signed by this trusted certificate WILL be accepted
|
||||
|
||||
pemFile.noMultiPrimes=The PKCS#1 certificate is in multi-prime format and Java does not provide an API for constructing an RSA private key object from that format
|
||||
pemFile.notValidRFC5915=The provided key file does not conform to RFC 5915
|
||||
@@ -0,0 +1,23 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
jsse.openssl.effectiveCiphers=Verwendete Ciphers: [{0}]
|
||||
jsse.pemParseError=Der Schlüssel konnte nicht aus [{0}] geparst werden.
|
||||
|
||||
jsseSupport.certTranslationError=Fehler beim Übersetzen des Zertifikates [{0}]
|
||||
jsseSupport.clientCertError=Fehler beim Versuch ein Zertifikat vom Client zu erhalten.
|
||||
|
||||
jsseUtil.noVerificationDepth=Der truststoreProvider [{0}] unterstützt nicht die Option certificateVerificationDepth
|
||||
jsseUtil.trustedCertNotValid=Das vertrauenswürdige Zertifikat mit alias [{0}] und DN [{1}] ist auf Grund von [{2}] nicht gültig. Zertifikate die von diesem signiert worden sind WERDEN akzeptiert.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
jsse.alias_no_key_entry=El nombre de Alias [{0}] no identifica una entrada de clave
|
||||
jsse.invalidTrustManagerClassName=El trustManagerClassName suministrado [{0}] no implementa javax.net.ssl.TrustManager
|
||||
jsse.openssl.effectiveCiphers=Cifradores usados: [{0}]
|
||||
jsse.pemParseError=Imposible parsear la clave desde [{0}]
|
||||
|
||||
jsseSupport.clientCertError=Error tratando de obtener un certificado desde el cliente
|
||||
|
||||
jsseUtil.trustedCertNotValid=El certificado confiable con alias [{0}] y DN [{1}] no es válido debido a [{2}]. Los certificados firmados por este certificados confiable SERAN aceptados\n
|
||||
@@ -0,0 +1,34 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
jsse.alias_no_key_entry=Le nom alias [{0}] n''identifie pas une entrée de clé
|
||||
jsse.excludeProtocol=Le protocole SSL [{0}] qui est supporté par ce JRE a été exclu des protocoles disponibles dans Tomcat
|
||||
jsse.invalidTrustManagerClassName=Le trustManagerClassName fourni [{0}] n''implémente pas javax.net.ssl.TrustManager
|
||||
jsse.noCertFile=L'attribut certificateFile de SSLHostConfig doit être défini lorsqu'un connecteur SSL est utilisé
|
||||
jsse.noDefaultProtocols=Impossible de déterminer un défaut pour sslEnabledProtocols de [{0}], indiquez une valeur explicite pour permettre le démarrage du connecteur
|
||||
jsse.noKeys=Aucun alias pour les clés privées n'a été trouvé dans la base de clés
|
||||
jsse.openssl.effectiveCiphers=Chiffres utilisés: [{0}]
|
||||
jsse.openssl.unknownElement=Elément inconnu dans la chaîne de chiffres: [{0}]
|
||||
jsse.pemParseError=Impossible de parser la clé de [{0}]
|
||||
|
||||
jsseSupport.certTranslationError=Erreur lors de la traduction du certificat [{0}]
|
||||
jsseSupport.clientCertError=Echec de l'obtention d'un certificat de la part du client
|
||||
|
||||
jsseUtil.noCrlSupport=Le truststoreProvider [{0}] ne supporte pas d''option de configuration certificateRevocationFile
|
||||
jsseUtil.noVerificationDepth=Le truststoreProvider [{0}] ne supporte pas l''option de configuration certificateVerificationDepth
|
||||
jsseUtil.trustedCertNotChecked=Les dates de validité du certificat de confiance dont l''alias est [{0}] n''ont pas été vérifiées car sont type est inconnu
|
||||
jsseUtil.trustedCertNotValid=Le certificat de confiance avec l''alias [{0}] et le DN [{1}] n''est pas valide à cause de [{2}], les certificats signés par ce certificat de confiance SERONT acceptés
|
||||
|
||||
pemFile.noMultiPrimes=Le certificat PKCS#1 est dans un format mutli-prime et Java ne fournit pas d'API pour construire une clé privée RSA à partir de ce format
|
||||
@@ -0,0 +1,32 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
jsse.alias_no_key_entry=別名 [{0}] はキーエントリを発見できません
|
||||
jsse.excludeProtocol=JRE は SSL プロトコル [{0}] に対応しています。しかし Tomcat の利用可能プロトコルからは除外されています。
|
||||
jsse.invalidTrustManagerClassName=[{0}]が提供するtrustManagerClassNameはjavax.net.ssl.TrustManagerを実装していません。
|
||||
jsse.noCertFile=SSLコネクタを使用する場合は、SSLHostConfigのcertificateFile属性を定義する必要があります。
|
||||
jsse.noDefaultProtocols=sslEnableProtocols の初期値を取得できません。コネクターを開始できるよう明示的に値を設定してください。
|
||||
jsse.noKeys=キーストアで見つかった秘密キーのエイリアスがありません。
|
||||
jsse.openssl.effectiveCiphers=使用された暗号:[{0}]
|
||||
jsse.openssl.unknownElement=暗号文字列の不明な要素:[{0}]
|
||||
jsse.pemParseError=秘密鍵ファイル [{0}] を解析できませんでした。
|
||||
|
||||
jsseSupport.certTranslationError=証明書の翻訳中にエラーが発生しました[{0}]
|
||||
jsseSupport.clientCertError=クライアントから証明書を取得できません。
|
||||
|
||||
jsseUtil.noCrlSupport=トラストストアプロバイダー [{0}] は設定項目 certificateRevocationFile に対応していません。
|
||||
jsseUtil.noVerificationDepth=トラストストアプロバイダー [{0}] は設定項目 certificateVerificationDepth に未対応です。
|
||||
jsseUtil.trustedCertNotChecked=エイリアス[{0}]を持つ信頼できる証明書の有効期限は、証明書が不明な型であるためチェックされませんでした。
|
||||
jsseUtil.trustedCertNotValid=エイリアス[{0}]とDN [{1}]を持つ信頼できる証明書が[{2}]のために無効です。 この信頼できる証明書で署名された証明書が受け入れられるでしょう
|
||||
@@ -0,0 +1,34 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
jsse.alias_no_key_entry=별칭 이름 [{0}]을(를) 사용하여 키 엔트리를 식별해낼 수 없습니다.
|
||||
jsse.excludeProtocol=이 JRE에서 지원되는 해당 SSL 프로토콜 [{0}]이(가), Tomcat의 가용 프로토콜 목록에서 제외되어 있습니다.
|
||||
jsse.invalidTrustManagerClassName=trustManagerClassName에 의해 제공된 클래스 [{0}]은(는) javax.net.ssl.TrustManager를 구현하지 않았습니다.
|
||||
jsse.noCertFile=SSLHostConfig의 속성인 certificateFile은, 반드시 SSL connector를 사용할 때에만 정의되어야 합니다.
|
||||
jsse.noDefaultProtocols=sslEnabledProtocols의 기본값을 결정할 수 없습니다. Connector가 제대로 시작되는지 보증하려면 명시적으로 값을 설정하십시오.
|
||||
jsse.noKeys=개인 키들에 대한 별칭들이 키 저장소에 없습니다.
|
||||
jsse.openssl.effectiveCiphers=사용되는 Cipher들: [{0}]
|
||||
jsse.openssl.unknownElement=Cipher 문자열에 알 수 없는 엘리먼트: [{0}]
|
||||
jsse.pemParseError=[{0}](으)로부터 키를 파싱할 수 없습니다.
|
||||
|
||||
jsseSupport.certTranslationError=인증서 [{0}]에 대한 인증서 변환을 하는 중 오류 발생
|
||||
jsseSupport.clientCertError=클라이언트로부터 인증서를 구하려 시도하는 중 오류 발생
|
||||
|
||||
jsseUtil.noCrlSupport=truststoreProvider [{0}]은(는) certificateRevocationFile 설정 옵션을 지원하지 않습니다.
|
||||
jsseUtil.noVerificationDepth=truststoreProvider [{0}]은(는) certificateVerificationDepth 설정 옵션을 지원하지 않습니다.
|
||||
jsseUtil.trustedCertNotChecked=인증서가 알 수 없는 타입이라서, 별칭이 [{0}]인 신뢰되는 인증서의 유효일자들이 점검되지 않았습니다.
|
||||
jsseUtil.trustedCertNotValid=별칭이 [{0}](이)고 DN이 [{1}]인 해당 신뢰받는 인증서는 [{2}](으)로 인하여 유효하지 않습니다. 이 신뢰되는 인증서에 의해 서명된 인증서들은 받아들여질 것입니다.
|
||||
|
||||
pemFile.noMultiPrimes=해당 PKCS#1 인증서는 multi-prime 포맷으로 되어 있는데, 자바는 해당 포맷으로부터 RSA 개인 키 객체를 생성할 API를 제공하지 않습니다.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
jsse.pemParseError=Невозможно получить ключ из [{0}]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
jsse.noDefaultProtocols=无法确定sslEnabledProtocols的默认值。设置显式值以确保连接器可以启动。
|
||||
jsse.openssl.effectiveCiphers=使用的密码:[{0}]
|
||||
jsse.pemParseError=无法从 [{0}] 解析 key
|
||||
|
||||
jsseSupport.certTranslationError=错误的转换证书[{0}]
|
||||
jsseSupport.clientCertError=尝试从客户端获取证书时出错
|
||||
|
||||
jsseUtil.trustedCertNotValid=由于[{2}],别名为[{0}]且DN [{1}]的可信证书无效。 将接受由此可信证书签署的证书
|
||||
302
java/org/apache/tomcat/util/net/jsse/PEMFile.java
Normal file
302
java/org/apache/tomcat/util/net/jsse/PEMFile.java
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.jsse;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.RSAPrivateCrtKeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.EncryptedPrivateKeyInfo;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
|
||||
import org.apache.tomcat.util.buf.Asn1Parser;
|
||||
import org.apache.tomcat.util.buf.Asn1Writer;
|
||||
import org.apache.tomcat.util.codec.binary.Base64;
|
||||
import org.apache.tomcat.util.file.ConfigFileLoader;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* RFC 1421 PEM file containing X509 certificates or private keys (PKCS#8 only,
|
||||
* i.e. with boundaries containing "BEGIN PRIVATE KEY" or "BEGIN ENCRYPTED PRIVATE KEY",
|
||||
* not "BEGIN RSA PRIVATE KEY" or other variations).
|
||||
*/
|
||||
public class PEMFile {
|
||||
|
||||
private static final StringManager sm = StringManager.getManager(PEMFile.class);
|
||||
|
||||
private static final byte[] OID_EC_PUBLIC_KEY =
|
||||
new byte[] { 0x06, 0x07, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 0x02, 0x01 };
|
||||
|
||||
private String filename;
|
||||
private List<X509Certificate> certificates = new ArrayList<>();
|
||||
private PrivateKey privateKey;
|
||||
|
||||
public List<X509Certificate> getCertificates() {
|
||||
return certificates;
|
||||
}
|
||||
|
||||
public PrivateKey getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
public PEMFile(String filename) throws IOException, GeneralSecurityException {
|
||||
this(filename, null);
|
||||
}
|
||||
|
||||
public PEMFile(String filename, String password) throws IOException, GeneralSecurityException {
|
||||
this(filename, password, null);
|
||||
}
|
||||
|
||||
public PEMFile(String filename, String password, String keyAlgorithm)
|
||||
throws IOException, GeneralSecurityException {
|
||||
this.filename = filename;
|
||||
|
||||
List<Part> parts = new ArrayList<>();
|
||||
try (InputStream inputStream = ConfigFileLoader.getInputStream(filename)) {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.US_ASCII));
|
||||
Part part = null;
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith(Part.BEGIN_BOUNDARY)) {
|
||||
part = new Part();
|
||||
part.type = line.substring(Part.BEGIN_BOUNDARY.length(), line.length() - 5).trim();
|
||||
} else if (line.startsWith(Part.END_BOUNDARY)) {
|
||||
parts.add(part);
|
||||
part = null;
|
||||
} else if (part != null && !line.contains(":") && !line.startsWith(" ")) {
|
||||
part.content += line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Part part : parts) {
|
||||
switch (part.type) {
|
||||
case "PRIVATE KEY":
|
||||
privateKey = part.toPrivateKey(null, keyAlgorithm, Format.PKCS8);
|
||||
break;
|
||||
case "EC PRIVATE KEY":
|
||||
privateKey = part.toPrivateKey(null, "EC", Format.RFC5915);
|
||||
break;
|
||||
case "ENCRYPTED PRIVATE KEY":
|
||||
privateKey = part.toPrivateKey(password, keyAlgorithm, Format.PKCS8);
|
||||
break;
|
||||
case "RSA PRIVATE KEY":
|
||||
privateKey = part.toPrivateKey(null, keyAlgorithm, Format.PKCS1);
|
||||
break;
|
||||
case "CERTIFICATE":
|
||||
case "X509 CERTIFICATE":
|
||||
certificates.add(part.toCertificate());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Part {
|
||||
public static final String BEGIN_BOUNDARY = "-----BEGIN ";
|
||||
public static final String END_BOUNDARY = "-----END ";
|
||||
|
||||
public String type;
|
||||
public String content = "";
|
||||
|
||||
private byte[] decode() {
|
||||
return Base64.decodeBase64(content);
|
||||
}
|
||||
|
||||
public X509Certificate toCertificate() throws CertificateException {
|
||||
CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(decode()));
|
||||
}
|
||||
|
||||
public PrivateKey toPrivateKey(String password, String keyAlgorithm, Format format)
|
||||
throws GeneralSecurityException, IOException {
|
||||
KeySpec keySpec = null;
|
||||
|
||||
if (password == null) {
|
||||
switch (format) {
|
||||
case PKCS1: {
|
||||
keySpec = parsePKCS1(decode());
|
||||
break;
|
||||
}
|
||||
case PKCS8: {
|
||||
keySpec = new PKCS8EncodedKeySpec(decode());
|
||||
break;
|
||||
}
|
||||
case RFC5915: {
|
||||
keySpec = new PKCS8EncodedKeySpec(rfc5915ToPkcs8(decode()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EncryptedPrivateKeyInfo privateKeyInfo = new EncryptedPrivateKeyInfo(decode());
|
||||
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(privateKeyInfo.getAlgName());
|
||||
SecretKey secretKey = secretKeyFactory.generateSecret(new PBEKeySpec(password.toCharArray()));
|
||||
|
||||
Cipher cipher = Cipher.getInstance(privateKeyInfo.getAlgName());
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, privateKeyInfo.getAlgParameters());
|
||||
|
||||
keySpec = privateKeyInfo.getKeySpec(cipher);
|
||||
}
|
||||
|
||||
InvalidKeyException exception = new InvalidKeyException(sm.getString("jsse.pemParseError", filename));
|
||||
if (keyAlgorithm == null) {
|
||||
for (String algorithm : new String[] {"RSA", "DSA", "EC"}) {
|
||||
try {
|
||||
return KeyFactory.getInstance(algorithm).generatePrivate(keySpec);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
exception.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return KeyFactory.getInstance(keyAlgorithm).generatePrivate(keySpec);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
exception.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
|
||||
throw exception;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RFC5915: SEQ
|
||||
* INT value = 1
|
||||
* OCTET STRING len = 32 bytes
|
||||
* [0]
|
||||
* OID named EC
|
||||
* [1]
|
||||
* BIT STRING len = 520 bits
|
||||
*
|
||||
* PKCS8: SEQ
|
||||
* INT value = 0
|
||||
* SEQ
|
||||
* OID 1.2.840.10045.2.1 (EC public key)
|
||||
* OID named EC
|
||||
* OCTET STRING
|
||||
* SEQ
|
||||
* INT value = 1
|
||||
* OCTET STRING len = 32 bytes
|
||||
* [1]
|
||||
* BIT STRING len = 520 bits
|
||||
*
|
||||
*/
|
||||
private byte[] rfc5915ToPkcs8(byte[] source) {
|
||||
// Parse RFC 5915 format EC private key
|
||||
Asn1Parser p = new Asn1Parser(source);
|
||||
|
||||
// Type (sequence)
|
||||
p.parseTag(0x30);
|
||||
// Length
|
||||
p.parseFullLength();
|
||||
|
||||
// Version
|
||||
BigInteger version = p.parseInt();
|
||||
if (version.intValue() != 1) {
|
||||
throw new IllegalArgumentException(sm.getString("pemFile.notValidRFC5915"));
|
||||
}
|
||||
|
||||
// Private key
|
||||
p.parseTag(0x04);
|
||||
int privateKeyLen = p.parseLength();
|
||||
byte[] privateKey = new byte[privateKeyLen];
|
||||
p.parseBytes(privateKey);
|
||||
|
||||
// [0] OID
|
||||
p.parseTag(0xA0);
|
||||
int oidLen = p.parseLength();
|
||||
byte[] oid = new byte[oidLen];
|
||||
p.parseBytes(oid);
|
||||
if (oid[0] != 0x06) {
|
||||
throw new IllegalArgumentException(sm.getString("pemFile.notValidRFC5915"));
|
||||
}
|
||||
|
||||
// [1] Public key
|
||||
p.parseTag(0xA1);
|
||||
int publicKeyLen = p.parseLength();
|
||||
byte[] publicKey = new byte[publicKeyLen];
|
||||
p.parseBytes(publicKey);
|
||||
if (publicKey[0] != 0x03) {
|
||||
throw new IllegalArgumentException(sm.getString("pemFile.notValidRFC5915"));
|
||||
}
|
||||
|
||||
|
||||
// Write out PKCS#8 format
|
||||
return Asn1Writer.writeSequence(
|
||||
Asn1Writer.writeInteger(0),
|
||||
Asn1Writer.writeSequence(
|
||||
OID_EC_PUBLIC_KEY,
|
||||
oid),
|
||||
Asn1Writer.writeOctetString(
|
||||
Asn1Writer.writeSequence(
|
||||
Asn1Writer.writeInteger(1),
|
||||
Asn1Writer.writeOctetString(privateKey),
|
||||
Asn1Writer.writeTag((byte) 0xA1, publicKey))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private RSAPrivateCrtKeySpec parsePKCS1(byte[] source) {
|
||||
Asn1Parser p = new Asn1Parser(source);
|
||||
|
||||
// https://en.wikipedia.org/wiki/X.690#BER_encoding
|
||||
// https://tools.ietf.org/html/rfc8017#page-55
|
||||
|
||||
// Type (sequence)
|
||||
p.parseTag(0x30);
|
||||
// Length
|
||||
p.parseFullLength();
|
||||
|
||||
BigInteger version = p.parseInt();
|
||||
if (version.intValue() == 1) {
|
||||
// JRE doesn't provide a suitable constructor for multi-prime
|
||||
// keys
|
||||
throw new IllegalArgumentException(sm.getString("pemFile.noMultiPrimes"));
|
||||
}
|
||||
return new RSAPrivateCrtKeySpec(p.parseInt(), p.parseInt(), p.parseInt(), p.parseInt(),
|
||||
p.parseInt(), p.parseInt(), p.parseInt(), p.parseInt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private enum Format {
|
||||
PKCS1,
|
||||
PKCS8,
|
||||
RFC5915
|
||||
}
|
||||
}
|
||||
675
java/org/apache/tomcat/util/net/mbeans-descriptors.xml
Normal file
675
java/org/apache/tomcat/util/net/mbeans-descriptors.xml
Normal file
@@ -0,0 +1,675 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<mbeans-descriptors>
|
||||
|
||||
<mbean name="NioEndpoint"
|
||||
className="org.apache.catalina.mbeans.ClassNameMBean"
|
||||
domain="Catalina"
|
||||
group="ThreadPool"
|
||||
type="org.apache.tomcat.util.net.NioEndpoint">
|
||||
|
||||
<attribute name="acceptCount"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="acceptorThreadCount"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="acceptorThreadPriority"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="alpnSupported"
|
||||
type="boolean"
|
||||
writeable="false"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="bindOnInit"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="connectionCount"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="connectionLinger"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="connectionTimeout"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="currentThreadCount"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="currentThreadsBusy"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="daemon"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="defaultSSLHostConfigName"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="deferAccept"
|
||||
type="boolean"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="domain"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="executorTerminationTimeoutMillis"
|
||||
type="long"/>
|
||||
|
||||
<attribute name="keepAliveCount"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="keepAliveTimeout"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="localPort"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="maxConnections"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="maxKeepAliveRequests"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="maxThreads"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="minSpareThreads"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="modelerType"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="name"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="paused"
|
||||
type="boolean"
|
||||
writeable="false"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="pollerThreadCount"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="pollerThreadPriority"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="port"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="running"
|
||||
type="boolean"
|
||||
writeable="false"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="sSLEnabled"
|
||||
type="boolean"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="selectorTimeout"
|
||||
type="long"/>
|
||||
|
||||
<attribute name="sniParseLimit"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="sslImplementation"
|
||||
type="org.apache.tomcat.util.net.SSLImplementation"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="sslImplementationName"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="tcpNoDelay"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="threadPriority"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="useInheritedChannel"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="useSendfile"
|
||||
type="boolean"/>
|
||||
|
||||
<operation name="addNegotiatedProtocol"
|
||||
returnType="void">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="bind"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="closeServerSocketGraceful"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="createExecutor"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="destroy"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="findSslHostConfigs"
|
||||
returnType="[Lorg.apache.tomcat.util.net.SSLHostConfig;"/>
|
||||
|
||||
<operation name="getAttribute"
|
||||
returnType="java.lang.Object">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="getProperty"
|
||||
returnType="java.lang.String">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="hasNegotiableProtocols"
|
||||
returnType="boolean"/>
|
||||
|
||||
<operation name="init"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="pause"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="reloadSslHostConfig"
|
||||
returnType="void">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="reloadSslHostConfigs"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="removeSslHostConfig"
|
||||
returnType="org.apache.tomcat.util.net.SSLHostConfig">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="resume"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="setProperty"
|
||||
returnType="boolean">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
<parameter name="param1"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="shutdownExecutor"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="start"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="startInternal"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="stop"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="stopInternal"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="unbind"
|
||||
returnType="void"/>
|
||||
|
||||
</mbean>
|
||||
|
||||
<mbean name="Nio2Endpoint"
|
||||
className="org.apache.catalina.mbeans.ClassNameMBean"
|
||||
domain="Catalina"
|
||||
group="ThreadPool"
|
||||
type="org.apache.tomcat.util.net.Nio2Endpoint">
|
||||
|
||||
<attribute name="acceptCount"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="acceptorThreadCount"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="acceptorThreadPriority"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="alpnSupported"
|
||||
type="boolean"
|
||||
writeable="false"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="bindOnInit"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="connectionCount"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="connectionLinger"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="connectionTimeout"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="currentThreadCount"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="currentThreadsBusy"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="daemon"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="defaultSSLHostConfigName"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="deferAccept"
|
||||
type="boolean"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="domain"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="executorTerminationTimeoutMillis"
|
||||
type="long"/>
|
||||
|
||||
<attribute name="keepAliveCount"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="keepAliveTimeout"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="localPort"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="maxConnections"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="maxKeepAliveRequests"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="maxThreads"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="minSpareThreads"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="modelerType"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="name"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="paused"
|
||||
type="boolean"
|
||||
writeable="false"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="port"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="running"
|
||||
type="boolean"
|
||||
writeable="false"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="sSLEnabled"
|
||||
type="boolean"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="sniParseLimit"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="sslImplementation"
|
||||
type="org.apache.tomcat.util.net.SSLImplementation"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="sslImplementationName"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="tcpNoDelay"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="threadPriority"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="useSendfile"
|
||||
type="boolean"/>
|
||||
|
||||
<operation name="addNegotiatedProtocol"
|
||||
returnType="void">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="bind"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="closeServerSocketGraceful"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="createExecutor"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="destroy"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="findSslHostConfigs"
|
||||
returnType="[Lorg.apache.tomcat.util.net.SSLHostConfig;"/>
|
||||
|
||||
<operation name="getAttribute"
|
||||
returnType="java.lang.Object">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="getProperty"
|
||||
returnType="java.lang.String">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="hasNegotiableProtocols"
|
||||
returnType="boolean"/>
|
||||
|
||||
<operation name="init"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="pause"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="reloadSslHostConfig"
|
||||
returnType="void">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="reloadSslHostConfigs"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="removeSslHostConfig"
|
||||
returnType="org.apache.tomcat.util.net.SSLHostConfig">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="resume"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="setProperty"
|
||||
returnType="boolean">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
<parameter name="param1"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="shutdownExecutor"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="start"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="startInternal"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="stop"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="stopInternal"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="unbind"
|
||||
returnType="void"/>
|
||||
|
||||
</mbean>
|
||||
|
||||
<mbean name="AprEndpoint"
|
||||
className="org.apache.catalina.mbeans.ClassNameMBean"
|
||||
domain="Catalina"
|
||||
group="ThreadPool"
|
||||
type="org.apache.tomcat.util.net.AprEndpoint">
|
||||
|
||||
<attribute name="acceptCount"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="acceptorThreadCount"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="acceptorThreadPriority"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="alpnSupported"
|
||||
type="boolean"
|
||||
writeable="false"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="bindOnInit"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="connectionCount"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="connectionLinger"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="connectionTimeout"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="currentThreadCount"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="currentThreadsBusy"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="daemon"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="defaultSSLHostConfigName"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="deferAccept"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="domain"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="executorTerminationTimeoutMillis"
|
||||
type="long"/>
|
||||
|
||||
<attribute name="ipv6v6only"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="keepAliveCount"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="keepAliveTimeout"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="localPort"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="maxConnections"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="maxKeepAliveRequests"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="maxThreads"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="minSpareThreads"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="modelerType"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="name"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="paused"
|
||||
type="boolean"
|
||||
writeable="false"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="pollTime"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="port"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="running"
|
||||
type="boolean"
|
||||
writeable="false"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="sSLEnabled"
|
||||
type="boolean"
|
||||
is="true"/>
|
||||
|
||||
<attribute name="sendfileCount"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="sendfileSize"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="tcpNoDelay"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="threadPriority"
|
||||
type="int"/>
|
||||
|
||||
<attribute name="useSendfile"
|
||||
type="boolean"/>
|
||||
|
||||
<operation name="addNegotiatedProtocol"
|
||||
returnType="void">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="bind"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="closeServerSocketGraceful"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="createExecutor"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="destroy"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="findSslHostConfigs"
|
||||
returnType="[Lorg.apache.tomcat.util.net.SSLHostConfig;"/>
|
||||
|
||||
<operation name="getAttribute"
|
||||
returnType="java.lang.Object">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="getProperty"
|
||||
returnType="java.lang.String">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="getSslContext"
|
||||
returnType="long">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="hasNegotiableProtocols"
|
||||
returnType="boolean"/>
|
||||
|
||||
<operation name="init"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="pause"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="reloadSslHostConfig"
|
||||
returnType="void">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="reloadSslHostConfigs"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="removeSslHostConfig"
|
||||
returnType="org.apache.tomcat.util.net.SSLHostConfig">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="resume"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="setProperty"
|
||||
returnType="boolean">
|
||||
<parameter name="param0"
|
||||
type="java.lang.String"/>
|
||||
<parameter name="param1"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="shutdownExecutor"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="start"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="startInternal"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="stop"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="stopInternal"
|
||||
returnType="void"/>
|
||||
|
||||
<operation name="unbind"
|
||||
returnType="void"/>
|
||||
|
||||
</mbean>
|
||||
|
||||
</mbeans-descriptors>
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
engine.ciphersFailure=Failed getting cipher list
|
||||
engine.emptyCipherSuite=Empty cipher suite
|
||||
engine.engineClosed=Engine is closed
|
||||
engine.failedCipherSuite=Failed to enable cipher suite [{0}]
|
||||
engine.inboundClose=Inbound closed before receiving peer's close_notify
|
||||
engine.invalidBufferArray=offset: [{0}], length: [{1}] (expected: offset <= offset + length <= srcs.length [{2}])
|
||||
engine.noSSLContext=No SSL context
|
||||
engine.noSession=SSL session ID not available
|
||||
engine.nullBuffer=Null buffer
|
||||
engine.nullBufferInArray=Null buffer in array
|
||||
engine.nullCipherSuite=Null cipher suite
|
||||
engine.nullName=Null value name
|
||||
engine.nullValue=Null value
|
||||
engine.openSSLError=OpenSSL error: [{0}] message: [{1}]
|
||||
engine.oversizedPacket=Encrypted packet is oversized
|
||||
engine.unsupportedCipher=Unsupported cipher suite: [{0}] [{1}]
|
||||
engine.unsupportedProtocol=Protocol [{0}] is not supported
|
||||
engine.unverifiedPeer=Peer unverified
|
||||
engine.writeToSSLFailed=Failed writing to SSL, returned: [{0}]
|
||||
|
||||
openssl.X509FactoryError=Error getting X509 factory instance
|
||||
openssl.addedClientCaCert=Added client CA cert: [{0}]
|
||||
openssl.applyConf=Applying OpenSSLConfCmd to SSL context
|
||||
openssl.certificateVerificationFailed=Certificate verification failed
|
||||
openssl.checkConf=Checking OpenSSLConf
|
||||
openssl.doubleInit=SSL context already initialized, ignoring
|
||||
openssl.errApplyConf=Could not apply OpenSSLConf to SSL context
|
||||
openssl.errCheckConf=Error during OpenSSLConf check
|
||||
openssl.errMakeConf=Could not create OpenSSLConf context
|
||||
openssl.errorSSLCtxInit=Error initializing SSL context
|
||||
openssl.keyManagerMissing=No key manager found
|
||||
openssl.makeConf=Creating OpenSSLConf context
|
||||
openssl.nonJsseCertficate=The certificate [{0}] or its private key [{1}] could not be processed using a JSSE key manager and will be given directly to OpenSSL
|
||||
openssl.nonJsseChain=The certificate chain [{0}] was not specified or was not valid and JSSE requires a valid certificate chain so attempting to use OpenSSL directly
|
||||
openssl.trustManagerMissing=No trust manager found
|
||||
|
||||
opensslconf.applyCommand=OpenSSLConf applying command (name [{0}], value [{1}])
|
||||
opensslconf.applyFailed=Failure while applying OpenSSLConf to SSL context
|
||||
opensslconf.checkCommand=OpenSSLConf checking command (name [{0}], value [{1}])
|
||||
opensslconf.checkFailed=Failure while checking OpenSSLConf
|
||||
opensslconf.failedCommand=OpenSSLConf failed command (name [{0}], value [{1}]) with result [{2}] - will be ignored
|
||||
opensslconf.finishFailed=OpenSSLConf finish failed with result [{0}]
|
||||
opensslconf.noCommandName=OpenSSLConf no command name - will be ignored (command value [{0}])
|
||||
opensslconf.resultCommand=OpenSSLConf command (name [{0}], value [{1}]) returned [{2}]
|
||||
|
||||
sessionContext.nullTicketKeys=Null keys
|
||||
@@ -0,0 +1,33 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
engine.ciphersFailure=Fehler beim abfragen der Cipher Liste
|
||||
engine.emptyCipherSuite=leere Cipher-Suite
|
||||
engine.inboundClose=Die eingehende Verbindung wurde vor einer close_notify Nachricht der Gegenstelle geschlossen
|
||||
engine.noSession=SSL Session-ID nicht vorhanden
|
||||
engine.openSSLError=OpenSSL Fehler: [{0}] Nachricht: [{1}]
|
||||
engine.unsupportedProtocol=Protokoll [{0}] ist nicht unterstützt
|
||||
|
||||
openssl.addedClientCaCert=Client CA Zertifikat hinzugefügt: [{0}]
|
||||
openssl.certificateVerificationFailed=Zertifikatsprüfung fehlgeschlagen
|
||||
openssl.errApplyConf=Die OpenSSLConf konnte nicht auf den SSL Context angewandt werden
|
||||
openssl.errCheckConf=Fehler beim Prüfen der OpenSSLConf
|
||||
openssl.errMakeConf=Der OpenSSLConf Context konnte nicht erzeugt werden
|
||||
openssl.errorSSLCtxInit=Fehler beim initialisieren des SSL Contexts
|
||||
openssl.keyManagerMissing=Kein Key-Manager gefunden
|
||||
openssl.trustManagerMissing=Kein Trust-Manager gefunden
|
||||
|
||||
opensslconf.applyFailed=Fehler bei der Anwendung der OpenSSLConf auf den SSL Context
|
||||
opensslconf.checkFailed=Fehler beim Prüfen der OpenSSLConf
|
||||
@@ -0,0 +1,25 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
engine.emptyCipherSuite=Suite de cifrado vacía
|
||||
engine.engineClosed=El notor esta cerrado
|
||||
engine.noSession=El identificador de la sesión SSL no está disponible
|
||||
engine.openSSLError=Error de OpenSSL: [{0}] mensage: [{1}]\n
|
||||
engine.writeToSSLFailed=Fallo al escribir hacia SSL, resultado: [{0}]
|
||||
|
||||
openssl.addedClientCaCert=Ceritifcado CA de cliente adicionado: [{0}]
|
||||
openssl.trustManagerMissing=No se encontró un manejador confiable
|
||||
|
||||
opensslconf.checkFailed=Fallo mientras se chequeaba OpenSSLConf\n
|
||||
@@ -0,0 +1,61 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
engine.ciphersFailure=Echec en essayant d'obtenir la liste des chiffres
|
||||
engine.emptyCipherSuite=La suite de chiffrement (cipher suite) est vide
|
||||
engine.engineClosed=Le moteur a déjà été fermé
|
||||
engine.failedCipherSuite=Impossible d''activer la suite de chiffres [{0}]
|
||||
engine.inboundClose=L'entrée a été fermée avant d'avoir reçu le close_notify du pair
|
||||
engine.invalidBufferArray=offset: [{0}], length: [{1}] (attendu: offset <= offset + length <= srcs.length [{2}])
|
||||
engine.noSSLContext=Pas de contexte SSL
|
||||
engine.noSession=Identificateur de session SSL non disponible
|
||||
engine.nullBuffer=Tampon null
|
||||
engine.nullBufferInArray=Tampon null dans le tableau
|
||||
engine.nullCipherSuite=Suite de chiffres nulle
|
||||
engine.nullName=La valeur du nom est null
|
||||
engine.nullValue=La valeur est null
|
||||
engine.openSSLError=Erreur OpenSSL : [{0}] message : [{1}]
|
||||
engine.oversizedPacket=Le paquet crypté est trop gros
|
||||
engine.unsupportedCipher=Suite de chiffres non supportée: [{0}] [{1}]
|
||||
engine.unsupportedProtocol=Le protocole [{0}] n''est pas supporté
|
||||
engine.unverifiedPeer=Le pair n'est pas vérifié
|
||||
engine.writeToSSLFailed=Echec d''écriture vers SSL, code de retour: [{0}]
|
||||
|
||||
openssl.X509FactoryError=Impossible d'obtenir l'instance de la fabrique X509
|
||||
openssl.addedClientCaCert=Ajout du certificat CA du client: [{0}]
|
||||
openssl.applyConf=Application de OpenSSLConfCmd au contexte SSL
|
||||
openssl.certificateVerificationFailed=La vérification du certificat a échoué
|
||||
openssl.checkConf=Vérification de OpenSSLConf en cours
|
||||
openssl.doubleInit=Le contexte SSL a déjà été initialisé, ignoré
|
||||
openssl.errApplyConf=Impossible d'appliquer la OpenSSLConf au contexte SSL
|
||||
openssl.errCheckConf=Erreur pendant la vérification de OpenSSLConf
|
||||
openssl.errMakeConf=Impossible de créer le contexte de OpenSSLConf
|
||||
openssl.errorSSLCtxInit=Erreur d'initialisation du contexte SSL
|
||||
openssl.keyManagerMissing=Aucun gestionnaire de clés trouvé
|
||||
openssl.makeConf=Création du contexte de OpenSSLConf
|
||||
openssl.nonJsseCertficate=Le certificat [{0}] ou sa clé privée [{1}] n''a pas pu être traité en utilisant un gestionnaire de clé de JSSE, et sera directement passée à OpenSSL
|
||||
openssl.nonJsseChain=La chaîne de certificat [{0}] n''a pas été spécifiée ou est invalide et JSSE requiert une chaîne de certificats valide, donc OpenSSL sera utilisé directement
|
||||
openssl.trustManagerMissing=Gestionnaire de confiance non trouvé
|
||||
|
||||
opensslconf.applyCommand=Application de la commande OpenSSLConf (nom [{0}] valeur [{1}])
|
||||
opensslconf.applyFailed=Erreur en appliquant OpenSSLConf au contexte SSL
|
||||
opensslconf.checkCommand=Vérification de la commande OpenSSLConf (nom [{0}] valeur [{1}])
|
||||
opensslconf.checkFailed=Echec de la vérification de OpenSSLConf
|
||||
opensslconf.failedCommand=La commande OpenSSLConf (nom [{0}] valeur [{1}]) a échoué avec le résultat [{2}] qui sera ignoré
|
||||
opensslconf.finishFailed=OpenSSLConf s''est terminé en échec avec le résultat [{0}]
|
||||
opensslconf.noCommandName=Pas de nom de commande OpenSSLConf (valeur [{0}]), cela sera ignoré
|
||||
opensslconf.resultCommand=La commande OpenSSLConf (nom [{0}] valeur [{1}]) a retourné [{2}]
|
||||
|
||||
sessionContext.nullTicketKeys=Clés nulles
|
||||
@@ -0,0 +1,59 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
engine.ciphersFailure=暗号リストを取得できません。
|
||||
engine.emptyCipherSuite=暗号スイートがありません。
|
||||
engine.engineClosed=エンジンが閉じられています
|
||||
engine.failedCipherSuite=暗号スイート[{0}]を有効にできませんでした。
|
||||
engine.inboundClose=ピアのclose_notifyを受信する前のインバウンドクローズ
|
||||
engine.invalidBufferArray=オフセット: [{0}], 長さ: [{1}] (期待値: offset <= offset + length <= srcs.length [{2}])
|
||||
engine.noSSLContext=SSLコンテキストがありません
|
||||
engine.noSession=SSLセッションIDが利用可能ではありません
|
||||
engine.nullBuffer=Null バッファ
|
||||
engine.nullBufferInArray=配列内のNull バッファ
|
||||
engine.nullCipherSuite=Null 暗号スイート
|
||||
engine.nullName=Null値名
|
||||
engine.nullValue=Null値
|
||||
engine.openSSLError=OpenSSLエラー:[{0}] メッセージ:[{1}]
|
||||
engine.oversizedPacket=暗号化パケットのサイズが超過しています。
|
||||
engine.unsupportedCipher=サポートされていない暗号スイート:[{0}] [{1}]
|
||||
engine.unsupportedProtocol=プロトコル [{0}] には対応していません。
|
||||
engine.unverifiedPeer=未確認のピア
|
||||
engine.writeToSSLFailed=SSLへの書き込みに失敗しました。返却値:[{0}]
|
||||
|
||||
openssl.X509FactoryError=X509ファクトリインスタンスの取得エラー
|
||||
openssl.addedClientCaCert=クライアント CA 証明書を登録しました: [{0}]
|
||||
openssl.applyConf=OpenSSLConfCmdをSSLコンテキストに適用します。
|
||||
openssl.certificateVerificationFailed=証明書確認に失敗しました
|
||||
openssl.checkConf=OpenSSLConfの確認
|
||||
openssl.doubleInit=SSLコンテキストが既に初期化されています。無視します。
|
||||
openssl.errApplyConf=OpenSSLConfをSSLコンテキストに適用できませんでした。
|
||||
openssl.errCheckConf=OpenSSLConfチェック中のエラー
|
||||
openssl.errMakeConf=OpenSSLConfコンテキストを作成できませんでした。
|
||||
openssl.errorSSLCtxInit=SSL コンテキストの初期化中にエラーが発生しました。
|
||||
openssl.keyManagerMissing=キーマネージャーが見つかりません。
|
||||
openssl.makeConf=OpenSSLConfコンテキストの作成
|
||||
openssl.trustManagerMissing=トラストマネージャが見つかりません
|
||||
|
||||
opensslconf.applyCommand=OpenSSLConfはコマンド(名前[{0}]、値[{1}])を適用しています。
|
||||
opensslconf.applyFailed=OpenSSLConfをSSLコンテキストに適用する際の失敗
|
||||
opensslconf.checkCommand=OpenSSLConfチェックコマンド(名前[{0}]、値[{1}])
|
||||
opensslconf.checkFailed=OpenSSLConf のチェックが失敗しました。
|
||||
opensslconf.failedCommand=結果[{2}]でOpenSSLConfがコマンド(名前[{0}]、値[{1}])に失敗しました。無視されます。
|
||||
opensslconf.finishFailed=結果[{0}]でOpenSSLConfのfinish処理が失敗しました
|
||||
opensslconf.noCommandName=OpenSSLConfコマンド名なし - 無視されます(コマンド値[{0}])
|
||||
opensslconf.resultCommand=OpenSSLConfコマンド(名前[{0}]、値[{1}])が[{2}]を返しました。
|
||||
|
||||
sessionContext.nullTicketKeys=Null キー
|
||||
@@ -0,0 +1,61 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
engine.ciphersFailure=Cipher들의 목록을 얻지 못했습니다.
|
||||
engine.emptyCipherSuite=CipherSuite 이름이 존재하지 않습니다.
|
||||
engine.engineClosed=엔진이 닫혀 있습니다.
|
||||
engine.failedCipherSuite=Cipher suite [{0}]을(를) 사용가능 상태로 설정하지 못했습니다.
|
||||
engine.inboundClose=Peer의 close_notify를 받기 전에, Inbound가 닫혔습니다.
|
||||
engine.invalidBufferArray=offset: [{0}], 길이: [{1}] (요구사항: offset <= offset + length <= srcs.length [{2}])
|
||||
engine.noSSLContext=SSL 컨텍스트가 없음.
|
||||
engine.noSession=SSL 세션 ID가 존재하지 않습니다.
|
||||
engine.nullBuffer=널 버퍼
|
||||
engine.nullBufferInArray=배열 내에 널 버퍼임
|
||||
engine.nullCipherSuite=널 cipher suite
|
||||
engine.nullName=name이 널입니다.
|
||||
engine.nullValue=널 값
|
||||
engine.openSSLError=OpenSSL 오류: [{0}], 메시지: [{1}]
|
||||
engine.oversizedPacket=암호화된 패킷이 너무 큽니다.
|
||||
engine.unsupportedCipher=지원되지 않는 cipher suite: [{0}] [{1}]
|
||||
engine.unsupportedProtocol=프로토콜 [{0}]은(는) 지원되지 않습니다.
|
||||
engine.unverifiedPeer=검증되지 않은 Peer
|
||||
engine.writeToSSLFailed=SSL에 쓰기 실패, 반환 값: [{0}]
|
||||
|
||||
openssl.X509FactoryError=X509 팩토리 인스턴스를 얻는 중 오류 발생
|
||||
openssl.addedClientCaCert=클라이언트 CA 인증서를 추가했습니다: [{0}]
|
||||
openssl.applyConf=OpenSSLConfCmd를 SSL 컨텍스트에 적용합니다.
|
||||
openssl.certificateVerificationFailed=인증서 검증에 실패했습니다.
|
||||
openssl.checkConf=OpenSSLConf를 점검합니다.
|
||||
openssl.doubleInit=SSL 컨텍스트가 이미 초기화되어 있으므로, 초기화 호출을 무시합니다.
|
||||
openssl.errApplyConf=SSL 컨텍스트에 OpenSSLConf를 적용할 수 없었습니다.
|
||||
openssl.errCheckConf=OpenSSLConf 점검 중 오류 발생
|
||||
openssl.errMakeConf=OpenSSLConf 컨텍스트를 생성할 수 없었습니다.
|
||||
openssl.errorSSLCtxInit=SSL 컨텍스트를 초기화 하는 중 오류 발생
|
||||
openssl.keyManagerMissing=키 매니저를 찾을 수 없습니다.
|
||||
openssl.makeConf=OpenSSLConf 컨텍스트를 생성합니다.
|
||||
openssl.nonJsseCertficate=인증서 [{0}] 또는 그것의 개인 키 [{1}]이(가) JSSE 키 매니저를 사용하여 처리되지 못하였으므로, OpenSSL에 직접 전달할 것입니다.
|
||||
openssl.nonJsseChain=해당 인증서 체인 [{0}]이(가) 지정되지 않았거나 유효하지 않으며, JSSE는 유효한 인증서 체인을 요구하므로, OpenSSL을 직접 사용하려 시도합니다.
|
||||
openssl.trustManagerMissing=Trust 매니저를 찾을 수 없습니다.
|
||||
|
||||
opensslconf.applyCommand=OpenSSLConf이 명령을 적용합니다 (이름 [{0}], 값 [{1}]).
|
||||
opensslconf.applyFailed=OpenSSLConf를 SSL 컨텍스트에 적용하는 중 실패
|
||||
opensslconf.checkCommand=OpenSSLConf 점검 명령 (이름 [{0}], 값 [{1}])
|
||||
opensslconf.checkFailed=OpenSSLConf 점검 실패
|
||||
opensslconf.failedCommand=OpenSSLConf가 명령(이름: [{0}], 값: [{1}])을 처리하지 못했습니다 (결과: [{2}]). 이는 무시될 것입니다.
|
||||
opensslconf.finishFailed=OpenSSLConf의 완료가 실패했습니다 (결과 값: [{0}]).
|
||||
opensslconf.noCommandName=OpenSSLConf: 명령 이름이 없습니다 - 무시될 것입니다. (명령 값 [{0}])
|
||||
opensslconf.resultCommand=OpenSSLConf 명령(이름: [{0}], 값: [{1}])이 [{2}]을(를) 반환했습니다.
|
||||
|
||||
sessionContext.nullTicketKeys=널 키들
|
||||
@@ -0,0 +1,16 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
engine.noSession=Идентификатор SSL сессии недоступен
|
||||
@@ -0,0 +1,35 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
engine.ciphersFailure=获取密码列表失败
|
||||
engine.emptyCipherSuite=空密码套件
|
||||
engine.engineClosed=引擎已经关闭
|
||||
engine.noSession=SSL会话ID不可用
|
||||
engine.nullCipherSuite=无加密套件
|
||||
engine.openSSLError=OpenSSL 错误:[{0}] 信息: [{1}]
|
||||
engine.unsupportedProtocol=不支持协议 [{0}]
|
||||
engine.writeToSSLFailed=写入SSL失败,返回:[{0}]
|
||||
|
||||
openssl.X509FactoryError=获取X509工厂实例时出错
|
||||
openssl.addedClientCaCert=添加了客户端 CA 证书:[{0}]
|
||||
openssl.errApplyConf=无法将OpenSSLConf 应用于SSL 上下文
|
||||
openssl.errMakeConf=无法创建OpenSSLConf上下文
|
||||
openssl.keyManagerMissing=key管理器未找到
|
||||
openssl.trustManagerMissing=没有找到.信任管理者
|
||||
|
||||
opensslconf.checkFailed=检查OpenSSLConf时失败。
|
||||
opensslconf.finishFailed=OpenSSLConf 配置失败结果为 [{0}]
|
||||
|
||||
sessionContext.nullTicketKeys=Null keys
|
||||
128
java/org/apache/tomcat/util/net/openssl/OpenSSLConf.java
Normal file
128
java/org/apache/tomcat/util/net/openssl/OpenSSLConf.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.openssl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.jni.SSLConf;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
public class OpenSSLConf implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Log log = LogFactory.getLog(OpenSSLConf.class);
|
||||
private static final StringManager sm = StringManager.getManager(OpenSSLConf.class);
|
||||
|
||||
private final List<OpenSSLConfCmd> commands = new ArrayList<>();
|
||||
|
||||
public void addCmd(OpenSSLConfCmd cmd) {
|
||||
commands.add(cmd);
|
||||
}
|
||||
|
||||
public List<OpenSSLConfCmd> getCommands() {
|
||||
return commands;
|
||||
}
|
||||
|
||||
public boolean check(long cctx) throws Exception {
|
||||
boolean result = true;
|
||||
OpenSSLConfCmd cmd;
|
||||
String name;
|
||||
String value;
|
||||
int rc;
|
||||
for (int i = 0; i < commands.size(); i++) {
|
||||
cmd = commands.get(i);
|
||||
name = cmd.getName();
|
||||
value = cmd.getValue();
|
||||
if (name == null) {
|
||||
log.error(sm.getString("opensslconf.noCommandName", value));
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("opensslconf.checkCommand", name, value));
|
||||
}
|
||||
try {
|
||||
rc = SSLConf.check(cctx, name, value);
|
||||
} catch (Exception e) {
|
||||
log.error(sm.getString("opensslconf.checkFailed"));
|
||||
return false;
|
||||
}
|
||||
if (rc <= 0) {
|
||||
log.error(sm.getString("opensslconf.failedCommand", name, value,
|
||||
Integer.toString(rc)));
|
||||
result = false;
|
||||
} else if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("opensslconf.resultCommand", name, value,
|
||||
Integer.toString(rc)));
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
log.error(sm.getString("opensslconf.checkFailed"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean apply(long cctx, long ctx) throws Exception {
|
||||
boolean result = true;
|
||||
SSLConf.assign(cctx, ctx);
|
||||
OpenSSLConfCmd cmd;
|
||||
String name;
|
||||
String value;
|
||||
int rc;
|
||||
for (int i = 0; i < commands.size(); i++) {
|
||||
cmd = commands.get(i);
|
||||
name = cmd.getName();
|
||||
value = cmd.getValue();
|
||||
if (name == null) {
|
||||
log.error(sm.getString("opensslconf.noCommandName", value));
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("opensslconf.applyCommand", name, value));
|
||||
}
|
||||
try {
|
||||
rc = SSLConf.apply(cctx, name, value);
|
||||
} catch (Exception e) {
|
||||
log.error(sm.getString("opensslconf.applyFailed"));
|
||||
return false;
|
||||
}
|
||||
if (rc <= 0) {
|
||||
log.error(sm.getString("opensslconf.failedCommand", name, value,
|
||||
Integer.toString(rc)));
|
||||
result = false;
|
||||
} else if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("opensslconf.resultCommand", name, value,
|
||||
Integer.toString(rc)));
|
||||
}
|
||||
}
|
||||
rc = SSLConf.finish(cctx);
|
||||
if (rc <= 0) {
|
||||
log.error(sm.getString("opensslconf.finishFailed", Integer.toString(rc)));
|
||||
result = false;
|
||||
}
|
||||
if (!result) {
|
||||
log.error(sm.getString("opensslconf.applyFailed"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
43
java/org/apache/tomcat/util/net/openssl/OpenSSLConfCmd.java
Normal file
43
java/org/apache/tomcat/util/net/openssl/OpenSSLConfCmd.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.openssl;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class OpenSSLConfCmd implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String name = null;
|
||||
private String value = null;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
563
java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
Normal file
563
java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
Normal file
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.openssl;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.jni.CertificateVerifier;
|
||||
import org.apache.tomcat.jni.Pool;
|
||||
import org.apache.tomcat.jni.SSL;
|
||||
import org.apache.tomcat.jni.SSLConf;
|
||||
import org.apache.tomcat.jni.SSLContext;
|
||||
import org.apache.tomcat.util.codec.binary.Base64;
|
||||
import org.apache.tomcat.util.net.AbstractEndpoint;
|
||||
import org.apache.tomcat.util.net.Constants;
|
||||
import org.apache.tomcat.util.net.SSLHostConfig;
|
||||
import org.apache.tomcat.util.net.SSLHostConfig.CertificateVerification;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
|
||||
|
||||
private static final Base64 BASE64_ENCODER = new Base64(64, new byte[] {'\n'});
|
||||
|
||||
private static final Log log = LogFactory.getLog(OpenSSLContext.class);
|
||||
|
||||
// Note: this uses the main "net" package strings as many are common with APR
|
||||
private static final StringManager netSm = StringManager.getManager(AbstractEndpoint.class);
|
||||
private static final StringManager sm = StringManager.getManager(OpenSSLContext.class);
|
||||
|
||||
private static final String defaultProtocol = "TLS";
|
||||
|
||||
private final SSLHostConfig sslHostConfig;
|
||||
private final SSLHostConfigCertificate certificate;
|
||||
private OpenSSLSessionContext sessionContext;
|
||||
private X509TrustManager x509TrustManager;
|
||||
|
||||
private final List<String> negotiableProtocols;
|
||||
|
||||
private String enabledProtocol;
|
||||
|
||||
public String getEnabledProtocol() {
|
||||
return enabledProtocol;
|
||||
}
|
||||
|
||||
public void setEnabledProtocol(String protocol) {
|
||||
enabledProtocol = (protocol == null) ? defaultProtocol : protocol;
|
||||
}
|
||||
|
||||
private final long aprPool;
|
||||
private final AtomicInteger aprPoolDestroyed = new AtomicInteger(0);
|
||||
|
||||
// OpenSSLConfCmd context
|
||||
protected final long cctx;
|
||||
// SSL context
|
||||
protected final long ctx;
|
||||
|
||||
static final CertificateFactory X509_CERT_FACTORY;
|
||||
|
||||
private static final String BEGIN_KEY = "-----BEGIN PRIVATE KEY-----\n";
|
||||
|
||||
private static final Object END_KEY = "\n-----END PRIVATE KEY-----";
|
||||
private boolean initialized = false;
|
||||
|
||||
static {
|
||||
try {
|
||||
X509_CERT_FACTORY = CertificateFactory.getInstance("X.509");
|
||||
} catch (CertificateException e) {
|
||||
throw new IllegalStateException(sm.getString("openssl.X509FactoryError"), e);
|
||||
}
|
||||
}
|
||||
|
||||
public OpenSSLContext(SSLHostConfigCertificate certificate, List<String> negotiableProtocols)
|
||||
throws SSLException {
|
||||
this.sslHostConfig = certificate.getSSLHostConfig();
|
||||
this.certificate = certificate;
|
||||
aprPool = Pool.create(0);
|
||||
boolean success = false;
|
||||
try {
|
||||
// Create OpenSSLConfCmd context if used
|
||||
OpenSSLConf openSslConf = sslHostConfig.getOpenSslConf();
|
||||
if (openSslConf != null) {
|
||||
try {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("openssl.makeConf"));
|
||||
cctx = SSLConf.make(aprPool,
|
||||
SSL.SSL_CONF_FLAG_FILE |
|
||||
SSL.SSL_CONF_FLAG_SERVER |
|
||||
SSL.SSL_CONF_FLAG_CERTIFICATE |
|
||||
SSL.SSL_CONF_FLAG_SHOW_ERRORS);
|
||||
} catch (Exception e) {
|
||||
throw new SSLException(sm.getString("openssl.errMakeConf"), e);
|
||||
}
|
||||
} else {
|
||||
cctx = 0;
|
||||
}
|
||||
sslHostConfig.setOpenSslConfContext(Long.valueOf(cctx));
|
||||
|
||||
// SSL protocol
|
||||
int value = SSL.SSL_PROTOCOL_NONE;
|
||||
for (String protocol : sslHostConfig.getEnabledProtocols()) {
|
||||
if (Constants.SSL_PROTO_SSLv2Hello.equalsIgnoreCase(protocol)) {
|
||||
// NO-OP. OpenSSL always supports SSLv2Hello
|
||||
} else if (Constants.SSL_PROTO_SSLv2.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_SSLV2;
|
||||
} else if (Constants.SSL_PROTO_SSLv3.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_SSLV3;
|
||||
} else if (Constants.SSL_PROTO_TLSv1.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_TLSV1;
|
||||
} else if (Constants.SSL_PROTO_TLSv1_1.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_TLSV1_1;
|
||||
} else if (Constants.SSL_PROTO_TLSv1_2.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_TLSV1_2;
|
||||
} else if (Constants.SSL_PROTO_TLSv1_3.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_TLSV1_3;
|
||||
} else if (Constants.SSL_PROTO_ALL.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_ALL;
|
||||
} else {
|
||||
// Should not happen since filtering to build
|
||||
// enabled protocols removes invalid values.
|
||||
throw new Exception(netSm.getString(
|
||||
"endpoint.apr.invalidSslProtocol", protocol));
|
||||
}
|
||||
}
|
||||
|
||||
// Create SSL Context
|
||||
try {
|
||||
ctx = SSLContext.make(aprPool, value, SSL.SSL_MODE_SERVER);
|
||||
} catch (Exception e) {
|
||||
// If the sslEngine is disabled on the AprLifecycleListener
|
||||
// there will be an Exception here but there is no way to check
|
||||
// the AprLifecycleListener settings from here
|
||||
throw new Exception(
|
||||
netSm.getString("endpoint.apr.failSslContextMake"), e);
|
||||
}
|
||||
|
||||
this.negotiableProtocols = negotiableProtocols;
|
||||
|
||||
success = true;
|
||||
} catch(Exception e) {
|
||||
throw new SSLException(sm.getString("openssl.errorSSLCtxInit"), e);
|
||||
} finally {
|
||||
if (!success) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void destroy() {
|
||||
// Guard against multiple destroyPools() calls triggered by construction exception and finalize() later
|
||||
if (aprPoolDestroyed.compareAndSet(0, 1)) {
|
||||
if (ctx != 0) {
|
||||
SSLContext.free(ctx);
|
||||
}
|
||||
if (cctx != 0) {
|
||||
SSLConf.free(cctx);
|
||||
}
|
||||
if (aprPool != 0) {
|
||||
Pool.destroy(aprPool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the SSL_CTX.
|
||||
*
|
||||
* @param kms Must contain a KeyManager of the type
|
||||
* {@code OpenSSLKeyManager}
|
||||
* @param tms Must contain a TrustManager of the type
|
||||
* {@code X509TrustManager}
|
||||
* @param sr Is not used for this implementation.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void init(KeyManager[] kms, TrustManager[] tms, SecureRandom sr) {
|
||||
if (initialized) {
|
||||
log.warn(sm.getString("openssl.doubleInit"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (sslHostConfig.getInsecureRenegotiation()) {
|
||||
SSLContext.setOptions(ctx, SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
|
||||
} else {
|
||||
SSLContext.clearOptions(ctx, SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
|
||||
}
|
||||
|
||||
// Use server's preference order for ciphers (rather than
|
||||
// client's)
|
||||
String honorCipherOrderStr = sslHostConfig.getHonorCipherOrder();
|
||||
if (honorCipherOrderStr != null) {
|
||||
if (Boolean.parseBoolean(honorCipherOrderStr)) {
|
||||
SSLContext.setOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
} else {
|
||||
SSLContext.clearOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
}
|
||||
}
|
||||
|
||||
// Disable compression if requested
|
||||
if (sslHostConfig.getDisableCompression()) {
|
||||
SSLContext.setOptions(ctx, SSL.SSL_OP_NO_COMPRESSION);
|
||||
} else {
|
||||
SSLContext.clearOptions(ctx, SSL.SSL_OP_NO_COMPRESSION);
|
||||
}
|
||||
|
||||
// Disable TLS Session Tickets (RFC4507) to protect perfect forward secrecy
|
||||
if (sslHostConfig.getDisableSessionTickets()) {
|
||||
SSLContext.setOptions(ctx, SSL.SSL_OP_NO_TICKET);
|
||||
} else {
|
||||
SSLContext.clearOptions(ctx, SSL.SSL_OP_NO_TICKET);
|
||||
}
|
||||
|
||||
// List the ciphers that the client is permitted to negotiate
|
||||
SSLContext.setCipherSuite(ctx, sslHostConfig.getCiphers());
|
||||
|
||||
if (certificate.getCertificateFile() == null) {
|
||||
certificate.setCertificateKeyManager(OpenSSLUtil.chooseKeyManager(kms));
|
||||
}
|
||||
|
||||
addCertificate(certificate);
|
||||
|
||||
// Client certificate verification
|
||||
int value = 0;
|
||||
switch (sslHostConfig.getCertificateVerification()) {
|
||||
case NONE:
|
||||
value = SSL.SSL_CVERIFY_NONE;
|
||||
break;
|
||||
case OPTIONAL:
|
||||
value = SSL.SSL_CVERIFY_OPTIONAL;
|
||||
break;
|
||||
case OPTIONAL_NO_CA:
|
||||
value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA;
|
||||
break;
|
||||
case REQUIRED:
|
||||
value = SSL.SSL_CVERIFY_REQUIRE;
|
||||
break;
|
||||
}
|
||||
SSLContext.setVerify(ctx, value, sslHostConfig.getCertificateVerificationDepth());
|
||||
|
||||
if (tms != null) {
|
||||
// Client certificate verification based on custom trust managers
|
||||
x509TrustManager = chooseTrustManager(tms);
|
||||
SSLContext.setCertVerifyCallback(ctx, new CertificateVerifier() {
|
||||
@Override
|
||||
public boolean verify(long ssl, byte[][] chain, String auth) {
|
||||
X509Certificate[] peerCerts = certificates(chain);
|
||||
try {
|
||||
x509TrustManager.checkClientTrusted(peerCerts, auth);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.debug(sm.getString("openssl.certificateVerificationFailed"), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// Pass along the DER encoded certificates of the accepted client
|
||||
// certificate issuers, so that their subjects can be presented
|
||||
// by the server during the handshake to allow the client choosing
|
||||
// an acceptable certificate
|
||||
for (X509Certificate caCert : x509TrustManager.getAcceptedIssuers()) {
|
||||
SSLContext.addClientCACertificateRaw(ctx, caCert.getEncoded());
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("openssl.addedClientCaCert", caCert.toString()));
|
||||
}
|
||||
} else {
|
||||
// Client certificate verification based on trusted CA files and dirs
|
||||
SSLContext.setCACertificate(ctx,
|
||||
SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificateFile()),
|
||||
SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificatePath()));
|
||||
}
|
||||
|
||||
if (negotiableProtocols != null && negotiableProtocols.size() > 0) {
|
||||
List<String> protocols = new ArrayList<>();
|
||||
protocols.addAll(negotiableProtocols);
|
||||
protocols.add("http/1.1");
|
||||
String[] protocolsArray = protocols.toArray(new String[0]);
|
||||
SSLContext.setAlpnProtos(ctx, protocolsArray, SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE);
|
||||
SSLContext.setNpnProtos(ctx, protocolsArray, SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE);
|
||||
}
|
||||
|
||||
// Apply OpenSSLConfCmd if used
|
||||
OpenSSLConf openSslConf = sslHostConfig.getOpenSslConf();
|
||||
if (openSslConf != null && cctx != 0) {
|
||||
// Check OpenSSLConfCmd if used
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("openssl.checkConf"));
|
||||
try {
|
||||
if (!openSslConf.check(cctx)) {
|
||||
log.error(sm.getString("openssl.errCheckConf"));
|
||||
throw new Exception(sm.getString("openssl.errCheckConf"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new Exception(sm.getString("openssl.errCheckConf"), e);
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("openssl.applyConf"));
|
||||
try {
|
||||
if (!openSslConf.apply(cctx, ctx)) {
|
||||
log.error(sm.getString("openssl.errApplyConf"));
|
||||
throw new SSLException(sm.getString("openssl.errApplyConf"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SSLException(sm.getString("openssl.errApplyConf"), e);
|
||||
}
|
||||
// Reconfigure the enabled protocols
|
||||
int opts = SSLContext.getOptions(ctx);
|
||||
List<String> enabled = new ArrayList<>();
|
||||
// Seems like there is no way to explicitly disable SSLv2Hello
|
||||
// in OpenSSL so it is always enabled
|
||||
enabled.add(Constants.SSL_PROTO_SSLv2Hello);
|
||||
if ((opts & SSL.SSL_OP_NO_TLSv1) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_TLSv1);
|
||||
}
|
||||
if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_TLSv1_1);
|
||||
}
|
||||
if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_TLSv1_2);
|
||||
}
|
||||
if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_SSLv2);
|
||||
}
|
||||
if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_SSLv3);
|
||||
}
|
||||
sslHostConfig.setEnabledProtocols(
|
||||
enabled.toArray(new String[enabled.size()]));
|
||||
// Reconfigure the enabled ciphers
|
||||
sslHostConfig.setEnabledCiphers(SSLContext.getCiphers(ctx));
|
||||
}
|
||||
|
||||
sessionContext = new OpenSSLSessionContext(this);
|
||||
// If client authentication is being used, OpenSSL requires that
|
||||
// this is set so always set it in case an app is configured to
|
||||
// require it
|
||||
sessionContext.setSessionIdContext(SSLContext.DEFAULT_SESSION_ID_CONTEXT);
|
||||
sslHostConfig.setOpenSslContext(Long.valueOf(ctx));
|
||||
initialized = true;
|
||||
} catch (Exception e) {
|
||||
log.warn(sm.getString("openssl.errorSSLCtxInit"), e);
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addCertificate(SSLHostConfigCertificate certificate) throws Exception {
|
||||
// Load Server key and certificate
|
||||
if (certificate.getCertificateFile() != null) {
|
||||
// Set certificate
|
||||
SSLContext.setCertificate(ctx,
|
||||
SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()),
|
||||
SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()),
|
||||
certificate.getCertificateKeyPassword(), getCertificateIndex(certificate));
|
||||
// Set certificate chain file
|
||||
SSLContext.setCertificateChainFile(ctx,
|
||||
SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()), false);
|
||||
// Set revocation
|
||||
SSLContext.setCARevocation(ctx,
|
||||
SSLHostConfig.adjustRelativePath(
|
||||
sslHostConfig.getCertificateRevocationListFile()),
|
||||
SSLHostConfig.adjustRelativePath(
|
||||
sslHostConfig.getCertificateRevocationListPath()));
|
||||
} else {
|
||||
String alias = certificate.getCertificateKeyAlias();
|
||||
X509KeyManager x509KeyManager = certificate.getCertificateKeyManager();
|
||||
if (alias == null) {
|
||||
alias = "tomcat";
|
||||
}
|
||||
X509Certificate[] chain = x509KeyManager.getCertificateChain(alias);
|
||||
if (chain == null) {
|
||||
alias = findAlias(x509KeyManager, certificate);
|
||||
chain = x509KeyManager.getCertificateChain(alias);
|
||||
}
|
||||
PrivateKey key = x509KeyManager.getPrivateKey(alias);
|
||||
StringBuilder sb = new StringBuilder(BEGIN_KEY);
|
||||
String encoded = BASE64_ENCODER.encodeToString(key.getEncoded());
|
||||
if (encoded.endsWith("\n")) {
|
||||
encoded = encoded.substring(0, encoded.length() - 1);
|
||||
}
|
||||
sb.append(encoded);
|
||||
sb.append(END_KEY);
|
||||
SSLContext.setCertificateRaw(ctx, chain[0].getEncoded(),
|
||||
sb.toString().getBytes(StandardCharsets.US_ASCII),
|
||||
getCertificateIndex(certificate));
|
||||
for (int i = 1; i < chain.length; i++) {
|
||||
SSLContext.addChainCertificateRaw(ctx, chain[i].getEncoded());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static int getCertificateIndex(SSLHostConfigCertificate certificate) {
|
||||
int result;
|
||||
// If the type is undefined there will only be one certificate (enforced
|
||||
// in SSLHostConfig) so use the RSA slot.
|
||||
if (certificate.getType() == Type.RSA || certificate.getType() == Type.UNDEFINED) {
|
||||
result = SSL.SSL_AIDX_RSA;
|
||||
} else if (certificate.getType() == Type.EC) {
|
||||
result = SSL.SSL_AIDX_ECC;
|
||||
} else if (certificate.getType() == Type.DSA) {
|
||||
result = SSL.SSL_AIDX_DSA;
|
||||
} else {
|
||||
result = SSL.SSL_AIDX_MAX;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find a valid alias when none was specified in the config.
|
||||
*/
|
||||
private static String findAlias(X509KeyManager keyManager,
|
||||
SSLHostConfigCertificate certificate) {
|
||||
|
||||
Type type = certificate.getType();
|
||||
String result = null;
|
||||
|
||||
List<Type> candidateTypes = new ArrayList<>();
|
||||
if (Type.UNDEFINED.equals(type)) {
|
||||
// Try all types to find an suitable alias
|
||||
candidateTypes.addAll(Arrays.asList(Type.values()));
|
||||
candidateTypes.remove(Type.UNDEFINED);
|
||||
} else {
|
||||
// Look for the specific type to find a suitable alias
|
||||
candidateTypes.add(type);
|
||||
}
|
||||
|
||||
Iterator<Type> iter = candidateTypes.iterator();
|
||||
while (result == null && iter.hasNext()) {
|
||||
result = keyManager.chooseServerAlias(iter.next().toString(), null, null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static X509TrustManager chooseTrustManager(TrustManager[] managers) {
|
||||
for (TrustManager m : managers) {
|
||||
if (m instanceof X509TrustManager) {
|
||||
return (X509TrustManager) m;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(sm.getString("openssl.trustManagerMissing"));
|
||||
}
|
||||
|
||||
private static X509Certificate[] certificates(byte[][] chain) {
|
||||
X509Certificate[] peerCerts = new X509Certificate[chain.length];
|
||||
for (int i = 0; i < peerCerts.length; i++) {
|
||||
peerCerts[i] = new OpenSSLX509Certificate(chain[i]);
|
||||
}
|
||||
return peerCerts;
|
||||
}
|
||||
|
||||
|
||||
long getSSLContextID() {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SSLSessionContext getServerSessionContext() {
|
||||
return sessionContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngine createSSLEngine() {
|
||||
return new OpenSSLEngine(ctx, defaultProtocol, false, sessionContext,
|
||||
(negotiableProtocols != null && negotiableProtocols.size() > 0), initialized,
|
||||
sslHostConfig.getCertificateVerificationDepth(),
|
||||
sslHostConfig.getCertificateVerification() == CertificateVerification.OPTIONAL_NO_CA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLServerSocketFactory getServerSocketFactory() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLParameters getSupportedSSLParameters() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(String alias) {
|
||||
X509Certificate[] chain = null;
|
||||
X509KeyManager x509KeyManager = certificate.getCertificateKeyManager();
|
||||
if (x509KeyManager != null) {
|
||||
if (alias == null) {
|
||||
alias = "tomcat";
|
||||
}
|
||||
chain = x509KeyManager.getCertificateChain(alias);
|
||||
if (chain == null) {
|
||||
alias = findAlias(x509KeyManager, certificate);
|
||||
chain = x509KeyManager.getCertificateChain(alias);
|
||||
}
|
||||
}
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
X509Certificate[] acceptedCerts = null;
|
||||
if (x509TrustManager != null) {
|
||||
acceptedCerts = x509TrustManager.getAcceptedIssuers();
|
||||
}
|
||||
return acceptedCerts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
/*
|
||||
* When an SSLHostConfig is replaced at runtime, it is not possible to
|
||||
* call destroy() on the associated OpenSSLContext since it is likely
|
||||
* that there will be in-progress connections using the OpenSSLContext.
|
||||
* A reference chain has been deliberately established (see
|
||||
* OpenSSLSessionContext) to ensure that the OpenSSLContext remains
|
||||
* ineligible for GC while those connections are alive. Once those
|
||||
* connections complete, the OpenSSLContext will become eligible for GC
|
||||
* and this method will ensure that the associated native resources are
|
||||
* cleaned up.
|
||||
*/
|
||||
try {
|
||||
destroy();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
1433
java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java
Normal file
1433
java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.openssl;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
|
||||
import org.apache.tomcat.util.net.SSLImplementation;
|
||||
import org.apache.tomcat.util.net.SSLSupport;
|
||||
import org.apache.tomcat.util.net.SSLUtil;
|
||||
import org.apache.tomcat.util.net.jsse.JSSESupport;
|
||||
|
||||
public class OpenSSLImplementation extends SSLImplementation {
|
||||
|
||||
@Override
|
||||
public SSLSupport getSSLSupport(SSLSession session) {
|
||||
return new JSSESupport(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLUtil getSSLUtil(SSLHostConfigCertificate certificate) {
|
||||
return new OpenSSLUtil(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlpnSupported() {
|
||||
// OpenSSL supported ALPN
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.openssl;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
|
||||
import org.apache.tomcat.jni.SSL;
|
||||
import org.apache.tomcat.jni.SSLContext;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* OpenSSL specific {@link SSLSessionContext} implementation.
|
||||
*/
|
||||
public class OpenSSLSessionContext implements SSLSessionContext {
|
||||
private static final StringManager sm = StringManager.getManager(OpenSSLSessionContext.class);
|
||||
private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
|
||||
|
||||
private final OpenSSLSessionStats stats;
|
||||
// This is deliberately unused. The reference is retained so that a
|
||||
// reference chain is established and maintained to the OpenSSLContext while
|
||||
// there is a connection that is using the OpenSSLContext. Therefore, the
|
||||
// OpenSSLContext can not be eligible for GC while it is in use.
|
||||
@SuppressWarnings("unused")
|
||||
private final OpenSSLContext context;
|
||||
private final long contextID;
|
||||
|
||||
OpenSSLSessionContext(OpenSSLContext context) {
|
||||
this.context = context;
|
||||
this.contextID = context.getSSLContextID();
|
||||
stats = new OpenSSLSessionStats(contextID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLSession getSession(byte[] bytes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<byte[]> getIds() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SSL session ticket keys of this context.
|
||||
*
|
||||
* @param keys The session ticket keys
|
||||
*/
|
||||
public void setTicketKeys(byte[] keys) {
|
||||
if (keys == null) {
|
||||
throw new IllegalArgumentException(sm.getString("sessionContext.nullTicketKeys"));
|
||||
}
|
||||
SSLContext.setSessionTicketKeys(contextID, keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable caching of SSL sessions.
|
||||
*
|
||||
* @param enabled {@code true} to enable caching, {@code false} to disable
|
||||
*/
|
||||
public void setSessionCacheEnabled(boolean enabled) {
|
||||
long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
|
||||
SSLContext.setSessionCacheMode(contextID, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if caching of SSL sessions is enabled, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isSessionCacheEnabled() {
|
||||
return SSLContext.getSessionCacheMode(contextID) == SSL.SSL_SESS_CACHE_SERVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The statistics for this context.
|
||||
*/
|
||||
public OpenSSLSessionStats stats() {
|
||||
return stats;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSessionTimeout(int seconds) {
|
||||
if (seconds < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
SSLContext.setSessionCacheTimeout(contextID, seconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSessionTimeout() {
|
||||
return (int) SSLContext.getSessionCacheTimeout(contextID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSessionCacheSize(int size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
SSLContext.setSessionCacheSize(contextID, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSessionCacheSize() {
|
||||
return (int) SSLContext.getSessionCacheSize(contextID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the context within which session be reused (server side only)
|
||||
* See <a href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html">
|
||||
* man SSL_CTX_set_session_id_context</a>
|
||||
*
|
||||
* @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name
|
||||
* of the application and/or the hostname and/or service name
|
||||
* @return {@code true} if success, {@code false} otherwise.
|
||||
*/
|
||||
public boolean setSessionIdContext(byte[] sidCtx) {
|
||||
return SSLContext.setSessionIdContext(contextID, sidCtx);
|
||||
}
|
||||
|
||||
private static final class EmptyEnumeration implements Enumeration<byte[]> {
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] nextElement() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
}
|
||||
126
java/org/apache/tomcat/util/net/openssl/OpenSSLSessionStats.java
Normal file
126
java/org/apache/tomcat/util/net/openssl/OpenSSLSessionStats.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.openssl;
|
||||
|
||||
import org.apache.tomcat.jni.SSLContext;
|
||||
|
||||
/**
|
||||
* Stats exposed by an OpenSSL session context.
|
||||
*
|
||||
* @see <a href="https://www.openssl.org/docs/ssl/SSL_CTX_sess_number.html"><code>SSL_CTX_sess_number</code></a>
|
||||
*/
|
||||
public final class OpenSSLSessionStats {
|
||||
|
||||
private final long context;
|
||||
|
||||
OpenSSLSessionStats(long context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current number of sessions in the internal session cache.
|
||||
*/
|
||||
public long number() {
|
||||
return SSLContext.sessionNumber(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of started SSL/TLS handshakes in client mode.
|
||||
*/
|
||||
public long connect() {
|
||||
return SSLContext.sessionConnect(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of successfully established SSL/TLS sessions in client mode.
|
||||
*/
|
||||
public long connectGood() {
|
||||
return SSLContext.sessionConnectGood(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of start renegotiations in client mode.
|
||||
*/
|
||||
public long connectRenegotiate() {
|
||||
return SSLContext.sessionConnectRenegotiate(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of started SSL/TLS handshakes in server mode.
|
||||
*/
|
||||
public long accept() {
|
||||
return SSLContext.sessionAccept(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of successfully established SSL/TLS sessions in server mode.
|
||||
*/
|
||||
public long acceptGood() {
|
||||
return SSLContext.sessionAcceptGood(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of start renegotiations in server mode.
|
||||
*/
|
||||
public long acceptRenegotiate() {
|
||||
return SSLContext.sessionAcceptRenegotiate(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of successfully reused sessions. In client mode, a
|
||||
* session set with {@code SSL_set_session} successfully reused is
|
||||
* counted as a hit. In server mode, a session successfully
|
||||
* retrieved from internal or external cache is counted as a hit.
|
||||
*/
|
||||
public long hits() {
|
||||
return SSLContext.sessionHits(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of successfully retrieved sessions from the external
|
||||
* session cache in server mode.
|
||||
*/
|
||||
public long cbHits() {
|
||||
return SSLContext.sessionCbHits(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of sessions proposed by clients that were not found in
|
||||
* the internal session cache in server mode.
|
||||
*/
|
||||
public long misses() {
|
||||
return SSLContext.sessionMisses(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of sessions proposed by clients and either found in
|
||||
* the internal or external session cache in server mode, but that
|
||||
* were invalid due to timeout. These sessions are not included in
|
||||
* the {@link #hits()} count.
|
||||
*/
|
||||
public long timeouts() {
|
||||
return SSLContext.sessionTimeouts(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of sessions that were removed because the maximum
|
||||
* session cache size was exceeded.
|
||||
*/
|
||||
public long cacheFull() {
|
||||
return SSLContext.sessionCacheFull(context);
|
||||
}
|
||||
}
|
||||
128
java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java
Normal file
128
java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.openssl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.net.SSLContext;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
|
||||
import org.apache.tomcat.util.net.SSLUtilBase;
|
||||
import org.apache.tomcat.util.net.jsse.JSSEKeyManager;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
public class OpenSSLUtil extends SSLUtilBase {
|
||||
|
||||
private static final Log log = LogFactory.getLog(OpenSSLUtil.class);
|
||||
private static final StringManager sm = StringManager.getManager(OpenSSLContext.class);
|
||||
|
||||
|
||||
public OpenSSLUtil(SSLHostConfigCertificate certificate) {
|
||||
super(certificate);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Log getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Set<String> getImplementedProtocols() {
|
||||
return OpenSSLEngine.IMPLEMENTED_PROTOCOLS_SET;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Set<String> getImplementedCiphers() {
|
||||
return OpenSSLEngine.AVAILABLE_CIPHER_SUITES;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean isTls13RenegAuthAvailable() {
|
||||
// OpenSSL does support authentication after the initial handshake
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SSLContext createSSLContextInternal(List<String> negotiableProtocols) throws Exception {
|
||||
return new OpenSSLContext(certificate, negotiableProtocols);
|
||||
}
|
||||
|
||||
|
||||
public static X509KeyManager chooseKeyManager(KeyManager[] managers) throws Exception {
|
||||
if (managers == null) {
|
||||
return null;
|
||||
}
|
||||
for (KeyManager manager : managers) {
|
||||
if (manager instanceof JSSEKeyManager) {
|
||||
return (JSSEKeyManager) manager;
|
||||
}
|
||||
}
|
||||
for (KeyManager manager : managers) {
|
||||
if (manager instanceof X509KeyManager) {
|
||||
return (X509KeyManager) manager;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(sm.getString("openssl.keyManagerMissing"));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public KeyManager[] getKeyManagers() throws Exception {
|
||||
try {
|
||||
return super.getKeyManagers();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// No (or invalid?) certificate chain was provided for the cert
|
||||
String msg = sm.getString("openssl.nonJsseChain", certificate.getCertificateChainFile());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.info(msg, e);
|
||||
} else {
|
||||
log.info(msg);
|
||||
}
|
||||
return null;
|
||||
} catch (KeyStoreException | IOException e) {
|
||||
// Depending on what is presented, JSSE may also throw
|
||||
// KeyStoreException or IOException if it doesn't understand the
|
||||
// provided file.
|
||||
if (certificate.getCertificateFile() != null) {
|
||||
String msg = sm.getString("openssl.nonJsseCertficate",
|
||||
certificate.getCertificateFile(), certificate.getCertificateKeyFile());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.info(msg, e);
|
||||
} else {
|
||||
log.info(msg);
|
||||
}
|
||||
// Assume JSSE processing of the certificate failed, try again with OpenSSL
|
||||
// without a key manager
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.util.net.openssl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.Principal;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateExpiredException;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
final class OpenSSLX509Certificate extends X509Certificate {
|
||||
|
||||
private final byte[] bytes;
|
||||
private X509Certificate wrapped;
|
||||
|
||||
public OpenSSLX509Certificate(byte[] bytes) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {
|
||||
unwrap().checkValidity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException {
|
||||
unwrap().checkValidity(date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return unwrap().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getSerialNumber() {
|
||||
return unwrap().getSerialNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getIssuerDN() {
|
||||
return unwrap().getIssuerDN();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getSubjectDN() {
|
||||
return unwrap().getSubjectDN();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getNotBefore() {
|
||||
return unwrap().getNotBefore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getNotAfter() {
|
||||
return unwrap().getNotAfter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getTBSCertificate() throws CertificateEncodingException {
|
||||
return unwrap().getTBSCertificate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getSignature() {
|
||||
return unwrap().getSignature();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSigAlgName() {
|
||||
return unwrap().getSigAlgName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSigAlgOID() {
|
||||
return unwrap().getSigAlgOID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getSigAlgParams() {
|
||||
return unwrap().getSigAlgParams();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] getIssuerUniqueID() {
|
||||
return unwrap().getIssuerUniqueID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] getSubjectUniqueID() {
|
||||
return unwrap().getSubjectUniqueID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] getKeyUsage() {
|
||||
return unwrap().getKeyUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBasicConstraints() {
|
||||
return unwrap().getBasicConstraints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return bytes.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verify(PublicKey key)
|
||||
throws CertificateException, NoSuchAlgorithmException,
|
||||
InvalidKeyException, NoSuchProviderException, SignatureException {
|
||||
unwrap().verify(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verify(PublicKey key, String sigProvider)
|
||||
throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
|
||||
NoSuchProviderException, SignatureException {
|
||||
unwrap().verify(key, sigProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return unwrap().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicKey getPublicKey() {
|
||||
return unwrap().getPublicKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnsupportedCriticalExtension() {
|
||||
return unwrap().hasUnsupportedCriticalExtension();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getCriticalExtensionOIDs() {
|
||||
return unwrap().getCriticalExtensionOIDs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getNonCriticalExtensionOIDs() {
|
||||
return unwrap().getNonCriticalExtensionOIDs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getExtensionValue(String oid) {
|
||||
return unwrap().getExtensionValue(oid);
|
||||
}
|
||||
|
||||
private X509Certificate unwrap() {
|
||||
X509Certificate wrapped = this.wrapped;
|
||||
if (wrapped == null) {
|
||||
try {
|
||||
wrapped = this.wrapped = (X509Certificate) OpenSSLContext.X509_CERT_FACTORY.generateCertificate(
|
||||
new ByteArrayInputStream(bytes));
|
||||
} catch (CertificateException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
return wrapped;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
public enum Authentication {
|
||||
RSA /* RSA auth */,
|
||||
DSS /* DSS auth */,
|
||||
aNULL /* no auth (i.e. use ADH or AECDH) */,
|
||||
DH /* Fixed DH auth (kDHd or kDHr) */,
|
||||
ECDH /* Fixed ECDH auth (kECDHe or kECDHr) */,
|
||||
KRB5 /* KRB5 auth */,
|
||||
ECDSA /* ECDSA auth*/,
|
||||
PSK /* PSK auth */,
|
||||
GOST94 /* GOST R 34.10-94 signature auth */,
|
||||
GOST01 /* GOST R 34.10-2001 */,
|
||||
FZA /* Fortezza */,
|
||||
SRP,
|
||||
ANY /* TLS 1.3 */
|
||||
}
|
||||
5119
java/org/apache/tomcat/util/net/openssl/ciphers/Cipher.java
Normal file
5119
java/org/apache/tomcat/util/net/openssl/ciphers/Cipher.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
enum Encryption {
|
||||
AES128,
|
||||
AES128CCM,
|
||||
AES128CCM8,
|
||||
AES128GCM,
|
||||
AES256,
|
||||
AES256CCM,
|
||||
AES256CCM8,
|
||||
AES256GCM,
|
||||
ARIA128GCM,
|
||||
ARIA256GCM,
|
||||
CAMELLIA256,
|
||||
CAMELLIA128,
|
||||
CHACHA20POLY1305,
|
||||
TRIPLE_DES,
|
||||
DES,
|
||||
IDEA,
|
||||
eGOST2814789CNT,
|
||||
SEED,
|
||||
FZA,
|
||||
RC4,
|
||||
RC2,
|
||||
eNULL
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
enum EncryptionLevel {
|
||||
STRONG_NONE,
|
||||
EXP40,
|
||||
EXP56,
|
||||
LOW,
|
||||
MEDIUM,
|
||||
HIGH,
|
||||
FIPS
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
enum KeyExchange {
|
||||
EECDH /* SSL_kEECDH - ephemeral ECDH */,
|
||||
RSA /* SSL_kRSA - RSA key exchange */,
|
||||
DHr /* SSL_kDHr - DH cert, RSA CA cert */ /* no such ciphersuites supported! */,
|
||||
DHd /* SSL_kDHd - DH cert, DSA CA cert */ /* no such ciphersuite supported! */,
|
||||
EDH /* SSL_kDHE - tmp DH key no DH cert */,
|
||||
PSK /* SSK_kPSK - PSK */,
|
||||
FZA /* SSL_kFZA - Fortezza */ /* no such ciphersuite supported! */,
|
||||
KRB5 /* SSL_kKRB5 - Kerberos 5 key exchange */,
|
||||
ECDHr /* SSL_kECDHr - ECDH cert, RSA CA cert */,
|
||||
ECDHe /* SSL_kECDHe - ECDH cert, ECDSA CA cert */,
|
||||
GOST /* SSL_kGOST - GOST key exchange */,
|
||||
SRP /* SSL_kSRP - SRP */,
|
||||
RSAPSK,
|
||||
ECDHEPSK,
|
||||
DHEPSK,
|
||||
ANY /* TLS 1.3 */
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
converter.mapping=Cipher suite mapping: [{0}] => [{1}]
|
||||
@@ -0,0 +1,16 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
converter.mapping=Association de la suite de chiffres: [{0}] => [{1}]
|
||||
@@ -0,0 +1,16 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
converter.mapping=暗号スイートの対応付け: [{0}] => [{1}]
|
||||
@@ -0,0 +1,16 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
converter.mapping=Cipher suite 매핑: [{0}] => [{1}]
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
enum MessageDigest {
|
||||
MD5,
|
||||
SHA1,
|
||||
GOST94,
|
||||
GOST89MAC,
|
||||
SHA256,
|
||||
SHA384,
|
||||
AEAD
|
||||
}
|
||||
@@ -0,0 +1,915 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.net.Constants;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Class in charge with parsing openSSL expressions to define a list of ciphers.
|
||||
*/
|
||||
public class OpenSSLCipherConfigurationParser {
|
||||
|
||||
private static final Log log = LogFactory.getLog(OpenSSLCipherConfigurationParser.class);
|
||||
private static final StringManager sm =
|
||||
StringManager.getManager("org.apache.tomcat.util.net.jsse.res");
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
||||
private static final String SEPARATOR = ":|,| ";
|
||||
/**
|
||||
* If ! is used then the ciphers are permanently deleted from the list. The ciphers deleted can never reappear in the list
|
||||
* even if they are explicitly stated.
|
||||
*/
|
||||
private static final String EXCLUDE = "!";
|
||||
/**
|
||||
* If - is used then the ciphers are deleted from the list, but some or all of the ciphers can be added again by later
|
||||
* options.
|
||||
*/
|
||||
private static final String DELETE = "-";
|
||||
/**
|
||||
* If + is used then the ciphers are moved to the end of the list. This option doesn't add any new ciphers it just moves
|
||||
* matching existing ones.
|
||||
*/
|
||||
private static final String TO_END = "+";
|
||||
/**
|
||||
* Lists of cipher suites can be combined in a single cipher string using the + character.
|
||||
* This is used as a logical and operation.
|
||||
* For example SHA1+DES represents all cipher suites containing the SHA1 and the DES algorithms.
|
||||
*/
|
||||
private static final String AND = "+";
|
||||
/**
|
||||
* All ciphers by their openssl alias name.
|
||||
*/
|
||||
private static final Map<String, List<Cipher>> aliases = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* the 'NULL' ciphers that is those offering no encryption. Because these offer no encryption at all and are a security risk
|
||||
* they are disabled unless explicitly included.
|
||||
*/
|
||||
private static final String eNULL = "eNULL";
|
||||
/**
|
||||
* The cipher suites offering no authentication. This is currently the anonymous DH algorithms. T These cipher suites are
|
||||
* vulnerable to a 'man in the middle' attack and so their use is normally discouraged.
|
||||
*/
|
||||
private static final String aNULL = "aNULL";
|
||||
|
||||
/**
|
||||
* 'high' encryption cipher suites. This currently means those with key lengths larger than 128 bits, and some cipher suites
|
||||
* with 128-bit keys.
|
||||
*/
|
||||
private static final String HIGH = "HIGH";
|
||||
/**
|
||||
* 'medium' encryption cipher suites, currently some of those using 128 bit encryption.
|
||||
*/
|
||||
private static final String MEDIUM = "MEDIUM";
|
||||
/**
|
||||
* 'low' encryption cipher suites, currently those using 64 or 56 bit encryption algorithms but excluding export cipher
|
||||
* suites.
|
||||
*/
|
||||
private static final String LOW = "LOW";
|
||||
/**
|
||||
* Export encryption algorithms. Including 40 and 56 bits algorithms.
|
||||
*/
|
||||
private static final String EXPORT = "EXPORT";
|
||||
/**
|
||||
* 40 bit export encryption algorithms.
|
||||
*/
|
||||
private static final String EXPORT40 = "EXPORT40";
|
||||
/**
|
||||
* 56 bit export encryption algorithms.
|
||||
*/
|
||||
private static final String EXPORT56 = "EXPORT56";
|
||||
/**
|
||||
* Cipher suites using RSA key exchange.
|
||||
*/
|
||||
private static final String kRSA = "kRSA";
|
||||
/**
|
||||
* Cipher suites using RSA authentication.
|
||||
*/
|
||||
private static final String aRSA = "aRSA";
|
||||
/**
|
||||
* Cipher suites using RSA for key exchange
|
||||
* Despite what the docs say, RSA is equivalent to kRSA.
|
||||
*/
|
||||
private static final String RSA = "RSA";
|
||||
/**
|
||||
* Cipher suites using ephemeral DH key agreement.
|
||||
*/
|
||||
private static final String kEDH = "kEDH";
|
||||
/**
|
||||
* Cipher suites using ephemeral DH key agreement.
|
||||
*/
|
||||
private static final String kDHE = "kDHE";
|
||||
/**
|
||||
* Cipher suites using ephemeral DH key agreement. equivalent to kEDH:-ADH
|
||||
*/
|
||||
private static final String EDH = "EDH";
|
||||
/**
|
||||
* Cipher suites using ephemeral DH key agreement. equivalent to kEDH:-ADH
|
||||
*/
|
||||
private static final String DHE = "DHE";
|
||||
/**
|
||||
* Cipher suites using DH key agreement and DH certificates signed by CAs with RSA keys.
|
||||
*/
|
||||
private static final String kDHr = "kDHr";
|
||||
/**
|
||||
* Cipher suites using DH key agreement and DH certificates signed by CAs with DSS keys.
|
||||
*/
|
||||
private static final String kDHd = "kDHd";
|
||||
/**
|
||||
* Cipher suites using DH key agreement and DH certificates signed by CAs with RSA or DSS keys.
|
||||
*/
|
||||
private static final String kDH = "kDH";
|
||||
/**
|
||||
* Cipher suites using fixed ECDH key agreement signed by CAs with RSA keys.
|
||||
*/
|
||||
private static final String kECDHr = "kECDHr";
|
||||
/**
|
||||
* Cipher suites using fixed ECDH key agreement signed by CAs with ECDSA keys.
|
||||
*/
|
||||
private static final String kECDHe = "kECDHe";
|
||||
/**
|
||||
* Cipher suites using fixed ECDH key agreement signed by CAs with RSA and ECDSA keys or either respectively.
|
||||
*/
|
||||
private static final String kECDH = "kECDH";
|
||||
/**
|
||||
* Cipher suites using ephemeral ECDH key agreement, including anonymous cipher suites.
|
||||
*/
|
||||
private static final String kEECDH = "kEECDH";
|
||||
/**
|
||||
* Cipher suites using ephemeral ECDH key agreement, excluding anonymous cipher suites.
|
||||
* Same as "kEECDH:-AECDH"
|
||||
*/
|
||||
private static final String EECDH = "EECDH";
|
||||
/**
|
||||
* Cipher suitesusing ECDH key exchange, including anonymous, ephemeral and fixed ECDH.
|
||||
*/
|
||||
private static final String ECDH = "ECDH";
|
||||
/**
|
||||
* Cipher suites using ephemeral ECDH key agreement, including anonymous cipher suites.
|
||||
*/
|
||||
private static final String kECDHE = "kECDHE";
|
||||
/**
|
||||
* Cipher suites using authenticated ephemeral ECDH key agreement
|
||||
*/
|
||||
private static final String ECDHE = "ECDHE";
|
||||
/**
|
||||
* Cipher suites using authenticated ephemeral ECDH key agreement
|
||||
*/
|
||||
private static final String EECDHE = "EECDHE";
|
||||
/**
|
||||
* Anonymous Elliptic Curve Diffie Hellman cipher suites.
|
||||
*/
|
||||
private static final String AECDH = "AECDH";
|
||||
/**
|
||||
* Cipher suites using DSS for key exchange
|
||||
*/
|
||||
private static final String DSS = "DSS";
|
||||
/**
|
||||
* Cipher suites using DSS authentication, i.e. the certificates carry DSS keys.
|
||||
*/
|
||||
private static final String aDSS = "aDSS";
|
||||
/**
|
||||
* Cipher suites effectively using DH authentication, i.e. the certificates carry DH keys.
|
||||
*/
|
||||
private static final String aDH = "aDH";
|
||||
/**
|
||||
* Cipher suites effectively using ECDH authentication, i.e. the certificates carry ECDH keys.
|
||||
*/
|
||||
private static final String aECDH = "aECDH";
|
||||
/**
|
||||
* Cipher suites effectively using ECDSA authentication, i.e. the certificates carry ECDSA keys.
|
||||
*/
|
||||
private static final String aECDSA = "aECDSA";
|
||||
/**
|
||||
* Cipher suites effectively using ECDSA authentication, i.e. the certificates carry ECDSA keys.
|
||||
*/
|
||||
private static final String ECDSA = "ECDSA";
|
||||
/**
|
||||
* Ciphers suites using FORTEZZA key exchange algorithms.
|
||||
*/
|
||||
private static final String kFZA = "kFZA";
|
||||
/**
|
||||
* Ciphers suites using FORTEZZA authentication algorithms.
|
||||
*/
|
||||
private static final String aFZA = "aFZA";
|
||||
/**
|
||||
* Ciphers suites using FORTEZZA encryption algorithms.
|
||||
*/
|
||||
private static final String eFZA = "eFZA";
|
||||
/**
|
||||
* Ciphers suites using all FORTEZZA algorithms.
|
||||
*/
|
||||
private static final String FZA = "FZA";
|
||||
/**
|
||||
* Cipher suites using DH, including anonymous DH, ephemeral DH and fixed DH.
|
||||
*/
|
||||
private static final String DH = "DH";
|
||||
/**
|
||||
* Anonymous DH cipher suites.
|
||||
*/
|
||||
private static final String ADH = "ADH";
|
||||
/**
|
||||
* Cipher suites using 128 bit AES.
|
||||
*/
|
||||
private static final String AES128 = "AES128";
|
||||
/**
|
||||
* Cipher suites using 256 bit AES.
|
||||
*/
|
||||
private static final String AES256 = "AES256";
|
||||
/**
|
||||
* Cipher suites using either 128 or 256 bit AES.
|
||||
*/
|
||||
private static final String AES = "AES";
|
||||
/**
|
||||
* AES in Galois Counter Mode (GCM): these cipher suites are only supported in TLS v1.2.
|
||||
*/
|
||||
private static final String AESGCM = "AESGCM";
|
||||
/**
|
||||
* AES in Counter with CBC-MAC Mode (CCM).
|
||||
*/
|
||||
private static final String AESCCM = "AESCCM";
|
||||
/**
|
||||
* AES in Counter with CBC-MAC Mode and 8-byte authentication (CCM8).
|
||||
*/
|
||||
private static final String AESCCM8 = "AESCCM8";
|
||||
/**
|
||||
* Cipher suites using either 128 bit ARIA.
|
||||
*/
|
||||
private static final String ARIA128 = "ARIA128";
|
||||
/**
|
||||
* Cipher suites using either 256 bit ARIA.
|
||||
*/
|
||||
private static final String ARIA256 = "ARIA256";
|
||||
/**
|
||||
* Cipher suites using either 128 or 256 bit ARIA.
|
||||
*/
|
||||
private static final String ARIA = "ARIA";
|
||||
/**
|
||||
* Cipher suites using 128 bit CAMELLIA.
|
||||
*/
|
||||
private static final String CAMELLIA128 = "CAMELLIA128";
|
||||
/**
|
||||
* Cipher suites using 256 bit CAMELLIA.
|
||||
*/
|
||||
private static final String CAMELLIA256 = "CAMELLIA256";
|
||||
/**
|
||||
* Cipher suites using either 128 or 256 bit CAMELLIA.
|
||||
*/
|
||||
private static final String CAMELLIA = "CAMELLIA";
|
||||
/**
|
||||
* Cipher suites using CHACHA20.
|
||||
*/
|
||||
private static final String CHACHA20 = "CHACHA20";
|
||||
/**
|
||||
* Cipher suites using triple DES.
|
||||
*/
|
||||
private static final String TRIPLE_DES = "3DES";
|
||||
/**
|
||||
* Cipher suites using DES (not triple DES).
|
||||
*/
|
||||
private static final String DES = "DES";
|
||||
/**
|
||||
* Cipher suites using RC4.
|
||||
*/
|
||||
private static final String RC4 = "RC4";
|
||||
/**
|
||||
* Cipher suites using RC2.
|
||||
*/
|
||||
private static final String RC2 = "RC2";
|
||||
/**
|
||||
* Cipher suites using IDEA.
|
||||
*/
|
||||
private static final String IDEA = "IDEA";
|
||||
/**
|
||||
* Cipher suites using SEED.
|
||||
*/
|
||||
private static final String SEED = "SEED";
|
||||
/**
|
||||
* Cipher suites using MD5.
|
||||
*/
|
||||
private static final String MD5 = "MD5";
|
||||
/**
|
||||
* Cipher suites using SHA1.
|
||||
*/
|
||||
private static final String SHA1 = "SHA1";
|
||||
/**
|
||||
* Cipher suites using SHA1.
|
||||
*/
|
||||
private static final String SHA = "SHA";
|
||||
/**
|
||||
* Cipher suites using SHA256.
|
||||
*/
|
||||
private static final String SHA256 = "SHA256";
|
||||
/**
|
||||
* Cipher suites using SHA384.
|
||||
*/
|
||||
private static final String SHA384 = "SHA384";
|
||||
/**
|
||||
* Cipher suites using KRB5.
|
||||
*/
|
||||
private static final String KRB5 = "KRB5";
|
||||
/**
|
||||
* Cipher suites using GOST R 34.10 (either 2001 or 94) for authentication.
|
||||
*/
|
||||
private static final String aGOST = "aGOST";
|
||||
/**
|
||||
* Cipher suites using GOST R 34.10-2001 for authentication.
|
||||
*/
|
||||
private static final String aGOST01 = "aGOST01";
|
||||
/**
|
||||
* Cipher suites using GOST R 34.10-94 authentication (note that R 34.10-94 standard has been expired so use GOST R
|
||||
* 34.10-2001)
|
||||
*/
|
||||
private static final String aGOST94 = "aGOST94";
|
||||
/**
|
||||
* Cipher suites using using VKO 34.10 key exchange, specified in the RFC 4357.
|
||||
*/
|
||||
private static final String kGOST = "kGOST";
|
||||
/**
|
||||
* Cipher suites, using HMAC based on GOST R 34.11-94.
|
||||
*/
|
||||
private static final String GOST94 = "GOST94";
|
||||
/**
|
||||
* Cipher suites using GOST 28147-89 MAC instead of HMAC.
|
||||
*/
|
||||
private static final String GOST89MAC = "GOST89MAC";
|
||||
/**
|
||||
* Cipher suites using SRP authentication, specified in the RFC 5054.
|
||||
*/
|
||||
private static final String aSRP = "aSRP";
|
||||
/**
|
||||
* Cipher suites using SRP key exchange, specified in the RFC 5054.
|
||||
*/
|
||||
private static final String kSRP = "kSRP";
|
||||
/**
|
||||
* Same as kSRP
|
||||
*/
|
||||
private static final String SRP = "SRP";
|
||||
/**
|
||||
* Cipher suites using pre-shared keys (PSK).
|
||||
*/
|
||||
private static final String PSK = "PSK";
|
||||
/**
|
||||
* Cipher suites using PSK authentication.
|
||||
*/
|
||||
private static final String aPSK = "aPSK";
|
||||
/**
|
||||
* Cipher suites using PSK key 'exchange'.
|
||||
*/
|
||||
private static final String kPSK = "kPSK";
|
||||
private static final String kRSAPSK = "kRSAPSK";
|
||||
private static final String kECDHEPSK = "kECDHEPSK";
|
||||
private static final String kDHEPSK = "kDHEPSK";
|
||||
|
||||
private static final String DEFAULT = "DEFAULT";
|
||||
private static final String COMPLEMENTOFDEFAULT = "COMPLEMENTOFDEFAULT";
|
||||
|
||||
private static final String ALL = "ALL";
|
||||
private static final String COMPLEMENTOFALL = "COMPLEMENTOFALL";
|
||||
|
||||
private static final Map<String,String> jsseToOpenSSL = new HashMap<>();
|
||||
|
||||
private static final void init() {
|
||||
|
||||
for (Cipher cipher : Cipher.values()) {
|
||||
String alias = cipher.getOpenSSLAlias();
|
||||
if (aliases.containsKey(alias)) {
|
||||
aliases.get(alias).add(cipher);
|
||||
} else {
|
||||
List<Cipher> list = new ArrayList<>();
|
||||
list.add(cipher);
|
||||
aliases.put(alias, list);
|
||||
}
|
||||
aliases.put(cipher.name(), Collections.singletonList(cipher));
|
||||
|
||||
for (String openSSlAltName : cipher.getOpenSSLAltNames()) {
|
||||
if (aliases.containsKey(openSSlAltName)) {
|
||||
aliases.get(openSSlAltName).add(cipher);
|
||||
} else {
|
||||
List<Cipher> list = new ArrayList<>();
|
||||
list.add(cipher);
|
||||
aliases.put(openSSlAltName, list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
jsseToOpenSSL.put(cipher.name(), cipher.getOpenSSLAlias());
|
||||
Set<String> jsseNames = cipher.getJsseNames();
|
||||
for (String jsseName : jsseNames) {
|
||||
jsseToOpenSSL.put(jsseName, cipher.getOpenSSLAlias());
|
||||
}
|
||||
}
|
||||
List<Cipher> allCiphersList = Arrays.asList(Cipher.values());
|
||||
Collections.reverse(allCiphersList);
|
||||
LinkedHashSet<Cipher> allCiphers = defaultSort(new LinkedHashSet<>(allCiphersList));
|
||||
addListAlias(eNULL, filterByEncryption(allCiphers, Collections.singleton(Encryption.eNULL)));
|
||||
LinkedHashSet<Cipher> all = new LinkedHashSet<>(allCiphers);
|
||||
remove(all, eNULL);
|
||||
addListAlias(ALL, all);
|
||||
addListAlias(HIGH, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.HIGH)));
|
||||
addListAlias(MEDIUM, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.MEDIUM)));
|
||||
addListAlias(LOW, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.LOW)));
|
||||
addListAlias(EXPORT, filterByEncryptionLevel(allCiphers, new HashSet<>(Arrays.asList(EncryptionLevel.EXP40, EncryptionLevel.EXP56))));
|
||||
aliases.put("EXP", aliases.get(EXPORT));
|
||||
addListAlias(EXPORT40, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.EXP40)));
|
||||
addListAlias(EXPORT56, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.EXP56)));
|
||||
aliases.put("NULL", aliases.get(eNULL));
|
||||
aliases.put(COMPLEMENTOFALL, aliases.get(eNULL));
|
||||
addListAlias(aNULL, filterByAuthentication(allCiphers, Collections.singleton(Authentication.aNULL)));
|
||||
addListAlias(kRSA, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.RSA)));
|
||||
addListAlias(aRSA, filterByAuthentication(allCiphers, Collections.singleton(Authentication.RSA)));
|
||||
// Despite what the docs say, RSA is equivalent to kRSA
|
||||
aliases.put(RSA, aliases.get(kRSA));
|
||||
addListAlias(kEDH, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EDH)));
|
||||
addListAlias(kDHE, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EDH)));
|
||||
Set<Cipher> edh = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EDH));
|
||||
edh.removeAll(filterByAuthentication(allCiphers, Collections.singleton(Authentication.aNULL)));
|
||||
addListAlias(EDH, edh);
|
||||
addListAlias(DHE, edh);
|
||||
addListAlias(kDHr, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.DHr)));
|
||||
addListAlias(kDHd, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.DHd)));
|
||||
addListAlias(kDH, filterByKeyExchange(allCiphers, new HashSet<>(Arrays.asList(KeyExchange.DHr, KeyExchange.DHd))));
|
||||
|
||||
addListAlias(kECDHr, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.ECDHr)));
|
||||
addListAlias(kECDHe, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.ECDHe)));
|
||||
addListAlias(kECDH, filterByKeyExchange(allCiphers, new HashSet<>(Arrays.asList(KeyExchange.ECDHe, KeyExchange.ECDHr))));
|
||||
addListAlias(ECDH, filterByKeyExchange(allCiphers, new HashSet<>(Arrays.asList(KeyExchange.ECDHe, KeyExchange.ECDHr, KeyExchange.EECDH))));
|
||||
addListAlias(kECDHE, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH)));
|
||||
|
||||
Set<Cipher> ecdhe = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH));
|
||||
remove(ecdhe, aNULL);
|
||||
addListAlias(ECDHE, ecdhe);
|
||||
|
||||
addListAlias(kEECDH, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH)));
|
||||
aliases.put(EECDHE, aliases.get(kEECDH));
|
||||
Set<Cipher> eecdh = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH));
|
||||
eecdh.removeAll(filterByAuthentication(allCiphers, Collections.singleton(Authentication.aNULL)));
|
||||
addListAlias(EECDH, eecdh);
|
||||
addListAlias(aDSS, filterByAuthentication(allCiphers, Collections.singleton(Authentication.DSS)));
|
||||
aliases.put(DSS, aliases.get(aDSS));
|
||||
addListAlias(aDH, filterByAuthentication(allCiphers, Collections.singleton(Authentication.DH)));
|
||||
Set<Cipher> aecdh = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH));
|
||||
addListAlias(AECDH, filterByAuthentication(aecdh, Collections.singleton(Authentication.aNULL)));
|
||||
addListAlias(aECDH, filterByAuthentication(allCiphers, Collections.singleton(Authentication.ECDH)));
|
||||
addListAlias(ECDSA, filterByAuthentication(allCiphers, Collections.singleton(Authentication.ECDSA)));
|
||||
aliases.put(aECDSA, aliases.get(ECDSA));
|
||||
addListAlias(kFZA, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.FZA)));
|
||||
addListAlias(aFZA, filterByAuthentication(allCiphers, Collections.singleton(Authentication.FZA)));
|
||||
addListAlias(eFZA, filterByEncryption(allCiphers, Collections.singleton(Encryption.FZA)));
|
||||
addListAlias(FZA, filter(allCiphers, null, Collections.singleton(KeyExchange.FZA), Collections.singleton(Authentication.FZA), Collections.singleton(Encryption.FZA), null, null));
|
||||
addListAlias(Constants.SSL_PROTO_TLSv1_2, filterByProtocol(allCiphers, Collections.singleton(Protocol.TLSv1_2)));
|
||||
addListAlias(Constants.SSL_PROTO_TLSv1_0, filterByProtocol(allCiphers, Collections.singleton(Protocol.TLSv1)));
|
||||
addListAlias(Constants.SSL_PROTO_SSLv3, filterByProtocol(allCiphers, Collections.singleton(Protocol.SSLv3)));
|
||||
aliases.put(Constants.SSL_PROTO_TLSv1, aliases.get(Constants.SSL_PROTO_TLSv1_0));
|
||||
addListAlias(Constants.SSL_PROTO_SSLv2, filterByProtocol(allCiphers, Collections.singleton(Protocol.SSLv2)));
|
||||
addListAlias(DH, filterByKeyExchange(allCiphers, new HashSet<>(Arrays.asList(KeyExchange.DHr, KeyExchange.DHd, KeyExchange.EDH))));
|
||||
Set<Cipher> adh = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EDH));
|
||||
adh.retainAll(filterByAuthentication(allCiphers, Collections.singleton(Authentication.aNULL)));
|
||||
addListAlias(ADH, adh);
|
||||
addListAlias(AES128, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128, Encryption.AES128CCM, Encryption.AES128CCM8, Encryption.AES128GCM))));
|
||||
addListAlias(AES256, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES256, Encryption.AES256CCM, Encryption.AES256CCM8, Encryption.AES256GCM))));
|
||||
addListAlias(AES, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128, Encryption.AES128CCM, Encryption.AES128CCM8, Encryption.AES128GCM, Encryption.AES256, Encryption.AES256CCM, Encryption.AES256CCM8, Encryption.AES256GCM))));
|
||||
addListAlias(ARIA128, filterByEncryption(allCiphers, Collections.singleton(Encryption.ARIA128GCM)));
|
||||
addListAlias(ARIA256, filterByEncryption(allCiphers, Collections.singleton(Encryption.ARIA256GCM)));
|
||||
addListAlias(ARIA, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.ARIA128GCM, Encryption.ARIA256GCM))));
|
||||
addListAlias(AESGCM, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128GCM, Encryption.AES256GCM))));
|
||||
addListAlias(AESCCM, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128CCM, Encryption.AES128CCM8, Encryption.AES256CCM, Encryption.AES256CCM8))));
|
||||
addListAlias(AESCCM8, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128CCM8, Encryption.AES256CCM8))));
|
||||
addListAlias(CAMELLIA, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.CAMELLIA128, Encryption.CAMELLIA256))));
|
||||
addListAlias(CAMELLIA128, filterByEncryption(allCiphers, Collections.singleton(Encryption.CAMELLIA128)));
|
||||
addListAlias(CAMELLIA256, filterByEncryption(allCiphers, Collections.singleton(Encryption.CAMELLIA256)));
|
||||
addListAlias(CHACHA20, filterByEncryption(allCiphers, Collections.singleton(Encryption.CHACHA20POLY1305)));
|
||||
addListAlias(TRIPLE_DES, filterByEncryption(allCiphers, Collections.singleton(Encryption.TRIPLE_DES)));
|
||||
addListAlias(DES, filterByEncryption(allCiphers, Collections.singleton(Encryption.DES)));
|
||||
addListAlias(RC4, filterByEncryption(allCiphers, Collections.singleton(Encryption.RC4)));
|
||||
addListAlias(RC2, filterByEncryption(allCiphers, Collections.singleton(Encryption.RC2)));
|
||||
addListAlias(IDEA, filterByEncryption(allCiphers, Collections.singleton(Encryption.IDEA)));
|
||||
addListAlias(SEED, filterByEncryption(allCiphers, Collections.singleton(Encryption.SEED)));
|
||||
addListAlias(MD5, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.MD5)));
|
||||
addListAlias(SHA1, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.SHA1)));
|
||||
aliases.put(SHA, aliases.get(SHA1));
|
||||
addListAlias(SHA256, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.SHA256)));
|
||||
addListAlias(SHA384, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.SHA384)));
|
||||
addListAlias(aGOST, filterByAuthentication(allCiphers, new HashSet<>(Arrays.asList(Authentication.GOST01, Authentication.GOST94))));
|
||||
addListAlias(aGOST01, filterByAuthentication(allCiphers, Collections.singleton(Authentication.GOST01)));
|
||||
addListAlias(aGOST94, filterByAuthentication(allCiphers, Collections.singleton(Authentication.GOST94)));
|
||||
addListAlias(kGOST, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.GOST)));
|
||||
addListAlias(GOST94, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.GOST94)));
|
||||
addListAlias(GOST89MAC, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.GOST89MAC)));
|
||||
addListAlias(PSK, filter(allCiphers, null, new HashSet<>(Arrays.asList(KeyExchange.PSK, KeyExchange.RSAPSK, KeyExchange.DHEPSK, KeyExchange.ECDHEPSK)), Collections.singleton(Authentication.PSK), null, null, null));
|
||||
addListAlias(aPSK, filterByAuthentication(allCiphers, Collections.singleton(Authentication.PSK)));
|
||||
addListAlias(kPSK, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.PSK)));
|
||||
addListAlias(kRSAPSK, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.RSAPSK)));
|
||||
addListAlias(kECDHEPSK, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.ECDHEPSK)));
|
||||
addListAlias(kDHEPSK, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.DHEPSK)));
|
||||
addListAlias(KRB5, filter(allCiphers, null, Collections.singleton(KeyExchange.KRB5), Collections.singleton(Authentication.KRB5), null, null, null));
|
||||
addListAlias(aSRP, filterByAuthentication(allCiphers, Collections.singleton(Authentication.SRP)));
|
||||
addListAlias(kSRP, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.SRP)));
|
||||
addListAlias(SRP, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.SRP)));
|
||||
initialized = true;
|
||||
// Despite what the OpenSSL docs say, DEFAULT also excludes SSLv2
|
||||
addListAlias(DEFAULT, parse("ALL:!EXPORT:!eNULL:!aNULL:!SSLv2:!DES:!RC2:!RC4:!DSS:!SEED:!IDEA:!CAMELLIA:!AESCCM:!3DES:!ARIA"));
|
||||
// COMPLEMENTOFDEFAULT is also not exactly as defined by the docs
|
||||
LinkedHashSet<Cipher> complementOfDefault = filterByKeyExchange(all, new HashSet<>(Arrays.asList(KeyExchange.EDH,KeyExchange.EECDH)));
|
||||
complementOfDefault = filterByAuthentication(complementOfDefault, Collections.singleton(Authentication.aNULL));
|
||||
complementOfDefault.removeAll(aliases.get(eNULL));
|
||||
complementOfDefault.addAll(aliases.get(Constants.SSL_PROTO_SSLv2));
|
||||
complementOfDefault.addAll(aliases.get(EXPORT));
|
||||
complementOfDefault.addAll(aliases.get(DES));
|
||||
complementOfDefault.addAll(aliases.get(TRIPLE_DES));
|
||||
complementOfDefault.addAll(aliases.get(RC2));
|
||||
complementOfDefault.addAll(aliases.get(RC4));
|
||||
complementOfDefault.addAll(aliases.get(aDSS));
|
||||
complementOfDefault.addAll(aliases.get(SEED));
|
||||
complementOfDefault.addAll(aliases.get(IDEA));
|
||||
complementOfDefault.addAll(aliases.get(CAMELLIA));
|
||||
complementOfDefault.addAll(aliases.get(AESCCM));
|
||||
complementOfDefault.addAll(aliases.get(ARIA));
|
||||
defaultSort(complementOfDefault);
|
||||
addListAlias(COMPLEMENTOFDEFAULT, complementOfDefault);
|
||||
}
|
||||
|
||||
static void addListAlias(String alias, Set<Cipher> ciphers) {
|
||||
aliases.put(alias, new ArrayList<>(ciphers));
|
||||
}
|
||||
|
||||
static void moveToEnd(final LinkedHashSet<Cipher> ciphers, final String alias) {
|
||||
moveToEnd(ciphers, aliases.get(alias));
|
||||
}
|
||||
|
||||
static void moveToEnd(final LinkedHashSet<Cipher> ciphers, final Collection<Cipher> toBeMovedCiphers) {
|
||||
List<Cipher> movedCiphers = new ArrayList<>(toBeMovedCiphers);
|
||||
movedCiphers.retainAll(ciphers);
|
||||
ciphers.removeAll(movedCiphers);
|
||||
ciphers.addAll(movedCiphers);
|
||||
}
|
||||
|
||||
static void moveToStart(final LinkedHashSet<Cipher> ciphers, final Collection<Cipher> toBeMovedCiphers) {
|
||||
List<Cipher> movedCiphers = new ArrayList<>(toBeMovedCiphers);
|
||||
List<Cipher> originalCiphers = new ArrayList<>(ciphers);
|
||||
movedCiphers.retainAll(ciphers);
|
||||
ciphers.clear();
|
||||
ciphers.addAll(movedCiphers);
|
||||
ciphers.addAll(originalCiphers);
|
||||
}
|
||||
|
||||
static void add(final LinkedHashSet<Cipher> ciphers, final String alias) {
|
||||
ciphers.addAll(aliases.get(alias));
|
||||
}
|
||||
|
||||
static void remove(final Set<Cipher> ciphers, final String alias) {
|
||||
ciphers.removeAll(aliases.get(alias));
|
||||
}
|
||||
|
||||
static LinkedHashSet<Cipher> strengthSort(final LinkedHashSet<Cipher> ciphers) {
|
||||
/*
|
||||
* This routine sorts the ciphers with descending strength. The sorting
|
||||
* must keep the pre-sorted sequence, so we apply the normal sorting
|
||||
* routine as '+' movement to the end of the list.
|
||||
*/
|
||||
Set<Integer> keySizes = new HashSet<>();
|
||||
for (Cipher cipher : ciphers) {
|
||||
keySizes.add(Integer.valueOf(cipher.getStrength_bits()));
|
||||
}
|
||||
List<Integer> strength_bits = new ArrayList<>(keySizes);
|
||||
Collections.sort(strength_bits);
|
||||
Collections.reverse(strength_bits);
|
||||
final LinkedHashSet<Cipher> result = new LinkedHashSet<>(ciphers);
|
||||
for (int strength : strength_bits) {
|
||||
moveToEnd(result, filterByStrengthBits(ciphers, strength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* See
|
||||
* https://github.com/openssl/openssl/blob/7c96dbcdab959fef74c4caae63cdebaa354ab252/ssl/ssl_ciph.c#L1371
|
||||
*/
|
||||
static LinkedHashSet<Cipher> defaultSort(final LinkedHashSet<Cipher> ciphers) {
|
||||
final LinkedHashSet<Cipher> result = new LinkedHashSet<>(ciphers.size());
|
||||
final LinkedHashSet<Cipher> ecdh = new LinkedHashSet<>(ciphers.size());
|
||||
|
||||
/* Everything else being equal, prefer ephemeral ECDH over other key exchange mechanisms */
|
||||
ecdh.addAll(filterByKeyExchange(ciphers, Collections.singleton(KeyExchange.EECDH)));
|
||||
|
||||
/* AES is our preferred symmetric cipher */
|
||||
Set<Encryption> aes = new HashSet<>(Arrays.asList(Encryption.AES128, Encryption.AES128CCM,
|
||||
Encryption.AES128CCM8, Encryption.AES128GCM, Encryption.AES256,
|
||||
Encryption.AES256CCM, Encryption.AES256CCM8, Encryption.AES256GCM));
|
||||
|
||||
/* Now arrange all ciphers by preference: */
|
||||
result.addAll(filterByEncryption(ecdh, aes));
|
||||
result.addAll(filterByEncryption(ciphers, aes));
|
||||
|
||||
/* Add everything else */
|
||||
result.addAll(ecdh);
|
||||
result.addAll(ciphers);
|
||||
|
||||
/* Low priority for MD5 */
|
||||
moveToEnd(result, filterByMessageDigest(result, Collections.singleton(MessageDigest.MD5)));
|
||||
|
||||
/* Move anonymous ciphers to the end. Usually, these will remain disabled.
|
||||
* (For applications that allow them, they aren't too bad, but we prefer
|
||||
* authenticated ciphers.) */
|
||||
moveToEnd(result, filterByAuthentication(result, Collections.singleton(Authentication.aNULL)));
|
||||
|
||||
/* Move ciphers without forward secrecy to the end */
|
||||
moveToEnd(result, filterByAuthentication(result, Collections.singleton(Authentication.ECDH)));
|
||||
moveToEnd(result, filterByKeyExchange(result, Collections.singleton(KeyExchange.RSA)));
|
||||
moveToEnd(result, filterByKeyExchange(result, Collections.singleton(KeyExchange.PSK)));
|
||||
|
||||
/* RC4 is sort-of broken -- move the the end */
|
||||
moveToEnd(result, filterByEncryption(result, Collections.singleton(Encryption.RC4)));
|
||||
return strengthSort(result);
|
||||
}
|
||||
|
||||
static Set<Cipher> filterByStrengthBits(Set<Cipher> ciphers, int strength_bits) {
|
||||
Set<Cipher> result = new LinkedHashSet<>(ciphers.size());
|
||||
for (Cipher cipher : ciphers) {
|
||||
if (cipher.getStrength_bits() == strength_bits) {
|
||||
result.add(cipher);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Set<Cipher> filterByProtocol(Set<Cipher> ciphers, Set<Protocol> protocol) {
|
||||
return filter(ciphers, protocol, null, null, null, null, null);
|
||||
}
|
||||
|
||||
static LinkedHashSet<Cipher> filterByKeyExchange(Set<Cipher> ciphers, Set<KeyExchange> kx) {
|
||||
return filter(ciphers, null, kx, null, null, null, null);
|
||||
}
|
||||
|
||||
static LinkedHashSet<Cipher> filterByAuthentication(Set<Cipher> ciphers, Set<Authentication> au) {
|
||||
return filter(ciphers, null, null, au, null, null, null);
|
||||
}
|
||||
|
||||
static Set<Cipher> filterByEncryption(Set<Cipher> ciphers, Set<Encryption> enc) {
|
||||
return filter(ciphers, null, null, null, enc, null, null);
|
||||
}
|
||||
|
||||
static Set<Cipher> filterByEncryptionLevel(Set<Cipher> ciphers, Set<EncryptionLevel> level) {
|
||||
return filter(ciphers, null, null, null, null, level, null);
|
||||
}
|
||||
|
||||
static Set<Cipher> filterByMessageDigest(Set<Cipher> ciphers, Set<MessageDigest> mac) {
|
||||
return filter(ciphers, null, null, null, null, null, mac);
|
||||
}
|
||||
|
||||
static LinkedHashSet<Cipher> filter(Set<Cipher> ciphers, Set<Protocol> protocol, Set<KeyExchange> kx,
|
||||
Set<Authentication> au, Set<Encryption> enc, Set<EncryptionLevel> level, Set<MessageDigest> mac) {
|
||||
LinkedHashSet<Cipher> result = new LinkedHashSet<>(ciphers.size());
|
||||
for (Cipher cipher : ciphers) {
|
||||
if (protocol != null && protocol.contains(cipher.getProtocol())) {
|
||||
result.add(cipher);
|
||||
}
|
||||
if (kx != null && kx.contains(cipher.getKx())) {
|
||||
result.add(cipher);
|
||||
}
|
||||
if (au != null && au.contains(cipher.getAu())) {
|
||||
result.add(cipher);
|
||||
}
|
||||
if (enc != null && enc.contains(cipher.getEnc())) {
|
||||
result.add(cipher);
|
||||
}
|
||||
if (level != null && level.contains(cipher.getLevel())) {
|
||||
result.add(cipher);
|
||||
}
|
||||
if (mac != null && mac.contains(cipher.getMac())) {
|
||||
result.add(cipher);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static LinkedHashSet<Cipher> parse(String expression) {
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
String[] elements = expression.split(SEPARATOR);
|
||||
LinkedHashSet<Cipher> ciphers = new LinkedHashSet<>();
|
||||
Set<Cipher> removedCiphers = new HashSet<>();
|
||||
for (String element : elements) {
|
||||
if (element.startsWith(DELETE)) {
|
||||
String alias = element.substring(1);
|
||||
if (aliases.containsKey(alias)) {
|
||||
remove(ciphers, alias);
|
||||
}
|
||||
} else if (element.startsWith(EXCLUDE)) {
|
||||
String alias = element.substring(1);
|
||||
if (aliases.containsKey(alias)) {
|
||||
removedCiphers.addAll(aliases.get(alias));
|
||||
} else {
|
||||
log.warn(sm.getString("jsse.openssl.unknownElement", alias));
|
||||
}
|
||||
} else if (element.startsWith(TO_END)) {
|
||||
String alias = element.substring(1);
|
||||
if (aliases.containsKey(alias)) {
|
||||
moveToEnd(ciphers, alias);
|
||||
}
|
||||
} else if ("@STRENGTH".equals(element)) {
|
||||
strengthSort(ciphers);
|
||||
break;
|
||||
} else if (aliases.containsKey(element)) {
|
||||
add(ciphers, element);
|
||||
} else if (element.contains(AND)) {
|
||||
String[] intersections = element.split("\\" + AND);
|
||||
if(intersections.length > 0 && aliases.containsKey(intersections[0])) {
|
||||
List<Cipher> result = new ArrayList<>(aliases.get(intersections[0]));
|
||||
for(int i = 1; i < intersections.length; i++) {
|
||||
if(aliases.containsKey(intersections[i])) {
|
||||
result.retainAll(aliases.get(intersections[i]));
|
||||
}
|
||||
}
|
||||
ciphers.addAll(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
ciphers.removeAll(removedCiphers);
|
||||
return ciphers;
|
||||
}
|
||||
|
||||
public static List<String> convertForJSSE(Collection<Cipher> ciphers) {
|
||||
List<String> result = new ArrayList<>(ciphers.size());
|
||||
for (Cipher cipher : ciphers) {
|
||||
result.addAll(cipher.getJsseNames());
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jsse.openssl.effectiveCiphers", displayResult(ciphers, true, ",")));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the specified expression according to the OpenSSL syntax and
|
||||
* returns a list of standard JSSE cipher names.
|
||||
*
|
||||
* @param expression the openssl expression to define a list of cipher.
|
||||
* @return the corresponding list of ciphers.
|
||||
*/
|
||||
public static List<String> parseExpression(String expression) {
|
||||
return convertForJSSE(parse(expression));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a JSSE cipher name to an OpenSSL cipher name.
|
||||
*
|
||||
* @param jsseCipherName The JSSE name for a cipher
|
||||
*
|
||||
* @return The OpenSSL name for the specified JSSE cipher
|
||||
*/
|
||||
public static String jsseToOpenSSL(String jsseCipherName) {
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
return jsseToOpenSSL.get(jsseCipherName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts an OpenSSL cipher name to a JSSE cipher name.
|
||||
*
|
||||
* @param opensslCipherName The OpenSSL name for a cipher
|
||||
*
|
||||
* @return The JSSE name for the specified OpenSSL cipher. If none is known,
|
||||
* the IANA standard name will be returned instead
|
||||
*/
|
||||
public static String openSSLToJsse(String opensslCipherName) {
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
List<Cipher> ciphers = aliases.get(opensslCipherName);
|
||||
if (ciphers == null || ciphers.size() != 1) {
|
||||
// Not an OpenSSL cipher name
|
||||
return null;
|
||||
}
|
||||
Cipher cipher = ciphers.get(0);
|
||||
// Each Cipher always has at least one JSSE name
|
||||
return cipher.getJsseNames().iterator().next();
|
||||
}
|
||||
|
||||
|
||||
static String displayResult(Collection<Cipher> ciphers, boolean useJSSEFormat, String separator) {
|
||||
if (ciphers.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder builder = new StringBuilder(ciphers.size() * 16);
|
||||
for (Cipher cipher : ciphers) {
|
||||
if (useJSSEFormat) {
|
||||
for (String name : cipher.getJsseNames()) {
|
||||
builder.append(name);
|
||||
builder.append(separator);
|
||||
}
|
||||
} else {
|
||||
builder.append(cipher.getOpenSSLAlias());
|
||||
}
|
||||
builder.append(separator);
|
||||
}
|
||||
return builder.toString().substring(0, builder.length() - 1);
|
||||
}
|
||||
|
||||
public static void usage() {
|
||||
System.out.println("Usage: java " + OpenSSLCipherConfigurationParser.class.getName() + " [options] cipherspec");
|
||||
System.out.println();
|
||||
System.out.println("Displays the TLS cipher suites matching the cipherspec.");
|
||||
System.out.println();
|
||||
System.out.println(" --help,");
|
||||
System.out.println(" -h Print this help message");
|
||||
System.out.println(" --openssl Show OpenSSL cipher suite names instead of IANA cipher suite names.");
|
||||
System.out.println(" --verbose,");
|
||||
System.out.println(" -v Provide detailed cipher listing");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
boolean verbose = false;
|
||||
boolean useOpenSSLNames = false;
|
||||
int argindex;
|
||||
for(argindex = 0; argindex < args.length; ++argindex)
|
||||
{
|
||||
String arg = args[argindex];
|
||||
if("--verbose".equals(arg) || "-v".equals(arg))
|
||||
verbose = true;
|
||||
else if("--openssl".equals(arg))
|
||||
useOpenSSLNames = true;
|
||||
else if("--help".equals(arg) || "-h".equals(arg)) {
|
||||
usage();
|
||||
System.exit(0);
|
||||
}
|
||||
else if("--".equals(arg)) {
|
||||
++argindex;
|
||||
break;
|
||||
} else if(arg.startsWith("-")) {
|
||||
System.out.println("Unknown option: " + arg);
|
||||
usage();
|
||||
System.exit(1);
|
||||
} else {
|
||||
// Non-switch argument... probably the cipher spec
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String cipherSpec;
|
||||
if(argindex < args.length) {
|
||||
cipherSpec = args[argindex];
|
||||
} else {
|
||||
cipherSpec = "DEFAULT";
|
||||
}
|
||||
Set<Cipher> ciphers = parse(cipherSpec);
|
||||
boolean first = true;
|
||||
if(null != ciphers && 0 < ciphers.size()) {
|
||||
for(Cipher cipher : ciphers)
|
||||
{
|
||||
if(first) {
|
||||
first = false;
|
||||
} else {
|
||||
if(!verbose)
|
||||
System.out.print(',');
|
||||
}
|
||||
if(useOpenSSLNames)
|
||||
System.out.print(cipher.getOpenSSLAlias());
|
||||
else
|
||||
System.out.print(cipher.name());
|
||||
if(verbose) {
|
||||
System.out.println("\t" + cipher.getProtocol() + "\tKx=" + cipher.getKx() + "\tAu=" + cipher.getAu() + "\tEnc=" + cipher.getEnc() + "\tMac=" + cipher.getMac());
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
} else {
|
||||
System.out.println("No ciphers match '" + cipherSpec + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.util.net.openssl.ciphers;
|
||||
|
||||
import org.apache.tomcat.util.net.Constants;
|
||||
|
||||
enum Protocol {
|
||||
|
||||
SSLv3(Constants.SSL_PROTO_SSLv3),
|
||||
SSLv2(Constants.SSL_PROTO_SSLv2),
|
||||
TLSv1(Constants.SSL_PROTO_TLSv1),
|
||||
TLSv1_2(Constants.SSL_PROTO_TLSv1_2),
|
||||
TLSv1_3(Constants.SSL_PROTO_TLSv1_3);
|
||||
|
||||
private final String openSSLName;
|
||||
|
||||
private Protocol(String openSSLName) {
|
||||
this.openSSLName = openSSLName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name returned by OpenSSL in the protocol column when using
|
||||
* <code>openssl ciphers -v</code>. This is currently only used by the unit
|
||||
* tests hence it is package private.
|
||||
*/
|
||||
String getOpenSSLName() {
|
||||
return openSSLName;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user