init
This commit is contained in:
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user