1 /* 2 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.pkcs11; 27 28 import java.util.*; 29 import java.util.concurrent.*; 30 31 import sun.security.pkcs11.wrapper.*; 32 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 33 34 /** 35 * TemplateManager class. 36 * 37 * Not all PKCS#11 tokens are created equal. One token may require that one 38 * value is specified when creating a certain type of object. Another token 39 * may require a different value. Yet another token may only work if the 40 * attribute is not specified at all. 41 * 42 * In order to allow an application to work unmodified with all those 43 * different tokens, the SunPKCS11 provider makes the attributes that are 44 * specified and their value configurable. Hence, only the SunPKCS11 45 * configuration file has to be tweaked at deployment time to allow all 46 * existing applications to be used. 47 * 48 * The template manager is responsible for reading the attribute configuration 49 * information and to make it available to the various internal components 50 * of the SunPKCS11 provider. 51 * 52 * @author Andreas Sterbenz 53 * @since 1.5 54 */ 55 final class TemplateManager { 56 57 private final static boolean DEBUG = false; 58 59 // constant for any operation (either O_IMPORT or O_GENERATE) 60 final static String O_ANY = "*"; 61 // constant for operation create ("importing" existing key material) 62 final static String O_IMPORT = "import"; 63 // constant for operation generate (generating new key material) 64 final static String O_GENERATE = "generate"; 65 66 private static class KeyAndTemplate { 67 final TemplateKey key; 68 final Template template; 69 70 KeyAndTemplate(TemplateKey key, Template template) { 71 this.key = key; 72 this.template = template; 73 } 74 } 75 76 // primitive templates contains the individual template configuration 77 // entries from the configuration file 78 private final List<KeyAndTemplate> primitiveTemplates; 79 80 // composite templates is a cache of the exact configuration template for 81 // each specific TemplateKey (no wildcards). the entries are created 82 // on demand during first use by compositing all applicable 83 // primitive template entries. the result is then stored in this map 84 // for performance 85 private final Map<TemplateKey,Template> compositeTemplates; 86 87 TemplateManager() { 88 primitiveTemplates = new ArrayList<KeyAndTemplate>(); 89 compositeTemplates = new ConcurrentHashMap<TemplateKey,Template>(); 90 } 91 92 // add a template. Called by Config. 93 void addTemplate(String op, long objectClass, long keyAlgorithm, 94 CK_ATTRIBUTE[] attrs) { 95 TemplateKey key = new TemplateKey(op, objectClass, keyAlgorithm); 96 Template template = new Template(attrs); 97 if (DEBUG) { 98 System.out.println("Adding " + key + " -> " + template); 99 } 100 primitiveTemplates.add(new KeyAndTemplate(key, template)); 101 } 102 103 private Template getTemplate(TemplateKey key) { 104 Template template = compositeTemplates.get(key); 105 if (template == null) { 106 template = buildCompositeTemplate(key); 107 compositeTemplates.put(key, template); 108 } 109 return template; 110 } 111 112 // Get the attributes for the requested op and combine them with attrs. 113 // This is the method called by the implementation to obtain the 114 // attributes. 115 CK_ATTRIBUTE[] getAttributes(String op, long type, long alg, 116 CK_ATTRIBUTE[] attrs) { 117 TemplateKey key = new TemplateKey(op, type, alg); 118 Template template = getTemplate(key); 119 CK_ATTRIBUTE[] newAttrs = template.getAttributes(attrs); 120 if (DEBUG) { 121 System.out.println(key + " -> " + Arrays.asList(newAttrs)); 122 } 123 return newAttrs; 124 } 125 126 // build a composite template for the given key 127 private Template buildCompositeTemplate(TemplateKey key) { 128 Template comp = new Template(); 129 // iterate through primitive templates and add all that apply 130 for (KeyAndTemplate entry : primitiveTemplates) { 131 if (entry.key.appliesTo(key)) { 132 comp.add(entry.template); 133 } 134 } 135 return comp; 136 } 137 138 /** 139 * Nested class representing a template identifier. 140 */ 141 private static final class TemplateKey { 142 final String operation; 143 final long keyType; 144 final long keyAlgorithm; 145 TemplateKey(String operation, long keyType, long keyAlgorithm) { 146 this.operation = operation; 147 this.keyType = keyType; 148 this.keyAlgorithm = keyAlgorithm; 149 } 150 public boolean equals(Object obj) { 151 if (this == obj) { 152 return true; 153 } 154 if (obj instanceof TemplateKey == false) { 155 return false; 156 } 157 TemplateKey other = (TemplateKey)obj; 158 boolean match = this.operation.equals(other.operation) 159 && (this.keyType == other.keyType) 160 && (this.keyAlgorithm == other.keyAlgorithm); 161 return match; 162 } 163 public int hashCode() { 164 return operation.hashCode() + (int)keyType + (int)keyAlgorithm; 165 } 166 boolean appliesTo(TemplateKey key) { 167 if (operation.equals(O_ANY) || operation.equals(key.operation)) { 168 if ((keyType == PCKO_ANY) || (keyType == key.keyType)) { 169 if ((keyAlgorithm == PCKK_ANY) 170 || (keyAlgorithm == key.keyAlgorithm)) { 171 return true; 172 } 173 } 174 } 175 return false; 176 } 177 public String toString() { 178 return "(" + operation + "," 179 + Functions.getObjectClassName(keyType) 180 + "," + Functions.getKeyName(keyAlgorithm) + ")"; 181 } 182 } 183 184 /** 185 * Nested class representing template attributes. 186 */ 187 private static final class Template { 188 189 private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0]; 190 191 private CK_ATTRIBUTE[] attributes; 192 193 Template() { 194 attributes = A0; 195 } 196 197 Template(CK_ATTRIBUTE[] attributes) { 198 this.attributes = attributes; 199 } 200 201 void add(Template template) { 202 attributes = getAttributes(template.attributes); 203 } 204 205 CK_ATTRIBUTE[] getAttributes(CK_ATTRIBUTE[] attrs) { 206 return combine(attributes, attrs); 207 } 208 209 /** 210 * Combine two sets of attributes. The second set has precedence 211 * over the first and overrides its settings. 212 */ 213 private static CK_ATTRIBUTE[] combine(CK_ATTRIBUTE[] attrs1, 214 CK_ATTRIBUTE[] attrs2) { 215 List<CK_ATTRIBUTE> attrs = new ArrayList<CK_ATTRIBUTE>(); 216 for (CK_ATTRIBUTE attr : attrs1) { 217 if (attr.pValue != null) { 218 attrs.add(attr); 219 } 220 } 221 for (CK_ATTRIBUTE attr2 : attrs2) { 222 long type = attr2.type; 223 for (CK_ATTRIBUTE attr1 : attrs1) { 224 if (attr1.type == type) { 225 attrs.remove(attr1); 226 } 227 } 228 if (attr2.pValue != null) { 229 attrs.add(attr2); 230 } 231 } 232 return attrs.toArray(A0); 233 } 234 235 public String toString() { 236 return Arrays.asList(attributes).toString(); 237 } 238 239 } 240 241 }