org.xipki.security.pkcs11.provider.XiKeyStoreSpi 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.provider;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.security.XiSecurityException;
import org.xipki.security.pkcs11.P11CryptService;
import org.xipki.security.pkcs11.P11CryptServiceFactory;
import org.xipki.security.pkcs11.P11Identity;
import org.xipki.security.pkcs11.P11Module;
import org.xipki.security.pkcs11.P11ObjectIdentifier;
import org.xipki.security.pkcs11.P11PrivateKey;
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;
/**
* Construction of alias is as follows.
*
* <module name>#slotid-<slot id>#keyid-<key id>
* <module name>#slotid-<slot id>#keylabel-<key label>
* <module name>#slotindex-<slot index>#keyid-<key id>
* <module name>#slotindex-<slot index>#keylabel-<key label>
*
*
*
* @author Lijun Liao
* @since 2.0.0
*/
public class XiKeyStoreSpi extends KeyStoreSpi {
private static final Logger LOG = LoggerFactory.getLogger(XiKeyStoreSpi.class);
private static class MyEnumeration implements Enumeration {
private Iterator iter;
MyEnumeration(Iterator iter) {
this.iter = iter;
}
@Override
public boolean hasMoreElements() {
return iter.hasNext();
}
@Override
public E nextElement() {
return iter.next();
}
} // class MyEnumeration
private static class KeyCertEntry {
private PrivateKey key;
private Certificate[] chain;
KeyCertEntry(PrivateKey key, Certificate[] chain) {
this.key = Args.notNull(key, "key");
this.chain = Args.notNull(chain, "chain");
if (chain.length < 1) {
throw new IllegalArgumentException("chain does not contain any certificate");
}
}
PrivateKey getKey() {
return key;
}
Certificate[] getCertificateChain() {
return Arrays.copyOf(chain, chain.length);
}
Certificate getCertificate() {
return chain[0];
}
} // class KeyCertEntry
private static P11CryptServiceFactory p11CryptServiceFactory;
private Date creationDate;
private Map keyCerts = new HashMap<>();
public static void setP11CryptServiceFactory(P11CryptServiceFactory service) {
p11CryptServiceFactory = service;
}
@Override
public void engineLoad(InputStream stream, char[] password) {
this.creationDate = new Date();
Set moduleNames = p11CryptServiceFactory.getModuleNames();
for (String moduleName : moduleNames) {
try {
engineLoad(moduleName);
} catch (XiSecurityException | P11TokenException ex) {
LogUtil.error(LOG, ex, "could not load PKCS#11 module " + moduleName);
}
}
if (LOG.isErrorEnabled()) {
LOG.info("loaded key entries {}", keyCerts.keySet());
}
} // class engineLoad
private void engineLoad(String moduleName) throws P11TokenException, XiSecurityException {
P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName);
P11Module module = p11Service.getModule();
List slotIds = module.getSlotIds();
for (P11SlotIdentifier slotId: slotIds) {
P11Slot slot = module.getSlot(slotId);
Set identityIds = slot.getIdentityKeyIds();
for (P11ObjectIdentifier objId : identityIds) {
P11Identity identity = slot.getIdentity(objId);
X509Certificate[] chain = identity.certificateChain();
if (chain == null || chain.length == 0) {
continue;
}
P11PrivateKey key = new P11PrivateKey(p11Service, identity.getId());
KeyCertEntry keyCertEntry = new KeyCertEntry(key, chain);
keyCerts.put(moduleName + "#slotid-" + slotId.getId() + "#keyid-"
+ objId.getIdHex(), keyCertEntry);
keyCerts.put(moduleName + "#slotid-" + slotId.getId() + "#keylabel-"
+ objId.getLabel(), keyCertEntry);
keyCerts.put(moduleName + "#slotindex-" + slotId.getIndex() + "#keyid-"
+ objId.getIdHex(), keyCertEntry);
keyCerts.put(moduleName + "#slotindex-" + slotId.getIndex() + "#keylabel-"
+ objId.getLabel(), keyCertEntry);
}
}
} // method engineLoad
@Override
public void engineStore(OutputStream stream, char[] password)
throws IOException, NoSuchAlgorithmException, CertificateException {
}
@Override
public Key engineGetKey(String alias, char[] password)
throws NoSuchAlgorithmException, UnrecoverableKeyException {
if (!keyCerts.containsKey(alias)) {
return null;
}
return keyCerts.get(alias).getKey();
}
@Override
public Certificate[] engineGetCertificateChain(String alias) {
if (!keyCerts.containsKey(alias)) {
return null;
}
return keyCerts.get(alias).getCertificateChain();
}
@Override
public Certificate engineGetCertificate(String alias) {
if (!keyCerts.containsKey(alias)) {
return null;
}
return keyCerts.get(alias).getCertificate();
}
@Override
public Date engineGetCreationDate(String alias) {
if (!keyCerts.containsKey(alias)) {
return null;
}
return creationDate;
}
@Override
public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
throws KeyStoreException {
throw new KeyStoreException("keystore is read only");
}
@Override
public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain)
throws KeyStoreException {
throw new KeyStoreException("keystore is read only");
}
@Override
public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
throw new KeyStoreException("keystore is read only");
}
@Override
public void engineDeleteEntry(String alias) throws KeyStoreException {
throw new KeyStoreException("keystore is read only");
}
@Override
public Enumeration engineAliases() {
return new MyEnumeration<>(keyCerts.keySet().iterator());
}
@Override
public boolean engineContainsAlias(String alias) {
return keyCerts.containsKey(alias);
}
@Override
public int engineSize() {
return keyCerts.size();
}
@Override
public boolean engineIsKeyEntry(String alias) {
if (!keyCerts.containsKey(alias)) {
return false;
}
return keyCerts.get(alias).key != null;
}
@Override
public boolean engineIsCertificateEntry(String alias) {
if (!keyCerts.containsKey(alias)) {
return false;
}
return keyCerts.get(alias).key == null;
}
@Override
public String engineGetCertificateAlias(Certificate cert) {
for (String alias : keyCerts.keySet()) {
if (keyCerts.get(alias).getCertificate().equals(cert)) {
return alias;
}
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy