/*
* 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.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreSpi;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactorySpi;
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.X509KeyManager;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.apache.tomcat.util.net.jsse.JSSEUtil;
/**
* Test case for <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=64614">Bug 64614</a>.
*/
public class TestKeyManagerWrappingFips {
private static final String FIPS_PROVIDER = "FIPS_PROVIDER";
private static final String NON_FIPS_PROVIDER = "NON_FIPS_PROVIDER";
private static final String DUMMY_ALGORITHM = "DUMMY_ALGORITHM";
private static final String KEYSTORE_PROVIDER = "KEYSTORE_PROVIDER";
private static final String DUMMY_KEYSTORE = "DUMMY_KEYSTORE";
@After
public void restore() {
DummyKeyStoreSpi.wrappingOccurred = false;
Security.removeProvider(FIPS_PROVIDER);
Security.removeProvider(NON_FIPS_PROVIDER);
Security.removeProvider(KEYSTORE_PROVIDER);
}
@Test
public void testBug64614_01() throws Exception {
Security.addProvider(new DummyKeyManagerFactoryProvider(FIPS_PROVIDER, "Sun JSSE provider (FIPS mode, crypto provider SunPKCS11-NSSfips", DUMMY_ALGORITHM));
getKeyManagers();
Assert.assertFalse(DummyKeyStoreSpi.wrappingOccurred);
}
@Test
public void testBug64614_02() throws Exception {
Security.addProvider(new DummyKeyManagerFactoryProvider(NON_FIPS_PROVIDER, "Sun JSSE provider", DUMMY_ALGORITHM));
getKeyManagers();
Assert.assertTrue(DummyKeyStoreSpi.wrappingOccurred);
}
private void getKeyManagers() throws Exception {
Security.addProvider(new DummyKeyStoreProvider(KEYSTORE_PROVIDER, "", DUMMY_KEYSTORE));
SSLHostConfig hostConfig = new SSLHostConfig();
hostConfig.setKeyManagerAlgorithm(DUMMY_ALGORITHM);
SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(hostConfig, SSLHostConfigCertificate.Type.UNDEFINED);
File keystoreFile = File.createTempFile("keystore", ".jks");
certificate.setCertificateKeystoreProvider(KEYSTORE_PROVIDER);
certificate.setCertificateKeystoreType(DUMMY_KEYSTORE);
certificate.setCertificateKeystoreFile(keystoreFile.getAbsolutePath());
new JSSEUtil(certificate).getKeyManagers();
if (!keystoreFile.delete()) {
keystoreFile.deleteOnExit();
}
}
private static final class DummyKeyStoreProvider extends Provider {
private static final long serialVersionUID = 1L;
DummyKeyStoreProvider(String name, String info, String algorithm) {
super(name, "", info);
put("KeyStore." + algorithm, DummyKeyStoreSpi.class.getName());
}
}
public static final class DummyKeyStoreSpi extends KeyStoreSpi {
static volatile boolean wrappingOccurred = false;
@Override
public Key engineGetKey(String s, char[] chars) {
wrappingOccurred = true;
return null;
}
@Override
public Certificate[] engineGetCertificateChain(String s) {
return null;
}
@Override
public Certificate engineGetCertificate(String s) {
return null;
}
@Override
public Date engineGetCreationDate(String s) {
return null;
}
@Override
public void engineSetKeyEntry(String s, Key key, char[] chars, Certificate[] certificates) {
}
@Override
public void engineSetKeyEntry(String s, byte[] bytes, Certificate[] certificates) {
}
@Override
public void engineSetCertificateEntry(String s, Certificate certificate) {
}
@Override
public void engineDeleteEntry(String s) {
}
@Override
public Enumeration<String> engineAliases() {
return new Enumeration<>() {
@Override
public boolean hasMoreElements() {
return true;
}
@Override
public String nextElement() {
return "";
}
};
}
@Override
public boolean engineContainsAlias(String s) {
return false;
}
@Override
public int engineSize() {
return 0;
}
@Override
public boolean engineIsKeyEntry(String s) {
return true;
}
@Override
public boolean engineIsCertificateEntry(String s) {
return false;
}
@Override
public String engineGetCertificateAlias(Certificate certificate) {
return "";
}
@Override
public void engineStore(OutputStream outputStream, char[] chars) {
}
@Override
public void engineLoad(InputStream inputStream, char[] chars) {
}
}
private static final class DummyKeyManagerFactoryProvider extends Provider {
private static final long serialVersionUID = 1L;
DummyKeyManagerFactoryProvider(String name, String info, String algorithm) {
super(name, "", info);
put("KeyManagerFactory." + algorithm, DummyKeyManagerFactorySpi.class.getName());
}
}
public static final class DummyKeyManagerFactorySpi extends KeyManagerFactorySpi {
@Override
protected void engineInit(KeyStore ks, char[] password) {
}
@Override
protected void engineInit(ManagerFactoryParameters spec) {
}
@Override
protected KeyManager[] engineGetKeyManagers() {
return new KeyManager[] { new X509KeyManager() {
@Override
public String[] getClientAliases(String s, Principal[] principals) {
return new String[0];
}
@Override
public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
return "";
}
@Override
public String[] getServerAliases(String s, Principal[] principals) {
return new String[0];
}
@Override
public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
return "";
}
@Override
public X509Certificate[] getCertificateChain(String s) {
return new X509Certificate[0];
}
@Override
public PrivateKey getPrivateKey(String s) {
return null;
}
} };
}
}
}