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

org.xipki.security.pkcs11.P11ModuleConf 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;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.password.PasswordResolver;
import org.xipki.password.PasswordResolverException;
import org.xipki.util.Args;
import org.xipki.util.CollectionUtil;
import org.xipki.util.InvalidConfException;
import org.xipki.util.StringUtil;

import iaik.pkcs.pkcs11.constants.Functions;
import iaik.pkcs.pkcs11.constants.PKCS11Constants;

/**
 * TODO.
 * @author Lijun Liao
 *
 */
public class P11ModuleConf {

  private static class P11SlotIdFilter {

    private final Integer index;

    private final Long id;

    P11SlotIdFilter(Integer index, Long id) {
      if (index == null && id == null) {
        throw new IllegalArgumentException("at least one of index and id may not be null");
      }
      this.index = index;
      this.id = id;
    }

    boolean match(P11SlotIdentifier slotId) {
      if (index != null) {
        if (index.intValue() != slotId.getIndex()) {
          return false;
        }
      }

      if (id != null) {
        if (id.longValue() != slotId.getId()) {
          return false;
        }
      }

      return true;
    }

  }

  private static final class P11SingleMechanismFilter {

    private final Set slots;

    private final Collection mechanisms;

    private P11SingleMechanismFilter(Set slots, Collection mechanisms) {
      this.slots = slots;
      this.mechanisms = CollectionUtil.isEmpty(mechanisms) ? null : mechanisms;
    }

    public boolean match(P11SlotIdentifier slot) {
      if (slots == null) {
        return true;
      }
      for (P11SlotIdFilter m : slots) {
        if (m.match(slot)) {
          return true;
        }
      }

      return false;
    }

    public boolean isMechanismSupported(long mechanism) {
      if (mechanisms == null) {
        return true;
      }

      return mechanisms.contains(mechanism);
    }

  } // class SingleFilter

  public static class P11MechanismFilter {

    private final List singleFilters;

    P11MechanismFilter() {
      singleFilters = new LinkedList<>();
    }

    void addEntry(Set slots, Collection mechanisms) {
      Args.notNull(mechanisms, "mechanismis");
      singleFilters.add(new P11SingleMechanismFilter(slots, mechanisms));
    }

    void addAcceptAllEntry(Set slots) {
      singleFilters.add(new P11SingleMechanismFilter(slots, null));
    }

    public boolean isMechanismPermitted(P11SlotIdentifier slotId, long mechanism) {
      Args.notNull(slotId, "slotId");
      if (CollectionUtil.isEmpty(singleFilters)) {
        return true;
      }

      for (P11SingleMechanismFilter sr : singleFilters) {
        if (sr.match(slotId)) {
          return sr.isMechanismSupported(mechanism);
        }
      }

      return true;
    }

  }

  public static class P11PasswordsRetriever {

    private static final class P11SinglePasswordRetriever {

      private final Set slots;

      private final List passwords;

      private P11SinglePasswordRetriever(Set slots, List passwords) {
        this.slots = slots;
        this.passwords = CollectionUtil.isEmpty(passwords) ? null : passwords;
      }

      public boolean match(P11SlotIdentifier slot) {
        if (slots == null) {
          return true;
        }
        for (P11SlotIdFilter m : slots) {
          if (m.match(slot)) {
            return true;
          }
        }

        return false;
      }

      public List getPasswords(PasswordResolver passwordResolver)
              throws PasswordResolverException {
        if (passwords == null) {
          return null;
        }

        List ret = new ArrayList(passwords.size());
        for (String password : passwords) {
          if (passwordResolver == null) {
            ret.add(password.toCharArray());
          } else {
            ret.add(passwordResolver.resolvePassword(password));
          }
        }

        return ret;
      }

    } // class SingleRetriever

    private final List singleRetrievers;
    private PasswordResolver passwordResolver;

    P11PasswordsRetriever() {
      singleRetrievers = new LinkedList<>();
    }

    void addPasswordEntry(Set slots, List passwords) {
      singleRetrievers.add(new P11SinglePasswordRetriever(slots, passwords));
    }

    public List getPassword(P11SlotIdentifier slotId) throws PasswordResolverException {
      Args.notNull(slotId, "slotId");
      if (CollectionUtil.isEmpty(singleRetrievers)) {
        return null;
      }

      for (P11SinglePasswordRetriever sr : singleRetrievers) {
        if (sr.match(slotId)) {
          return sr.getPasswords(passwordResolver);
        }
      }

      return null;
    }

    public PasswordResolver getPasswordResolver() {
      return passwordResolver;
    }

    public void setPasswordResolver(PasswordResolver passwordResolver) {
      this.passwordResolver = passwordResolver;
    }

  }

  public static class P11NewObjectConf {

    private boolean ignoreLabel;

    private int idLength = 8;

    private Set setCertObjectAttributes;

    public P11NewObjectConf(Pkcs11conf.NewObjectConf conf) {
      Boolean bb = conf.getIgnoreLabel();
      this.ignoreLabel = (bb == null) ? false : bb.booleanValue();

      Integer ii = conf.getIdLength();
      this.idLength = (ii == null) ? 8 : ii.intValue();

      List attrs = conf.getCertAttributes();
      Set set = new HashSet<>();
      if (attrs != null) {
        for (Pkcs11conf.NewObjectConf.CertAttribute attr : attrs) {
          set.add(attr.getPkcs11CkaCode());
        }
      }
      this.setCertObjectAttributes = Collections.unmodifiableSet(set);
    }

    public P11NewObjectConf() {
      this.setCertObjectAttributes = Collections.emptySet();
    }

    public boolean isIgnoreLabel() {
      return ignoreLabel;
    }

    public void setIgnoreLabel(boolean ignoreLabel) {
      this.ignoreLabel = ignoreLabel;
    }

    public int getIdLength() {
      return idLength;
    }

    public void setIdLength(int idLength) {
      this.idLength = idLength;
    }

    public Set getSetCertObjectAttributes() {
      return setCertObjectAttributes;
    }

    public void setSetCertObjectAttributes(Set setCertObjectAttributes) {
      this.setCertObjectAttributes =
          Args.notNull(setCertObjectAttributes, "setCertObjectAttributes");
    }

  }

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

  private final String name;

  private final String type;

  private final String nativeLibrary;

  private final boolean readOnly;

  private final Set excludeSlots;

  private final Set includeSlots;

  private final P11PasswordsRetriever passwordRetriever;

  private final P11MechanismFilter mechanismFilter;

  private final int maxMessageSize;

  private final long userType;

  private final P11NewObjectConf newObjectConf;

  public P11ModuleConf(Pkcs11conf.Module moduleType, List mechanismSets,
      PasswordResolver passwordResolver) throws InvalidConfException {
    Args.notNull(moduleType, "moduleType");
    Args.notEmpty(mechanismSets, "mechanismSets");
    this.name = moduleType.getName();
    this.readOnly = moduleType.isReadonly();

    String userTypeStr = moduleType.getUser().toUpperCase();
    if ("CKU_USER".equals(userTypeStr)) {
      this.userType = PKCS11Constants.CKU_USER;
    } else if ("CKU_SO".equals(userTypeStr)) {
      this.userType = PKCS11Constants.CKU_SO;
    } else if ("CKU_CONTEXT_SPECIFIC".equals(userTypeStr)) {
      this.userType = PKCS11Constants.CKU_CONTEXT_SPECIFIC;
    } else {
      try {
        if (userTypeStr.startsWith("0X")) {
          this.userType = Long.parseLong(userTypeStr.substring(2), 16);
        } else {
          this.userType = Long.parseLong(userTypeStr);
        }
      } catch (NumberFormatException ex) {
        throw new InvalidConfException("invalid user " + userTypeStr);
      }
    }

    this.maxMessageSize = moduleType.getMaxMessageSize();
    this.type = moduleType.getType();
    if (maxMessageSize < 128) {
      throw new InvalidConfException("invalid maxMessageSize (< 128): " + maxMessageSize);
    }

    // parse mechanismSets
    Map> mechanismSetsMap = new HashMap<>(mechanismSets.size() * 3 / 2);
    for (Pkcs11conf.MechanismSet m : mechanismSets) {
      String name = m.getName();
      if (mechanismSetsMap.containsKey(name)) {
        throw new InvalidConfException("Duplication mechanismSets named " + name);
      }

      Set mechanisms = new HashSet<>();
      for (String mechStr : m.getMechanisms()) {
        mechStr = mechStr.trim().toUpperCase();
        if (mechStr.equals("ALL")) {
          mechanisms = null; // accept all mechanisms
          break;
        }

        Long mech = null;
        if (mechStr.startsWith("CKM_")) {
          mech = Functions.mechanismStringToCode(mechStr);
        } else {
          int radix = 10;
          if (mechStr.startsWith("0X")) {
            radix = 16;
            mechStr = mechStr.substring(2);
          }

          if (mechStr.endsWith("UL")) {
            mechStr = mechStr.substring(0, mechStr.length() - 2);
          } else if (mechStr.endsWith("L")) {
            mechStr = mechStr.substring(0, mechStr.length() - 1);
          }

          try {
            mech = Long.parseLong(mechStr, radix);
          } catch (NumberFormatException ex) {// CHECKSTYLE:SKIP
          }
        }

        if (mech == null) {
          LOG.warn("skipped unknown mechanism '" + mechStr + "'");
        } else {
          mechanisms.add(mech);
        }
      }

      mechanismSetsMap.put(name, mechanisms);
    }

    // Mechanism filter
    mechanismFilter = new P11MechanismFilter();

    List mechFilters = moduleType.getMechanismFilters();
    if (mechFilters != null && CollectionUtil.isNonEmpty(mechFilters)) {
      for (Pkcs11conf.MechanimFilter filterType : mechFilters) {
        Set slots = getSlotIdFilters(filterType.getSlots());
        String mechanismSetName = filterType.getMechanismSet();

        if (!mechanismSetsMap.containsKey(mechanismSetName)) {
          throw new InvalidConfException("MechanismSet '" +  mechanismSetName
              + "' is not defined");
        }

        Set mechanisms = mechanismSetsMap.get(mechanismSetName);
        if (mechanisms == null) {
          mechanismFilter.addAcceptAllEntry(slots);
        } else {
          mechanismFilter.addEntry(slots, mechanisms);
        }
      }
    }

    // Password retriever
    passwordRetriever = new P11PasswordsRetriever();
    List passwordsList = moduleType.getPasswordSets();
    if (passwordsList != null && CollectionUtil.isNonEmpty(passwordsList)) {
      passwordRetriever.setPasswordResolver(passwordResolver);
      for (Pkcs11conf.PasswordSet passwordType : passwordsList) {
        Set slots = getSlotIdFilters(passwordType.getSlots());
        passwordRetriever.addPasswordEntry(slots, new ArrayList<>(passwordType.getPasswords()));
      }
    }

    includeSlots = getSlotIdFilters(moduleType.getIncludeSlots());
    excludeSlots = getSlotIdFilters(moduleType.getExcludeSlots());

    final String osName = System.getProperty("os.name").toLowerCase();
    String nativeLibraryPath = null;
    for (Pkcs11conf.NativeLibrary library : moduleType.getNativeLibraries()) {
      List osNames = library.getOperationSystems();
      if (CollectionUtil.isEmpty(osNames)) {
        nativeLibraryPath = library.getPath();
      } else {
        for (String entry : osNames) {
          if (osName.contains(entry.toLowerCase())) {
            nativeLibraryPath = library.getPath();
            break;
          }
        }
      }

      if (nativeLibraryPath != null) {
        break;
      }
    } // end for (NativeLibraryType library)

    if (nativeLibraryPath == null) {
      throw new InvalidConfException("could not find PKCS#11 library for OS " + osName);
    }
    this.nativeLibrary = nativeLibraryPath;

    this.newObjectConf = (moduleType.getNewObjectConf() == null) ? new P11NewObjectConf()
        : new P11NewObjectConf(moduleType.getNewObjectConf());
  }

