/*
*
* Copyright (c) 2013 - 2017 Lijun Liao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3
* as published by the Free Software Foundation with the addition of the
* following permission added to Section 15 as permitted in Section 7(a):
*
* FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
* THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
* OF THIRD PARTY RIGHTS.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License.
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial activities involving the XiPKI software without
* disclosing the source code of your own applications.
*
* For more information, please contact Lijun Liao at this
* address: lijun.liao@gmail.com
*/
package org.xipki.commons.security.pkcs11.iaik;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.commons.common.util.LogUtil;
import org.xipki.commons.common.util.ParamUtil;
import org.xipki.commons.password.PasswordResolverException;
import org.xipki.commons.security.exception.P11TokenException;
import org.xipki.commons.security.pkcs11.AbstractP11Module;
import org.xipki.commons.security.pkcs11.P11Module;
import org.xipki.commons.security.pkcs11.P11ModuleConf;
import org.xipki.commons.security.pkcs11.P11Slot;
import org.xipki.commons.security.pkcs11.P11SlotIdentifier;
import iaik.pkcs.pkcs11.DefaultInitializeArgs;
import iaik.pkcs.pkcs11.Module;
import iaik.pkcs.pkcs11.Slot;
import iaik.pkcs.pkcs11.SlotInfo;
import iaik.pkcs.pkcs11.TokenException;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;
/**
* @author Lijun Liao
* @since 2.0.0
*/
public class IaikP11Module extends AbstractP11Module {
private static final Logger LOG = LoggerFactory.getLogger(IaikP11Module.class);
private Module module;
private IaikP11Module(final Module module, final P11ModuleConf moduleConf)
throws P11TokenException {
super(moduleConf);
this.module = ParamUtil.requireNonNull("module", module);
Slot[] slotList;
try {
slotList = module.getSlotList(Module.SlotRequirement.ALL_SLOTS);
} catch (Throwable th) {
final String msg = "could not getSlotList of module " + moduleConf.getName();
LogUtil.error(LOG, th, msg);
throw new P11TokenException(msg);
}
final int size = (slotList == null) ? 0 : slotList.length;
if (size == 0) {
throw new P11TokenException("no slot could be found");
}
for (int i = 0; i < size; i++) {
Slot slot = slotList[i];
SlotInfo slotInfo;
try {
slotInfo = slot.getSlotInfo();
} catch (TokenException ex) {
LOG.error("ignore slot[{}] (id={} with error", i, slot.getSlotID());
slotList[i] = null;
continue;
}
if (slotInfo.isTokenPresent()) {
slotList[i] = null;
LOG.info("ignore slot[{}] (id={} without token", i, slot.getSlotID());
}
}
StringBuilder msg = new StringBuilder();
Set<P11Slot> slots = new HashSet<>();
for (int i = 0; i < slotList.length; i++) {
Slot slot = slotList[i];
if (slot == null) {
continue;
}
P11SlotIdentifier slotId = new P11SlotIdentifier(i, slot.getSlotID());
if (!moduleConf.isSlotIncluded(slotId)) {
LOG.info("skipped slot {}", slotId);
continue;
}
if (LOG.isDebugEnabled()) {
msg.append("--------------------Slot ").append(i).append("--------------------\n");
msg.append("id: ").append(slot.getSlotID()).append("\n");
try {
msg.append(slot.getSlotInfo()).append("\n");
} catch (TokenException ex) {
msg.append("error: " + ex.getMessage());
}
}
List<char[]> pwd;
try {
pwd = moduleConf.getPasswordRetriever().getPassword(slotId);
} catch (PasswordResolverException ex) {
throw new P11TokenException("PasswordResolverException: " + ex.getMessage(), ex);
}
P11Slot p11Slot = new IaikP11Slot(moduleConf.getName(), slotId, slot,
moduleConf.isReadOnly(), moduleConf.getUserType(), pwd,
moduleConf.getMaxMessageSize(), moduleConf.getP11MechanismFilter());
slots.add(p11Slot);
}
if (LOG.isDebugEnabled()) {
LOG.debug("{}", msg);
}
setSlots(slots);
}
public static P11Module getInstance(final P11ModuleConf moduleConf) throws P11TokenException {
ParamUtil.requireNonNull("moduleConf", moduleConf);
Module module;
try {
module = Module.getInstance(moduleConf.getNativeLibrary());
} catch (IOException ex) {
final String msg = "could not load the PKCS#11 module " + moduleConf.getName();
LogUtil.error(LOG, ex, msg);
throw new P11TokenException(msg, ex);
}
try {
module.initialize(new DefaultInitializeArgs());
} catch (PKCS11Exception ex) {
if (ex.getErrorCode() != PKCS11Constants.CKR_CRYPTOKI_ALREADY_INITIALIZED) {
LogUtil.error(LOG, ex);
close(moduleConf.getName(), module);
throw new P11TokenException(ex.getMessage(), ex);
} else {
LOG.info("PKCS#11 module already initialized");
if (LOG.isInfoEnabled()) {
try {
LOG.info("pkcs11.getInfo():\n{}", module.getInfo());
} catch (TokenException e2) {
LOG.debug("module.getInfo()", e2);
}
}
}
} catch (Throwable th) {
LogUtil.error(LOG, th, "unexpected Exception");
close(moduleConf.getName(), module);
throw new P11TokenException(th.getMessage());
}
return new IaikP11Module(module, moduleConf);
}
@Override
public void close() {
for (P11SlotIdentifier slotId : getSlotIdentifiers()) {
try {
getSlot(slotId).close();
} catch (Throwable th) {
LogUtil.error(LOG, th, "could not close PKCS#11 slot " + slotId);
}
}
close(conf.getNativeLibrary(), module);
}
private static void close(final String modulePath, final Module module) {
if (module == null) {
return;
}
LOG.info("close", "close pkcs11 module: {}", modulePath);
try {
module.finalize(null);
} catch (Throwable th) {
LogUtil.error(LOG, th, "could not close module " + modulePath);
}
}
}