/*
*
* 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.security.pkcs11;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.commons.common.InvalidConfException;
import org.xipki.commons.common.util.CollectionUtil;
import org.xipki.commons.common.util.ParamUtil;
import org.xipki.commons.common.util.StringUtil;
import org.xipki.commons.password.PasswordResolver;
import org.xipki.commons.security.pkcs11.jaxb.MechanismSetsType;
import org.xipki.commons.security.pkcs11.jaxb.MechanismsType;
import org.xipki.commons.security.pkcs11.jaxb.ModuleType;
import org.xipki.commons.security.pkcs11.jaxb.NativeLibraryType;
import org.xipki.commons.security.pkcs11.jaxb.PasswordSetsType;
import org.xipki.commons.security.pkcs11.jaxb.PasswordsType;
import org.xipki.commons.security.pkcs11.jaxb.SlotType;
import org.xipki.commons.security.pkcs11.jaxb.SlotsType;
/**
* @author Lijun Liao
* @since 2.0.0
*/
public class P11ModuleConf {
private static final Logger LOG = LoggerFactory.getLogger(P11ModuleConf.class);
private final String name;
private final String nativeLibrary;
private final boolean readOnly;
private final Set<P11SlotIdFilter> excludeSlots;
private final Set<P11SlotIdFilter> includeSlots;
private final P11PasswordsRetriever passwordRetriever;
private final P11MechanismFilter mechanismFilter;
private final int maxMessageSize;
private final long userType;
public P11ModuleConf(final ModuleType moduleType, final PasswordResolver passwordResolver)
throws InvalidConfException {
ParamUtil.requireNonNull("moduleType", moduleType);
this.name = moduleType.getName();
this.readOnly = moduleType.isReadonly();
this.userType = moduleType.getUser().longValue();
this.maxMessageSize = moduleType.getMaxMessageSize().intValue();
if (maxMessageSize < 128) {
throw new InvalidConfException("invalid maxMessageSize (< 128): " + maxMessageSize);
}
// Mechanism filter
mechanismFilter = new P11MechanismFilter();
MechanismSetsType mechsList = moduleType.getMechanismSets();
if (mechsList != null && CollectionUtil.isNonEmpty(mechsList.getMechanisms())) {
for (MechanismsType mechType : mechsList.getMechanisms()) {
Set<P11SlotIdFilter> slots = getSlotIdFilters(mechType.getSlots());
Set<Long> mechanisms = new HashSet<>();
for (String mechStr : mechType.getMechanism()) {
Long mech = null;
if (mechStr.startsWith("CKM_")) {
mech = P11Constants.getMechanism(mechStr);
} else {
int radix = 10;
String value = mechStr.toLowerCase();
if (value.startsWith("0x")) {
radix = 16;
value = value.substring(2);
}
if (value.endsWith("l")) {
value = value.substring(0, value.length() - 1);
}
try {
mech = Long.parseLong(value, radix);
} catch (NumberFormatException ex) {// CHECKSTYLE:SKIP
}
}
if (mech == null) {
LOG.warn("skipped unknown mechanism '" + mechStr + "'");
} else {
mechanisms.add(mech);
}
}
mechanismFilter.addEntry(slots, mechanisms);
}
}
// Password retriever
passwordRetriever = new P11PasswordsRetriever();
PasswordSetsType passwordsList = moduleType.getPasswordSets();
if (passwordsList != null && CollectionUtil.isNonEmpty(passwordsList.getPasswords())) {
passwordRetriever.setPasswordResolver(passwordResolver);
for (PasswordsType passwordType : passwordsList.getPasswords()) {
Set<P11SlotIdFilter> slots = getSlotIdFilters(passwordType.getSlots());
passwordRetriever.addPasswordEntry(slots,
new ArrayList<>(passwordType.getPassword()));
}
}
includeSlots = getSlotIdFilters(moduleType.getIncludeSlots());
excludeSlots = getSlotIdFilters(moduleType.getExcludeSlots());
final String osName = System.getProperty("os.name").toLowerCase();
String nativeLibraryPath = null;
for (NativeLibraryType library
: moduleType.getNativeLibraries().getNativeLibrary()) {
List<String> osNames = library.getOs();
if (CollectionUtil.isEmpty(osNames)) {
nativeLibraryPath = library.getPath();
} else {
for (String entry : osNames) {
if (osName.contains(entry.toLowerCase())) {
nativeLibraryPath = library.getPath();
break;
}
}
}
if (nativeLibraryPath != null) {
break;
}
} // end for (NativeLibraryType library)
if (nativeLibraryPath == null) {
throw new InvalidConfException("could not find PKCS#11 library for OS "
+ osName);
}
this.nativeLibrary = nativeLibraryPath;
}
public String getName() {
return name;
}
public String getNativeLibrary() {
return nativeLibrary;
}
public int getMaxMessageSize() {
return maxMessageSize;
}
public boolean isReadOnly() {
return readOnly;
}
public long getUserType() {
return userType;
}
public P11PasswordsRetriever getPasswordRetriever() {
return passwordRetriever;
}
public boolean isSlotIncluded(final P11SlotIdentifier slotId) {
ParamUtil.requireNonNull("slotId", slotId);
boolean included;
if (CollectionUtil.isEmpty(includeSlots)) {
included = true;
} else {
included = false;
for (P11SlotIdFilter entry : includeSlots) {
if (entry.match(slotId)) {
included = true;
break;
}
}
}
if (!included) {
return false;
}
if (CollectionUtil.isEmpty(excludeSlots)) {
return included;
}
for (P11SlotIdFilter entry : excludeSlots) {
if (entry.match(slotId)) {
return false;
}
}
return true;
}
public P11MechanismFilter getP11MechanismFilter() {
return mechanismFilter;
}
private static Set<P11SlotIdFilter> getSlotIdFilters(final SlotsType type)
throws InvalidConfException {
if (type == null || CollectionUtil.isEmpty(type.getSlot())) {
return null;
}
Set<P11SlotIdFilter> filters = new HashSet<>();
for (SlotType slotType : type.getSlot()) {
Long slotId = null;
if (slotType.getId() != null) {
String str = slotType.getId().trim();
try {
slotId = StringUtil.startsWithIgnoreCase(str, "0X")
? Long.parseLong(str.substring(2), 16) : Long.parseLong(str);
} catch (NumberFormatException ex) {
String message = "invalid slotId '" + str + "'";
LOG.error(message);
throw new InvalidConfException(message);
}
}
filters.add(new P11SlotIdFilter(slotType.getIndex(), slotId));
}
return filters;
}
}