All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xipki.security.pkcs11.iaik.IaikP11Module Maven / Gradle / Ivy

/*
 *
 * Copyright (c) 2013 - 2019 Lijun Liao
 *
 * Licensed 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.xipki.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.password.PasswordResolverException;
import org.xipki.security.pkcs11.P11Module;
import org.xipki.security.pkcs11.P11ModuleConf;
import org.xipki.security.pkcs11.P11Slot;
import org.xipki.security.pkcs11.P11SlotIdentifier;
import org.xipki.security.pkcs11.P11TokenException;
import org.xipki.util.Args;
import org.xipki.util.LogUtil;
import org.xipki.util.StringUtil;

import iaik.pkcs.pkcs11.DefaultInitializeArgs;
import iaik.pkcs.pkcs11.Info;
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;

/**
 * {@link P11Module} based on the IAIK PKCS#11 wrapper.
 *
 * @author Lijun Liao
 * @since 2.0.0
 */

public class IaikP11Module extends P11Module {

  public enum Vendor {

    YUBIKEY,
    GENERAL

  }

  public static final String TYPE = "native";

  private static final Logger LOG = LoggerFactory.getLogger(IaikP11Module.class);

  private Module module;

  private String description;

  private IaikP11Module(Module module, P11ModuleConf moduleConf) throws P11TokenException {
    super(moduleConf);
    this.module = Args.notNull(module, "module");

    String library = moduleConf.getNativeLibrary();
    Vendor vendor;
    if (library.contains("ykcs11")) {
      vendor = Vendor.YUBIKEY;
    } else {
      vendor = Vendor.GENERAL;
    }

    try {
      Info info = module.getInfo();
      this.description = StringUtil.concatObjects("PKCS#11 IAIK",
          "\n\tPath: ", library,
          "\n\tCryptoki Version: ", info.getCryptokiVersion(),
          "\n\tManufacturerID: ", info.getManufacturerID(),
          "\n\tLibrary Description: ", info.getLibraryDescription(),
          "\n\tLibrary Version: ", info.getLibraryVersion());

    } catch (TokenException ex) {
      this.description = StringUtil.concatObjects("PKCS#11 IAIK",
          "\n\tPath", moduleConf.getNativeLibrary());
    }

    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 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 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(), moduleConf.getP11NewObjectConf(), vendor);

      slots.add(p11Slot);
    }

    if (LOG.isDebugEnabled()) {
      LOG.debug("{}", msg);
    }

    setSlots(slots);
  } // constructor

  public static P11Module getInstance(P11ModuleConf moduleConf) throws P11TokenException {
    Args.notNull(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) {
      LOG.error("unexpected Exception", th);
      close(moduleConf.getName(), module);
      throw new P11TokenException(th.getMessage());
    }

    return new IaikP11Module(module, moduleConf);
  } // method getInstance

  @Override
  public String getDescription() {
    return description;
  }

  @Override
  public void close() {
    for (P11SlotIdentifier slotId : getSlotIds()) {
      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(String modulePath, 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);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy