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 }