  public String getName() {
    return name;
  }

  public String getType() {
    return type;
  }

  public String getNativeLibrary() {
    return nativeLibrary;
  }

  public int getMaxMessageSize() {
    return maxMessageSize;
  }

  public boolean isReadOnly() {
    return readOnly;
  }

  public long getUserType() {
    return userType;
  }

  public P11PasswordsRetriever getPasswordRetriever() {
    return passwordRetriever;
  }

  public boolean isSlotIncluded(P11SlotIdentifier slotId) {
    Args.notNull(slotId, "slotId");
    boolean included;
    if (CollectionUtil.isEmpty(includeSlots)) {
      included = true;
    } else {
      included = false;
      for (P11SlotIdFilter entry : includeSlots) {
        if (entry.match(slotId)) {
          included = true;
          break;
        }
      }
    }

    if (!included) {
      return false;
    }

    if (CollectionUtil.isEmpty(excludeSlots)) {
      return included;
    }

    for (P11SlotIdFilter entry : excludeSlots) {
      if (entry.match(slotId)) {
        return false;
      }
    }

    return true;
  }

  public P11MechanismFilter getP11MechanismFilter() {
    return mechanismFilter;
  }

  public P11NewObjectConf getP11NewObjectConf() {
    return newObjectConf;
  }

  private static Set getSlotIdFilters(List slotTypes)
      throws InvalidConfException {
    if (CollectionUtil.isEmpty(slotTypes)) {
      return null;
    }

    Set filters = new HashSet<>();
    for (Pkcs11conf.Slot slotType : slotTypes) {
      Long slotId = null;
      if (slotType.getId() != null) {
        String str = slotType.getId().trim();
        try {
          slotId = StringUtil.startsWithIgnoreCase(str, "0X")
              ? Long.parseLong(str.substring(2), 16) : Long.parseLong(str);
        } catch (NumberFormatException ex) {
          String message = "invalid slotId '" + str + "'";
          LOG.error(message);
          throw new InvalidConfException(message);
        }
      }
      filters.add(new P11SlotIdFilter(slotType.getIndex(), slotId));
    }

    return filters;
  }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy