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

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

/*
 *
 * Copyright (c) 2013 - 2020 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 iaik.pkcs.pkcs11.Mechanism;
import iaik.pkcs.pkcs11.*;
import iaik.pkcs.pkcs11.objects.*;
import iaik.pkcs.pkcs11.objects.Key.KeyType;
import iaik.pkcs.pkcs11.parameters.InitializationVectorParameters;
import iaik.pkcs.pkcs11.parameters.OpaqueParameters;
import iaik.pkcs.pkcs11.parameters.Parameters;
import iaik.pkcs.pkcs11.parameters.RSAPkcsPssParameters;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.security.EdECConstants;
import org.xipki.security.X509Cert;
import org.xipki.security.XiSecurityException;
import org.xipki.security.pkcs11.P11ModuleConf.P11NewObjectConf;
import org.xipki.security.pkcs11.P11Params;
import org.xipki.security.pkcs11.P11Slot.P11KeyUsage;
import org.xipki.security.pkcs11.P11Slot.P11NewKeyControl;
import org.xipki.security.pkcs11.P11TokenException;
import org.xipki.security.util.KeyUtil;
import org.xipki.security.util.X509Util;
import org.xipki.util.LogUtil;

import java.math.BigInteger;
import java.security.cert.CertificateException;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.*;

import static org.xipki.security.pkcs11.P11Slot.getDescription;
import static org.xipki.util.CollectionUtil.isEmpty;
import static org.xipki.util.CollectionUtil.isNotEmpty;

/**
 * IAIK PKCS#11 wrapper util.
 *
 * @author Lijun Liao
 * @since 2.0.0
 */
class IaikP11SlotUtil {

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

  static void singleLogin(Session session, long userType, char[] pin)
      throws P11TokenException {
    char[] tmpPin = pin;
    // some driver does not accept null PIN
    if (pin == null) {
      tmpPin = new char[]{};
    }

    String userTypeText = getUserTypeText(userType);
    try {
      session.login(userType, tmpPin);
      LOG.info("login successful as user " + userTypeText);
    } catch (TokenException ex) {
      // 0x100: user already logged in
      if (ex instanceof PKCS11Exception && ((PKCS11Exception) ex).getErrorCode() == 0x100) {
        LOG.info("user already logged in");
      } else {
        LOG.info("login failed as user " + userTypeText);
        throw new P11TokenException(
            "login failed as user " + userTypeText + ": " + ex.getMessage(), ex);
      }
    }
  } // method singleLogin

  private static String getUserTypeText(long userType) {
    if (userType == PKCS11Constants.CKU_SO) {
      return "CKU_SO";
    } else if (userType == PKCS11Constants.CKU_USER) {
      return "CKU_USER";
    } else if (userType == PKCS11Constants.CKU_CONTEXT_SPECIFIC) {
      return "CKU_CONTEXT_SPECIFIC";
    } else {
      return "VENDOR_" + userType;
    }
  }

  static byte[] digestKey(Session session, int digestLen, Mechanism mechanism, SecretKey key)
      throws TokenException {
    session.digestInit(mechanism);
    session.digestKey(key);
    byte[] digest = new byte[digestLen];
    session.digestFinal(digest, 0, digestLen);
    return digest;
  } // method digestKey0

  static Mechanism getMechanism(long mechanism, P11Params parameters)
      throws P11TokenException {
    Mechanism ret = Mechanism.get(mechanism);
    if (parameters == null) {
      return ret;
    }

    Parameters paramObj;
    if (parameters instanceof P11Params.P11RSAPkcsPssParams) {
      P11Params.P11RSAPkcsPssParams param = (P11Params.P11RSAPkcsPssParams) parameters;
      paramObj = new RSAPkcsPssParameters(param.getHashAlgorithm(),
          param.getMaskGenerationFunction(), param.getSaltLength());
    } else if (parameters instanceof P11Params.P11ByteArrayParams) {
      paramObj = new OpaqueParameters(((P11Params.P11ByteArrayParams) parameters).getBytes());
    } else if (parameters instanceof P11Params.P11IVParams) {
      paramObj = new InitializationVectorParameters(((P11Params.P11IVParams) parameters).getIV());
    } else {
      throw new P11TokenException("unknown P11Parameters " + parameters.getClass().getName());
    }

    ret.setParameters(paramObj);

    return ret;
  } // method getMechanism

  static X509PublicKeyCertificate getCertificateObject(Session session, byte[] keyId,
      char[] keyLabel)
          throws P11TokenException {
    X509PublicKeyCertificate[] certs = getCertificateObjects(session, keyId, keyLabel);

    if (isEmpty(certs)) {
      LOG.info("found no certificate identified by {}", getDescription(keyId, keyLabel));
      return null;
    }

    int size = certs.length;
    if (size > 1) {
      LOG.warn("found {} public key identified by {}, use the first one", size,
          getDescription(keyId, keyLabel));
    }

    return certs[0];
  } // method getCertificateObject

  static boolean checkSessionLoggedIn(Session session, long userType)
      throws P11TokenException {
    SessionInfo info;
    try {
      info = session.getSessionInfo();
    } catch (TokenException ex) {
      throw new P11TokenException(ex.getMessage(), ex);
    }
    if (LOG.isTraceEnabled()) {
      LOG.debug("SessionInfo: {}", info);
    }

    State state = info.getState();
    long deviceError = info.getDeviceError();

    LOG.debug("to be verified PKCS11Module: state = {}, deviceError: {}", state, deviceError);
    if (deviceError != 0) {
      LOG.error("deviceError {}", deviceError);
      return false;
    }

    boolean sessionLoggedIn;
    if (userType == PKCS11Constants.CKU_SO) {
      sessionLoggedIn = state.equals(State.RW_SO_FUNCTIONS);
    } else {
      sessionLoggedIn = state.equals(State.RW_USER_FUNCTIONS)
          || state.equals(State.RO_USER_FUNCTIONS);
    }

    LOG.debug("sessionLoggedIn: {}", sessionLoggedIn);
    return sessionLoggedIn;
  } // method checkSessionLoggedIn

  static byte[] value(ByteArrayAttribute attr) {
    return attr == null ? null : attr.getByteArrayValue();
  }

  static char[] value(CharArrayAttribute attr) {
    return attr == null ? null : attr.getCharArrayValue();
  }

  static String valueStr(CharArrayAttribute attr) {
    char[] chars = attr == null ? null : attr.getCharArrayValue();
    return chars == null ? null : new String(chars);
  }

  static List getObjects(Session session, Storage template)
      throws P11TokenException {
    return getObjects(session, template, 9999);
  }

  static List getObjects(Session session, Storage template, int maxNo)
      throws P11TokenException {
    List objList = new LinkedList<>();

    try {
      session.findObjectsInit(template);

      while (objList.size() < maxNo) {
        PKCS11Object[] foundObjects = session.findObjects(1);
        if (foundObjects == null || foundObjects.length == 0) {
          break;
        }

        for (PKCS11Object object : foundObjects) {
          logPkcs11ObjectAttributes("found object: ", object);
          objList.add((Storage) object);
        }
      }
    } catch (TokenException ex) {
      throw new P11TokenException(ex.getMessage(), ex);
    } finally {
      try {
        session.findObjectsFinal();
      } catch (Exception ex) {
        LogUtil.error(LOG, ex, "session.findObjectsFinal() failed");
      }
    }

    return objList;
  } // method getObjects

