/*
*
* Copyright (c) 2013 - 2017 Lijun Liao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3
* as published by the Free Software Foundation with the addition of the
* following permission added to Section 15 as permitted in Section 7(a):
*
* FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
* THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
* OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License.
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial activities involving the XiPKI software without
* disclosing the source code of your own applications.
*
* For more information, please contact Lijun Liao at this
* address: lijun.liao@gmail.com
*/
package org.xipki.commons.remotep11.server;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.commons.security.HashAlgoType;
import org.xipki.commons.security.exception.P11TokenException;
import org.xipki.commons.security.exception.XiSecurityException;
import org.xipki.commons.security.pkcs11.P11CryptService;
import org.xipki.commons.security.pkcs11.P11CryptServiceFactory;
/**
* @author Lijun Liao
* @since 2.0.0
*/
public class LocalP11CryptServicePool {
private static final Logger LOG = LoggerFactory.getLogger(LocalP11CryptServicePool.class);
private P11CryptServiceFactory p11CryptServiceFactory;
private Map<Short, P11CryptService> p11CryptServices = new HashMap<>();
private AtomicBoolean initialized = new AtomicBoolean(false);
public LocalP11CryptServicePool() {
}
public void setP11CryptServiceFactory(final P11CryptServiceFactory p11CryptServiceFactory) {
this.p11CryptServiceFactory = p11CryptServiceFactory;
}
public boolean isInitialized() {
return initialized.get();
}
public void init() throws P11TokenException, XiSecurityException {
LOG.info("initializing ...");
if (initialized.get()) {
LOG.info("already initialized, skipping ...");
return;
}
if (p11CryptServiceFactory == null) {
throw new IllegalStateException("securityFactory is not configured");
}
Set<String> moduleNames = p11CryptServiceFactory.getModuleNames();
for (String moduleName : moduleNames) {
P11CryptService p11Service = p11CryptServiceFactory.getP11CryptService(moduleName);
if (p11Service != null) {
short moduleId = deriveModuleId(moduleName);
String hexModuleId = "0x" + Integer.toHexString(moduleId);
if (p11CryptServices.containsKey(moduleId)) {
throw new P11TokenException(
"module Id " + moduleId + " for name " + moduleName
+ " already used, use another module name");
}
p11CryptServices.put(moduleId, p11Service);
LOG.info("map module name '{}' to ID {}({}), access path: "
+ "'proxy:url=https://<host>:<port>/p11proxy,module={}'",
moduleName, moduleId, hexModuleId, hexModuleId);
}
}
initialized.set(true);
LOG.info("initialized");
}
public P11CryptService getP11CryptService(final short moduleId) {
return p11CryptServices.get(moduleId);
}
/* ID = SHA1(moduleName.getBytes("UTF-8")[1..15] */
private static short deriveModuleId(String moduleName) throws XiSecurityException {
byte[] hash;
try {
hash = HashAlgoType.SHA1.hash(moduleName.getBytes("UTF-8"));
} catch (UnsupportedEncodingException ex) {
throw new XiSecurityException("Unsupported charset UTF-8");
}
int intCode = 0x7FFF & ((byteToInt(hash[0]) << 8) | byteToInt(hash[1]));
return (short) intCode;
}
private static int byteToInt(byte bb) {
return (bb < 0) ? 256 + bb : bb;
}
}