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

org.xipki.security.pkcs11.P11SignerFactory 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.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.security.ConcurrentContentSigner;
import org.xipki.security.SecurityFactory;
import org.xipki.security.SignerConf;
import org.xipki.security.SignerFactory;
import org.xipki.security.XiSecurityException;
import org.xipki.security.util.AlgorithmUtil;
import org.xipki.util.Hex;
import org.xipki.util.LogUtil;
import org.xipki.util.ObjectCreationException;

/**
 * {@link SignerFactory} for PKCS#11 token.
 *
 * @author Lijun Liao
 * @since 2.0.0
 */

// CHECKSTYLE:SKIP
public class P11SignerFactory implements SignerFactory {

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

  private static final String TYPE = "pkcs11";

  private static final Set types = Collections.unmodifiableSet(
      new HashSet<>(Arrays.asList(TYPE)));

  private P11CryptServiceFactory p11CryptServiceFactory;

  private SecurityFactory securityFactory;

  public void setP11CryptServiceFactory(P11CryptServiceFactory p11CryptServiceFactory) {
    this.p11CryptServiceFactory = p11CryptServiceFactory;
  }

  public void setSecurityFactory(SecurityFactory securityFactory) {
    this.securityFactory = securityFactory;
  }

  @Override
  public Set getSupportedSignerTypes() {
    return types;
  }

  @Override
  public boolean canCreateSigner(String type) {
    return types.contains(type.toLowerCase());
  }

  @Override
  public ConcurrentContentSigner newSigner(String type, SignerConf conf,
      X509Certificate[] certificateChain) throws ObjectCreationException {
    if (!TYPE.equalsIgnoreCase(type)) {
      throw new ObjectCreationException("unknown signer type " + type);
    }

    if (p11CryptServiceFactory == null) {
      throw new ObjectCreationException("p11CryptServiceFactory is not set");
    }

    if (securityFactory == null) {
      throw new ObjectCreationException("securityFactory is not set");
    }

    String str = conf.getConfValue("parallelism");
    int parallelism = securityFactory.getDfltSignerParallelism();
    if (str != null) {
      try {
        parallelism = Integer.parseInt(str);
      } catch (NumberFormatException ex) {
        throw new ObjectCreationException("invalid parallelism " + str);
      }

      if (parallelism < 1) {
        throw new ObjectCreationException("invalid parallelism " + str);
      }
    }

    String moduleName = conf.getConfValue("module");
    str = conf.getConfValue("slot");
    Integer slotIndex = (str == null) ? null : Integer.parseInt(str);

    str = conf.getConfValue("slot-id");
    Long slotId = (str == null) ? null : Long.parseLong(str);

    if ((slotIndex == null && slotId == null)
        || (slotIndex != null && slotId != null)) {
      throw new ObjectCreationException(
          "exactly one of slot (index) and slot-id must be specified");
    }

    String keyLabel = conf.getConfValue("key-label");
    str = conf.getConfValue("key-id");
    byte[] keyId = null;
    if (str != null) {
      keyId = Hex.decode(str);
    }

    if ((keyId == null && keyLabel == null) || (keyId != null && keyLabel != null)) {
      throw new ObjectCreationException("exactly one of key-id and key-label must be specified");
    }

    P11CryptService p11Service;
    P11Slot slot;
    try {
      p11Service = p11CryptServiceFactory.getP11CryptService(moduleName);
      P11Module module = p11Service.getModule();
      P11SlotIdentifier p11SlotId;
      if (slotId != null) {
        p11SlotId = module.getSlotIdForId(slotId);
      } else if (slotIndex != null) {
        p11SlotId = module.getSlotIdForIndex(slotIndex);
      } else {
        throw new IllegalStateException("should not reach here");
      }
      slot = module.getSlot(p11SlotId);
    } catch (P11TokenException | XiSecurityException ex) {
      throw new ObjectCreationException(ex.getMessage(), ex);
    }

    P11IdentityId identityId = slot.getIdentityId(keyId, keyLabel);
    if (identityId == null) {
      String str2 = (keyId != null) ? "id " + Hex.encode(keyId) : "label " + keyLabel;
      throw new ObjectCreationException("cound not find identity with " + str2);
    }

    try {
      AlgorithmIdentifier macAlgId = null;
      String algoName = conf.getConfValue("algo");
      if (algoName != null) {
        try {
          macAlgId = AlgorithmUtil.getMacAlgId(algoName);
        } catch (NoSuchAlgorithmException ex) {
          // do nothing
        }
      }

      if (macAlgId != null) {
        P11MacContentSignerBuilder signerBuilder = new P11MacContentSignerBuilder(
            p11Service, identityId);
        return signerBuilder.createSigner(macAlgId, parallelism);
      } else {
        AlgorithmIdentifier signatureAlgId;
        if (conf.getHashAlgo() == null) {
          signatureAlgId = AlgorithmUtil.getSigAlgId(null, conf);
        } else {
          PublicKey pubKey = slot.getIdentity(identityId.getKeyId()).getPublicKey();
          signatureAlgId = AlgorithmUtil.getSigAlgId(pubKey, conf);
        }

        P11ContentSignerBuilder signerBuilder = new P11ContentSignerBuilder(p11Service,
            securityFactory, identityId, certificateChain);
        return signerBuilder.createSigner(signatureAlgId, parallelism);
      }
    } catch (P11TokenException | NoSuchAlgorithmException | XiSecurityException ex) {
      throw new ObjectCreationException(ex.getMessage(), ex);
    }
  } // method newSigner

  @Override
  public void refreshToken(String type) throws XiSecurityException {
    if (!TYPE.equalsIgnoreCase(type)) {
      // Nothing to do
      return;
    }

    Set errorModules = new HashSet<>(2);
    for (String name : p11CryptServiceFactory.getModuleNames()) {
      try {
        p11CryptServiceFactory.getP11CryptService(name).refresh();
      } catch (P11TokenException ex) {
        LogUtil.error(LOG, ex, "could not refresh PKCS#11 module " + name);
        errorModules.add(name);
      }
    }

    if (!errorModules.isEmpty()) {
      throw new XiSecurityException("could not refreshed modules " + errorModules);
    }
  } // method refreshToken

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy