
org.dihedron.crypto.providers.smartcard.SmartCardProviderFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of crypto Show documentation
Show all versions of crypto Show documentation
Set of classes to support cryptography, including smart card detection, encryption, decription and signing.
The newest version!
/**
* Copyright (c) 2012-2014, Andrea Funto'. All rights reserved.
*
* This file is part of the Crypto library ("Crypto").
*
* Crypto is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Crypto 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Crypto. If not, see .
*/
package org.dihedron.crypto.providers.smartcard;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Provider;
import org.dihedron.core.Platform;
import org.dihedron.crypto.exceptions.ProviderException;
import org.dihedron.crypto.exceptions.SmartCardException;
import org.dihedron.crypto.exceptions.UnavailableDriverException;
import org.dihedron.crypto.providers.ProviderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Smart card securoty provider factory class: helps install a security provider
* for PKCS#11 providers, once the reader in which the PKCS#11 token is available
* has been detected and information about the smart card (in the form of a
* {@code SmartCard} database entry) has been retrieved.
*
* @author Andrea Funto'
*/
public class SmartCardProviderFactory extends ProviderFactory {
/**
* The logger
*/
private static final Logger logger = LoggerFactory.getLogger(SmartCardProviderFactory.class);
/**
* Installs a new PKCS#11 security provider supporting the smart card model
* and make specified in the initialisation traits, which must provide a
* reference to the smart card reader in which the card is present and to
* the database entry corresponding to the card's model.
*
* @param traits
* the characteristics traits of the smart card whose capabilities the
* provider will expose.
* @return
* the new {@code Provider}, or {@code null} if none valid could be installed.
* @throws SmartCardException
* @throws UnavailableDriverException
*/
@Override
public Provider acquire(SmartCardTraits traits) throws ProviderException {
String name = "SmartCard-" + traits.getSmartCard().getATR() + "-" + traits.getReader().getSlot();
logger.info("installing PKCS#11 provider '{}'...", name);
InputStream stream = null;
try {
// find the driver on disk
File driver = traits.getSmartCard().getDriver(Platform.getCurrent());
if (driver != null) {
logger.info("... file driver is available on disk at '{}'", driver.getAbsolutePath());
// prepare configuration as stream
Configuration configuration = new Configuration()
.setName(name)
.setLibrary(driver)
.setOnCardHashing(traits.isHashOnCard())
.setSlot(traits.getReader().getSlot());
logger.info("... provider configuration: \n{}", configuration);
stream = configuration.toStream();
// load the class dynamically (to avoid errors when not running on Sun JDK)
Class> clazz = Class.forName(SmartCardTraits.SUN_PKCS11_PROVIDER_CLASS);
Constructor> constructor = clazz.getConstructor(String.class, InputStream.class);
Provider provider = (Provider) constructor.newInstance(name + "-configuration", stream);
logger.info("... PKCS#11 provider '{}' loaded!", provider.getName());
return provider;
} else {
logger.error("driver for smartcard '{}' and platform '{}' not available on disk", traits.getSmartCard().getATR(), Platform.getCurrent());
throw new UnavailableDriverException("No valid smartcard PKCS#11 driver could be found on disk");
}
} catch (ClassNotFoundException e) {
logger.error("Sun PKCS#11 supporting classes not available", e);
throw new SmartCardException("Sun PKCS#11 supporting classes not available", e);
} catch (NoSuchMethodException e) {
logger.error("no constructor with (String, InputStream) parameter for Sun PKCS#11 available", e);
throw new SmartCardException("no constructor with (String, InputStream) parameter for Sun PKCS#11 available", e);
} catch (SecurityException e) {
logger.error("security exception accessing Sun PKCS#11 constructor", e);
throw new SmartCardException("security exception accessing Sun PKCS#11 constructor", e);
} catch (InstantiationException e) {
logger.error("error invoking Sun PKCS#11 constructor", e);
throw new SmartCardException("error invoking Sun PKCS#11 constructor", e);
} catch (IllegalAccessException e) {
logger.error("error invoking inaccessible Sun PKCS#11 constructor", e);
throw new SmartCardException("error invoking inaccessible Sun PKCS#11 constructor", e);
} catch (IllegalArgumentException e) {
logger.error("illegal argument to Sun PKCS#11 constructor", e);
throw new SmartCardException("illegal argument to Sun PKCS#11 constructor", e);
} catch (InvocationTargetException e) {
logger.error("generic error invoking Sun PKCS#11 constructor", e);
throw new SmartCardException("generic error invoking Sun PKCS#11 constructor", e);
} finally {
if(stream != null) {
try {
stream.close();
} catch (IOException e) {
logger.warn("error closing PKCS#11 provider configuration input stream", e);
}
}
}
}
/**
* Uninstalls the given provider; smart cards instantiate a new provider for
* each different smart card, in order to support multiple initialisation
* parameters, and these custom providers need to be uninstalled once one is
* done using them.
*
* @param provider
* the provider to uninstall.
*/
@Override
public void release(Provider provider) {
if(provider != null) {
try {
if(provider.getClass().getName().equals(SmartCardTraits.SUN_PKCS11_PROVIDER_CLASS)) {
logger.info("Sun PKCS#11 provider detected, trying to log out...");
Method logout = null;
Class> clazz = provider.getClass();
while(clazz != null && clazz != Object.class && logout == null) {
logout = clazz.getDeclaredMethod("logout");
clazz = clazz.getSuperclass();
}
if(logout != null) {
logger.trace("... invoking logout() on provider");
logout.invoke(provider);
logger.info("... logged out of provider");
}
}
} catch(NoSuchMethodException e) {
logger.error("no method logout() on Sun PKCS#11 provider", e);
} catch (IllegalAccessException e) {
logger.error("illegal access to method logout() on Sun PKCS#11 provider", e);
} catch (IllegalArgumentException e) {
logger.error("illegal arguments to method logout() on Sun PKCS#11 provider", e);
} catch (InvocationTargetException e) {
logger.error("error trying to invoke logout() method on Sun PKCS#11 provider", e);
}
}
}
/**
* Helper class to format a PKCS#11 configuration file.
*
* @author Andrea Funtò
*/
private static class Configuration {
/**
* The buffer holding the configuration.
*/
private StringBuilder buffer = null;
/**
* Constructor.
*/
Configuration() {
buffer = new StringBuilder();
}
/**
* Sets the PKCS#11 provider name into the configuration.
*
* @param name
* the PKCS#11 provider name.
* @return
* the object, for method chaining.
*/
Configuration setName(String name) {
buffer.append("name=").append(name).append("\n");
return this;
}
/**
* Adds the path to the supporting PKCS#11 driver to the configuration.
*
* @param driver
* the path to the supporting driver.
* @return
* the object, for method chaining.
* @throws IOException
*/
Configuration setLibrary(File driver) {
buffer.append("library=").append(driver.getAbsolutePath()).append("\n");
return this;
}
/**
* Adds the slot indication to the configuration; if none specified, by
* default the provider will assume the slot to be 0.
*
* @param slot
* the 0-based slot index.
* @return
* the object, for method chaining.
*/
Configuration setSlot(int slot) {
buffer.append("slot=").append(slot).append("\n");
return this;
}
/**
* Disables the mechanisms that perform hashing on the smart card; on-card
* digesting has proven to be slow, and faulty on some smart cards, so it's
* better to disable it and perform hashing in Java code.
*
* @return
* the object, for method chaining.
*/
Configuration setOnCardHashing(boolean enabled) {
if(!enabled) {
buffer.append("disabledMechanisms = {\n");
buffer.append(" CKM_SHA1_RSA_PKCS\n");
buffer.append(" CKM_SHA256_RSA_PKCS\n");
buffer.append(" CKM_SHA384_RSA_PKCS\n");
buffer.append(" CKM_SHA512_RSA_PKCS\n");
buffer.append("}\n");
}
return this;
}
@Override
public String toString() {
String configuration = buffer.toString();
logger.trace("PKCS#11 configuration:\n{}", configuration);
return configuration;
}
/**
* Returns the PKCS#11 configuration file as an input stream.
*
* @return
* the PKCS#11 file as an input stream.
*/
public InputStream toStream() {
return new ByteArrayInputStream(buffer.toString().getBytes());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy