/* * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.pkcs11; import java.util.*; import java.util.concurrent.*; import sun.security.pkcs11.wrapper.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; /** * TemplateManager class. * * Not all PKCS#11 tokens are created equal. One token may require that one * value is specified when creating a certain type of object. Another token * may require a different value. Yet another token may only work if the * attribute is not specified at all. * * In order to allow an application to work unmodified with all those * different tokens, the SunPKCS11 provider makes the attributes that are * specified and their value configurable. Hence, only the SunPKCS11 * configuration file has to be tweaked at deployment time to allow all * existing applications to be used. * * The template manager is responsible for reading the attribute configuration * information and to make it available to the various internal components * of the SunPKCS11 provider. * * @author Andreas Sterbenz * @since 1.5 */ final class TemplateManager { private final static boolean DEBUG = false; // constant for any operation (either O_IMPORT or O_GENERATE) final static String O_ANY = "*"; // constant for operation create ("importing" existing key material) final static String O_IMPORT = "import"; // constant for operation generate (generating new key material) final static String O_GENERATE = "generate"; private static class KeyAndTemplate { final TemplateKey key; final Template template; KeyAndTemplate(TemplateKey key, Template template) { this.key = key; this.template = template; } } // primitive templates contains the individual template configuration // entries from the configuration file private final List<KeyAndTemplate> primitiveTemplates; // composite templates is a cache of the exact configuration template for // each specific TemplateKey (no wildcards). the entries are created // on demand during first use by compositing all applicable // primitive template entries. the result is then stored in this map // for performance private final Map<TemplateKey,Template> compositeTemplates; TemplateManager() { primitiveTemplates = new ArrayList<KeyAndTemplate>(); compositeTemplates = new ConcurrentHashMap<TemplateKey,Template>(); } // add a template. Called by Config. void addTemplate(String op, long objectClass, long keyAlgorithm, CK_ATTRIBUTE[] attrs) { TemplateKey key = new TemplateKey(op, objectClass, keyAlgorithm); Template template = new Template(attrs); if (DEBUG) { System.out.println("Adding " + key + " -> " + template); } primitiveTemplates.add(new KeyAndTemplate(key, template)); } private Template getTemplate(TemplateKey key) { Template template = compositeTemplates.get(key); if (template == null) { template = buildCompositeTemplate(key); compositeTemplates.put(key, template); } return template; } // Get the attributes for the requested op and combine them with attrs. // This is the method called by the implementation to obtain the // attributes. CK_ATTRIBUTE[] getAttributes(String op, long type, long alg, CK_ATTRIBUTE[] attrs) { TemplateKey key = new TemplateKey(op, type, alg); Template template = getTemplate(key); CK_ATTRIBUTE[] newAttrs = template.getAttributes(attrs); if (DEBUG) { System.out.println(key + " -> " + Arrays.asList(newAttrs)); } return newAttrs; } // build a composite template for the given key private Template buildCompositeTemplate(TemplateKey key) { Template comp = new Template(); // iterate through primitive templates and add all that apply for (KeyAndTemplate entry : primitiveTemplates) { if (entry.key.appliesTo(key)) { comp.add(entry.template); } } return comp; } /** * Nested class representing a template identifier. */ private static final class TemplateKey { final String operation; final long keyType; final long keyAlgorithm; TemplateKey(String operation, long keyType, long keyAlgorithm) { this.operation = operation; this.keyType = keyType; this.keyAlgorithm = keyAlgorithm; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof TemplateKey == false) { return false; } TemplateKey other = (TemplateKey)obj; boolean match = this.operation.equals(other.operation) && (this.keyType == other.keyType) && (this.keyAlgorithm == other.keyAlgorithm); return match; } public int hashCode() { return operation.hashCode() + (int)keyType + (int)keyAlgorithm; } boolean appliesTo(TemplateKey key) { if (operation.equals(O_ANY) || operation.equals(key.operation)) { if ((keyType == PCKO_ANY) || (keyType == key.keyType)) { if ((keyAlgorithm == PCKK_ANY) || (keyAlgorithm == key.keyAlgorithm)) { return true; } } } return false; } public String toString() { return "(" + operation + "," + Functions.getObjectClassName(keyType) + "," + Functions.getKeyName(keyAlgorithm) + ")"; } } /** * Nested class representing template attributes. */ private static final class Template { private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0]; private CK_ATTRIBUTE[] attributes; Template() { attributes = A0; } Template(CK_ATTRIBUTE[] attributes) { this.attributes = attributes; } void add(Template template) { attributes = getAttributes(template.attributes); } CK_ATTRIBUTE[] getAttributes(CK_ATTRIBUTE[] attrs) { return combine(attributes, attrs); } /** * Combine two sets of attributes. The second set has precedence * over the first and overrides its settings. */ private static CK_ATTRIBUTE[] combine(CK_ATTRIBUTE[] attrs1, CK_ATTRIBUTE[] attrs2) { List<CK_ATTRIBUTE> attrs = new ArrayList<CK_ATTRIBUTE>(); for (CK_ATTRIBUTE attr : attrs1) { if (attr.pValue != null) { attrs.add(attr); } } for (CK_ATTRIBUTE attr2 : attrs2) { long type = attr2.type; for (CK_ATTRIBUTE attr1 : attrs1) { if (attr1.type == type) { attrs.remove(attr1); } } if (attr2.pValue != null) { attrs.add(attr2); } } return attrs.toArray(A0); } public String toString() { return Arrays.asList(attributes).toString(); } } }