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

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

import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.List;

import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.xipki.security.BadAsn1ObjectException;
import org.xipki.security.X509Cert;
import org.xipki.security.pkcs11.P11Identity;
import org.xipki.security.pkcs11.P11IdentityId;
import org.xipki.security.pkcs11.P11ModuleConf.P11MechanismFilter;
import org.xipki.security.pkcs11.P11ObjectIdentifier;
import org.xipki.security.pkcs11.P11Slot;
import org.xipki.security.pkcs11.P11SlotIdentifier;
import org.xipki.security.pkcs11.P11TokenException;
import org.xipki.security.pkcs11.P11UnknownEntityException;
import org.xipki.security.util.KeyUtil;
import org.xipki.security.util.X509Util;
import org.xipki.util.StringUtil;

/**
 * TODO.
 * @author Lijun Liao
 * @since 2.0.0
 */

public class ProxyP11Slot extends P11Slot {

  private final ProxyP11Module module;

  private final P11SlotIdentifier slotId;

  private final ProxyMessage.SlotIdentifier asn1SlotId;

  ProxyP11Slot(ProxyP11Module module, P11SlotIdentifier slotId, boolean readOnly,
      P11MechanismFilter mechanismFilter) throws P11TokenException {
    super(module.getName(), slotId, readOnly, mechanismFilter);
    this.module = module;
    this.slotId = slotId;
    this.asn1SlotId = new ProxyMessage.SlotIdentifier(slotId);
    refresh();
  }

  @Override
  protected P11SlotRefreshResult refresh0() throws P11TokenException {
    P11SlotRefreshResult refreshResult = new P11SlotRefreshResult();

    // mechanisms
    List mechs = getMechanismsFromServer();
    for (Long mech : mechs) {
      refreshResult.addMechanism(mech);
    }

    // certificates
    List certIds =
        getObjectIdsFromServer(P11ProxyConstants.ACTION_GET_CERT_IDS);
    for (P11ObjectIdentifier certId : certIds) {
      X509Cert cert = getCertificate(certId);
      if (cert != null) {
        refreshResult.addCertificate(certId, cert);
      }
    }

    // public keys
    List pubkeyIds =
        getObjectIdsFromServer(P11ProxyConstants.ACTION_GET_PUBLICKEY_IDS);

    List keyIds =
        getObjectIdsFromServer(P11ProxyConstants.ACTION_GET_IDENTITY_IDS);
    for (P11ObjectIdentifier keyId : keyIds) {
      byte[] id = keyId.getId();

      // find the label of public key
      P11ObjectIdentifier pubkeyid = null;
      for (P11ObjectIdentifier m : pubkeyIds) {
        if (m.matchesId(id)) {
          pubkeyid = m;
          break;
        }
      }

      java.security.PublicKey pubKey = null;
      X509Cert cert = refreshResult.getCertForId(id);
      if (cert != null) {
        pubKey = cert.getCert().getPublicKey();
      } else {
        pubKey = getPublicKey(keyId);
      }

      P11IdentityId entityId = new P11IdentityId(slotId, keyId,
          (pubkeyid == null ? null : pubkeyid.getLabel()),
          refreshResult.getCertLabelForId(id));

      ProxyP11Identity identity;
      if (pubKey == null) {
        identity = new ProxyP11Identity(this, entityId);
      } else {
        X509Certificate[] certs = (cert == null) ? null : new X509Certificate[]{cert.getCert()};
        identity = new ProxyP11Identity(this, entityId, pubKey, certs);
      }
      refreshResult.addIdentity(identity);
    }

    return refreshResult;
  }

  @Override
  public void close() {
  }

  private PublicKey getPublicKey(P11ObjectIdentifier objectId)
      throws P11UnknownEntityException, P11TokenException {
    ASN1Object req =
        new ProxyMessage.SlotIdAndObjectId(asn1SlotId, new ProxyMessage.ObjectIdentifier(objectId));
    byte[] resp = module.send(P11ProxyConstants.ACTION_GET_PUBLICKEY, req);
    if (resp == null) {
      return null;
    }

    SubjectPublicKeyInfo pkInfo = SubjectPublicKeyInfo.getInstance(resp);
    try {
      return KeyUtil.generatePublicKey(pkInfo);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
      throw new P11TokenException("could not generate Public Key from SubjectPublicKeyInfo:"
          + ex.getMessage(), ex);
    }
  }

  private X509Cert getCertificate(P11ObjectIdentifier objectId) throws P11TokenException {
    ASN1Object req =
        new ProxyMessage.SlotIdAndObjectId(asn1SlotId, new ProxyMessage.ObjectIdentifier(objectId));
    byte[] resp = module.send(P11ProxyConstants.ACTION_GET_CERT, req);
    if (resp == null) {
      return null;
    }

    try {
      return new X509Cert(X509Util.parseCert(resp), resp);
    } catch (CertificateException ex) {
      throw new P11TokenException("could not parse certificate:" + ex.getMessage(), ex);
    }
  }

  @Override
  public int removeObjects(byte[] id, String label) throws P11TokenException {
    if ((id == null || id.length == 0) && StringUtil.isBlank(label)) {
      throw new IllegalArgumentException("at least one of id and label must not be null");
    }

    ProxyMessage.RemoveObjectsParams params =
        new ProxyMessage.RemoveObjectsParams(slotId, id, label);
    byte[] resp = module.send(P11ProxyConstants.ACTION_REMOVE_OBJECTS, params);
    try {
      return ASN1Integer.getInstance(resp).getValue().intValue();
    } catch (IllegalArgumentException ex) {
      throw new P11TokenException(ex.getMessage(), ex);
    }
  }

  @Override
  protected void removeIdentity0(P11IdentityId identityId) throws P11TokenException {
    ASN1Object req =  new ProxyMessage.SlotIdAndObjectId(asn1SlotId,
        new ProxyMessage.ObjectIdentifier(identityId.getKeyId()));
    module.send(P11ProxyConstants.ACTION_REMOVE_IDENTITY, req);
  }

  @Override
  protected P11ObjectIdentifier addCert0(X509Certificate cert, P11NewObjectControl control)
      throws P11TokenException, CertificateException {
    ProxyMessage.AddCertParams asn1 = new ProxyMessage.AddCertParams(slotId, control, cert);
    byte[] resp = module.send(P11ProxyConstants.ACTION_ADD_CERT, asn1);
    if (resp == null) {
      return null;
    }
    ProxyMessage.ObjectIdentifier objId;
    try {
      objId = ProxyMessage.ObjectIdentifier.getInstance(resp);
    } catch (BadAsn1ObjectException ex) {
      throw new P11TokenException(
          "invalid ASN1 object Asn1P11ObjectIdentifier: " + ex.getMessage(), ex);
    }
    return objId.getValue();
  }

  @Override
  protected void removeCerts0(P11ObjectIdentifier objectId) throws P11TokenException {
    ASN1Object req =
        new ProxyMessage.SlotIdAndObjectId(asn1SlotId, new ProxyMessage.ObjectIdentifier(objectId));
    module.send(P11ProxyConstants.ACTION_REMOVE_CERTS, req);
  }

  @Override
  protected P11Identity generateSecretKey0(long keyType, int keysize, P11NewKeyControl control)
      throws P11TokenException {
    ProxyMessage.GenSecretKeyParams asn1 = new ProxyMessage.GenSecretKeyParams(
        slotId, control, keyType, keysize);
    byte[] resp = module.send(P11ProxyConstants.ACTION_GEN_SECRET_KEY, asn1);
    return parseGenerateSecretKeyResult(resp);
  }

  @Override
  protected P11Identity importSecretKey0(long keyType, byte[] keyValue, P11NewKeyControl control)
      throws P11TokenException {
    ProxyMessage.ImportSecretKeyParams asn1 = new ProxyMessage.ImportSecretKeyParams(
        slotId, control, keyType, keyValue);
    byte[] resp = module.send(P11ProxyConstants.ACTION_IMPORT_SECRET_KEY, asn1);
    return parseGenerateSecretKeyResult(resp);
  }

  @Override
  protected P11Identity generateRSAKeypair0(int keysize, BigInteger publicExponent,
      P11NewKeyControl control) throws P11TokenException {
    ProxyMessage.GenRSAKeypairParams asn1 = new ProxyMessage.GenRSAKeypairParams(
        slotId, control, keysize, publicExponent);
    byte[] resp = module.send(P11ProxyConstants.ACTION_GEN_KEYPAIR_RSA, asn1);
    return parseGenerateKeypairResult(resp);
  }

  @Override
  protected P11Identity generateDSAKeypair0(BigInteger p, BigInteger q, BigInteger g,
      P11NewKeyControl control) throws P11TokenException {
    ProxyMessage.GenDSAKeypairParams asn1 =
        new ProxyMessage.GenDSAKeypairParams(slotId, control, p, q, g);
    byte[] resp = module.send(P11ProxyConstants.ACTION_GEN_KEYPAIR_DSA, asn1);
    return parseGenerateKeypairResult(resp);
  }

  @Override
  protected P11Identity generateECKeypair0(ASN1ObjectIdentifier curveId, P11NewKeyControl control)
      throws P11TokenException {
    ProxyMessage.GenECKeypairParams asn1 =
        new ProxyMessage.GenECKeypairParams(slotId, control, curveId);
    byte[] resp = module.send(P11ProxyConstants.ACTION_GEN_KEYPAIR_EC, asn1);
    return parseGenerateKeypairResult(resp);
  }

  @Override
  protected P11Identity generateSM2Keypair0(P11NewKeyControl control) throws P11TokenException {
    ProxyMessage.GenSM2KeypairParams asn1 =
        new ProxyMessage.GenSM2KeypairParams(slotId, control);
    byte[] resp = module.send(P11ProxyConstants.ACTION_GEN_KEYPAIR_SM2, asn1);
    return parseGenerateKeypairResult(resp);
  }

  private P11Identity parseGenerateKeypairResult(byte[] resp) throws P11TokenException {
    return parseGenerateKeyResult(resp, true);
  }

  private P11Identity parseGenerateSecretKeyResult(byte[] resp) throws P11TokenException {
    return parseGenerateKeyResult(resp, false);
  }

  private P11Identity parseGenerateKeyResult(byte[] resp, boolean needsPublicKey)
      throws P11TokenException {
    if (resp == null) {
      throw new P11TokenException("server returned no result");
    }

    ProxyMessage.IdentityId ei;
    try {
      ei = ProxyMessage.IdentityId.getInstance(resp);
    } catch (BadAsn1ObjectException ex) {
      throw new P11TokenException(
          "invalid ASN1 object Asn1P11EntityIdentifier: " + ex.getMessage(), ex);
    }

    if (!slotId.equals(ei.getValue().getSlotId())) {
      throw new P11TokenException("returned identity has different slodId");
    }

    P11IdentityId identityId = ei.getValue();
    if (needsPublicKey) {
      PublicKey publicKey = getPublicKey(identityId.getPublicKeyId());
      return new ProxyP11Identity(this, identityId, publicKey, null);
    } else {
      return new ProxyP11Identity(this, identityId);
    }
  }

  @Override
  protected void updateCertificate0(P11ObjectIdentifier objectId, X509Certificate newCert)
      throws P11TokenException, CertificateException {
    ProxyMessage.ObjectIdAndCert asn1 = new ProxyMessage.ObjectIdAndCert(asn1SlotId,
        new ProxyMessage.ObjectIdentifier(objectId), newCert);
    module.send(P11ProxyConstants.ACTION_UPDATE_CERT, asn1);
  }

  private List getMechanismsFromServer() throws P11TokenException {
    ProxyMessage.SlotIdentifier asn1SlotId = new ProxyMessage.SlotIdentifier(slotId);
    byte[] resp = module.send(P11ProxyConstants.ACTION_GET_MECHANISMS, asn1SlotId);
    ASN1Sequence seq = requireSequence(resp);
    final int n = seq.size();

    List mechs = new ArrayList<>(n);
    for (int i = 0; i < n; i++) {
      long mech = ASN1Integer.getInstance(seq.getObjectAt(i)).getValue().longValue();
      mechs.add(mech);
    }
    return mechs;
  }

  private List getObjectIdsFromServer(short action)
      throws P11TokenException {
    ProxyMessage.SlotIdentifier asn1SlotId = new ProxyMessage.SlotIdentifier(slotId);
    byte[] resp = module.send(action, asn1SlotId);

    List asn1ObjectIds;
    try {
      asn1ObjectIds = ProxyMessage.ObjectIdentifiers.getInstance(resp).getObjectIds();
    } catch (BadAsn1ObjectException ex) {
      throw new P11TokenException("bad ASN1 object: " + ex.getMessage(), ex);
    }

    List objectIds = new ArrayList<>(asn1ObjectIds.size());
    for (ProxyMessage.ObjectIdentifier asn1Id : asn1ObjectIds) {
      objectIds.add(asn1Id.getValue());
    }
    return objectIds;
  }

  private ASN1Sequence requireSequence(byte[] response) throws P11TokenException {
    try {
      return ASN1Sequence.getInstance(response);
    } catch (IllegalArgumentException ex) {
      throw new P11TokenException("response is not ASN1Sequence", ex);
    }
  }

  ProxyP11Module getModule() {
    return module;
  }

  ProxyMessage.SlotIdentifier getAsn1SlotId() {
    return asn1SlotId;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy