/*
* Demoiselle Framework
* Copyright (C) 2010 SERPRO
* ----------------------------------------------------------------------------
* This file is part of Demoiselle Framework.
*
* Demoiselle Framework is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License version 3
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License version 3
* along with this program; if not, see <http://www.gnu.org/licenses/>
* or write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301, USA.
* ----------------------------------------------------------------------------
* Este arquivo é parte do Framework Demoiselle.
*
* O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou
* modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação
* do Software Livre (FSF).
*
* Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA
* GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou
* APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português
* para maiores detalhes.
*
* Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título
* "LICENCA.txt", junto com esse programa. Se não, acesse <http://www.gnu.org/licenses/>
* ou escreva para a Fundação do Software Livre (FSF) Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA.
*/
package br.gov.frameworkdemoiselle.certificate.keystore.loader.implementation;
import java.lang.reflect.Field;
import java.security.KeyStore;
import java.security.KeyStoreSpi;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Map;
import javax.security.auth.callback.CallbackHandler;
import br.gov.frameworkdemoiselle.certificate.keystore.loader.KeyStoreLoader;
import br.gov.frameworkdemoiselle.certificate.keystore.loader.KeyStoreLoaderException;
/**
* Implementação de KeyStoreLoader baseado no Provider específico do Windows que
* acompanha a distribuição da Sun JVM 1.6.
*/
public class MSKeyStoreLoader implements KeyStoreLoader {
protected static final String MS_PROVIDER = "SunMSCAPI";
protected static final String MS_TYPE = "Windows-MY";
protected static final String MS_ERROR_LOAD = "Error on load a KeyStore from SunMSCAPI";
private CallbackHandler callback;
@Override
public KeyStore getKeyStore() {
try {
KeyStore result = KeyStore.getInstance(MSKeyStoreLoader.MS_TYPE, MSKeyStoreLoader.MS_PROVIDER);
result.load(null, null);
fixAliases(result);
return result;
} catch (Throwable error) {
throw new KeyStoreLoaderException(MSKeyStoreLoader.MS_ERROR_LOAD, error);
}
}
@Override
public void setCallbackHandler(CallbackHandler callback) {
this.callback = callback;
}
/**
* Implementacao do metodo de contorno para evitar a duplicidade de
* certificados, conforme descrito em
* <http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6672015>
*
* @param keyStore
*/
private void fixAliases(KeyStore keyStore) {
Field field;
KeyStoreSpi keyStoreVeritable;
try {
field = keyStore.getClass().getDeclaredField("keyStoreSpi");
field.setAccessible(true);
keyStoreVeritable = (KeyStoreSpi) field.get(keyStore);
/**
* Atualização 26/07/2016: o bug 6672015 foi agrupado no bug 6483657 e
* resolvido na build 101 do Java 1.8. (http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6483657)
*/
field = keyStoreVeritable.getClass().getEnclosingClass().getDeclaredField("entries");
field.setAccessible(true);
if(field.get(keyStoreVeritable) instanceof Map) return;
if ("sun.security.mscapi.KeyStore$MY".equals(keyStoreVeritable.getClass().getName())) {
Collection entries;
String alias, hashCode;
X509Certificate[] certificates;
field = keyStoreVeritable.getClass().getEnclosingClass().getDeclaredField("entries");
field.setAccessible(true);
entries = (Collection) field.get(keyStoreVeritable);
for (Object entry : entries) {
field = entry.getClass().getDeclaredField("certChain");
field.setAccessible(true);
certificates = (X509Certificate[]) field.get(entry);
hashCode = Integer.toString(certificates[0].hashCode());
field = entry.getClass().getDeclaredField("alias");
field.setAccessible(true);
alias = (String) field.get(entry);
if (!alias.equals(hashCode)) {
field.set(entry, alias.concat(" - ").concat(hashCode));
}
}
}
} catch (Exception exception) {
System.err.println(exception);
exception.printStackTrace();
}
}
}