  static java.security.PublicKey generatePublicKey(PublicKey p11Key)
      throws XiSecurityException {
    if (p11Key instanceof RSAPublicKey) {
      RSAPublicKey rsaP11Key = (RSAPublicKey) p11Key;
      BigInteger exp = new BigInteger(1, value(rsaP11Key.getPublicExponent()));

      byte[] modBytes = value(rsaP11Key.getModulus());
      BigInteger mod = new BigInteger(1, modBytes);
      RSAPublicKeySpec keySpec = new RSAPublicKeySpec(mod, exp);
      try {
        return KeyUtil.generateRSAPublicKey(keySpec);
      } catch (InvalidKeySpecException ex) {
        throw new XiSecurityException(ex.getMessage(), ex);
      }
    } else if (p11Key instanceof DSAPublicKey) {
      DSAPublicKey dsaP11Key = (DSAPublicKey) p11Key;

      BigInteger prime = new BigInteger(1, value(dsaP11Key.getPrime())); // p
      BigInteger subPrime = new BigInteger(1, value(dsaP11Key.getSubprime())); // q
      BigInteger base = new BigInteger(1, value(dsaP11Key.getBase())); // g
      BigInteger value = new BigInteger(1, value(dsaP11Key.getValue())); // y
      DSAPublicKeySpec keySpec = new DSAPublicKeySpec(value, prime, subPrime, base);
      try {
        return KeyUtil.generateDSAPublicKey(keySpec);
      } catch (InvalidKeySpecException ex) {
        throw new XiSecurityException(ex.getMessage(), ex);
      }
    } else if (p11Key instanceof ECPublicKey) {
      ECPublicKey ecP11Key = (ECPublicKey) p11Key;
      long keyType = ecP11Key.getKeyType().getLongValue();
      byte[] ecParameters = value(ecP11Key.getEcdsaParams());
      byte[] encodedPoint = DEROctetString.getInstance(value(ecP11Key.getEcPoint())).getOctets();

      if (keyType == KeyType.EC_EDWARDS || keyType == KeyType.EC_MONTGOMERY) {
        ASN1ObjectIdentifier algOid = ASN1ObjectIdentifier.getInstance(ecParameters);
        if (keyType == KeyType.EC_EDWARDS) {
          if (!EdECConstants.isEdwardsCurve(algOid)) {
            throw new XiSecurityException("unknown Edwards curve OID " + algOid);
          }
        } else {
          if (!EdECConstants.isMontgomeryCurve(algOid)) {
            throw new XiSecurityException("unknown Montgomery curve OID " + algOid);
          }
        }
        SubjectPublicKeyInfo pkInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(algOid),
            encodedPoint);
        try {
          return KeyUtil.generatePublicKey(pkInfo);
        } catch (InvalidKeySpecException ex) {
          throw new XiSecurityException(ex.getMessage(), ex);
        }
      } else {
        try {
          return KeyUtil.createECPublicKey(ecParameters, encodedPoint);
        } catch (InvalidKeySpecException ex) {
          throw new XiSecurityException(ex.getMessage(), ex);
        }
      }
    } else {
      throw new XiSecurityException("unknown publicKey class " + p11Key.getClass().getName());
    }
  } // method generatePublicKey

  static X509Cert parseCert(X509PublicKeyCertificate p11Cert)
      throws P11TokenException {
    try {
      byte[] encoded = value(p11Cert.getValue());
      return X509Util.parseCert(encoded);
    } catch (CertificateException ex) {
      throw new P11TokenException("could not parse certificate: " + ex.getMessage(), ex);
    }
  } // method parseCert

  static List getAllCertificateObjects(Session session)
      throws P11TokenException {
    X509PublicKeyCertificate template = new X509PublicKeyCertificate();
    List tmpObjects = getObjects(session, template);

    List certs = new ArrayList<>(tmpObjects.size());
    for (PKCS11Object tmpObject : tmpObjects) {
      X509PublicKeyCertificate cert = (X509PublicKeyCertificate) tmpObject;
      certs.add(cert);
    }
    return certs;
  } // method getAllCertificateObjects

  static int removeObjects0(Session session, Storage template, String desc)
      throws P11TokenException {
    try {
      List objects = getObjects(session, template);
      for (Storage obj : objects) {
        session.destroyObject(obj);
      }
      return objects.size();
    } catch (TokenException ex) {
      LogUtil.error(LOG, ex, "could not remove " + desc);
      throw new P11TokenException(ex.getMessage(), ex);
    }
  } // method removeObjects

  static void setKeyAttributes(P11NewKeyControl control,
      PublicKey publicKey, PrivateKey privateKey, P11NewObjectConf newObjectConf) {
    if (privateKey != null) {
      privateKey.getToken().setBooleanValue(true);
      if (newObjectConf.isIgnoreLabel()) {
        if (control.getLabel() != null) {
          LOG.warn("label is set, but ignored: '{}'", control.getLabel());
        }
      } else {
        privateKey.getLabel().setCharArrayValue(control.getLabel().toCharArray());
      }
      privateKey.getPrivate().setBooleanValue(true);

      if (control.getExtractable() != null) {
        privateKey.getExtractable().setBooleanValue(control.getExtractable());
      }

      if (control.getSensitive() != null) {
        privateKey.getSensitive().setBooleanValue(control.getSensitive());
      }

      Set usages = control.getUsages();
      // CHECKSTYLE:SKIP
      final Boolean TRUE = Boolean.TRUE;
      if (isNotEmpty(usages)) {
        for (P11KeyUsage usage : usages) {
          if (usage == P11KeyUsage.DECRYPT) {
            privateKey.getDecrypt().setBooleanValue(TRUE);
          } else if (usage == P11KeyUsage.DERIVE) {
            privateKey.getDerive().setBooleanValue(TRUE);
          } else if (usage == P11KeyUsage.SIGN) {
            privateKey.getSign().setBooleanValue(TRUE);
          } else if (usage == P11KeyUsage.SIGN_RECOVER) {
            privateKey.getSignRecover().setBooleanValue(TRUE);
          } else if (usage == P11KeyUsage.UNWRAP) {
            privateKey.getUnwrap().setBooleanValue(TRUE);
          }
        }
      } else {
        long keyType = privateKey.getKeyType().getLongValue();
        // if not set
        if (keyType == PKCS11Constants.CKK_EC
            || keyType == PKCS11Constants.CKK_RSA
            || keyType == PKCS11Constants.CKK_DSA
            || keyType == PKCS11Constants.CKK_VENDOR_SM2) {
          privateKey.getSign().setBooleanValue(TRUE);
        }

        if (keyType == PKCS11Constants.CKK_RSA) {
          privateKey.getUnwrap().setBooleanValue(TRUE);
          privateKey.getDecrypt().setBooleanValue(TRUE);
        }
      }
    }

    if (publicKey != null) {
      publicKey.getToken().setBooleanValue(true);
      if (!newObjectConf.isIgnoreLabel()) {
        publicKey.getLabel().setCharArrayValue(control.getLabel().toCharArray());
      }
      publicKey.getVerify().setBooleanValue(true);
    }
  } // method setKeyAttributes

  static void setKeyAttributes(P11NewKeyControl control,
      SecretKey template, char[] label) {
    template.getToken().setBooleanValue(true);
    if (label != null) {
      template.getLabel().setCharArrayValue(label);
    }

    if (control.getExtractable() != null) {
      template.getExtractable().setBooleanValue(control.getExtractable());
    }

    if (control.getSensitive() != null) {
      template.getSensitive().setBooleanValue(control.getSensitive());
    }

    Set usages = control.getUsages();
    // CHECKSTYLE:SKIP
    final Boolean TRUE = Boolean.TRUE;
    if (isNotEmpty(usages)) {
      for (P11KeyUsage usage : usages) {
        if (usage == P11KeyUsage.DECRYPT) {
          template.getDecrypt().setBooleanValue(TRUE);
        } else if (usage == P11KeyUsage.DERIVE) {
          template.getDerive().setBooleanValue(TRUE);
        } else if (usage == P11KeyUsage.SIGN) {
          template.getSign().setBooleanValue(TRUE);
        } else if (usage == P11KeyUsage.UNWRAP) {
          template.getUnwrap().setBooleanValue(TRUE);
        }
      }
    }
  }

  static X509PublicKeyCertificate[] getCertificateObjects(Session session, byte[] keyId,
      char[] keyLabel)
          throws P11TokenException {
    X509PublicKeyCertificate template = new X509PublicKeyCertificate();
    if (keyId != null) {
      template.getId().setByteArrayValue(keyId);
    }
    if (keyLabel != null) {
      template.getLabel().setCharArrayValue(keyLabel);
    }

    List tmpObjects = getObjects(session, template);

    if (isEmpty(tmpObjects)) {
      LOG.info("found no certificate identified by {}", getDescription(keyId, keyLabel));
      return null;
    }

    int size = tmpObjects.size();
    X509PublicKeyCertificate[] certs = new X509PublicKeyCertificate[size];
    for (int i = 0; i < size; i++) {
      certs[i] = (X509PublicKeyCertificate) tmpObjects.get(i);
    }
    return certs;
  } // method getCertificateObjects

  static void logPkcs11ObjectAttributes(String prefix, PKCS11Object p11Object) {
    if (!LOG.isDebugEnabled()) {
      return;
    }

    Hashtable table = p11Object.getAttributeTable();
    StringBuilder sb = new StringBuilder();
    if (prefix != null) {
      sb.append(prefix);
    }

    Enumeration keys = table.keys();
    while (keys.hasMoreElements()) {
      Attribute attr = p11Object.getAttribute(keys.nextElement());
      sb.append("\n  ").append(attr.toString(true));
    }

    LOG.debug(sb.toString());
  } // method logPkcs11ObjectAttributes

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy