1 /*
2 * Copyright (c) 2003, 2016, 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.io.*;
29 import static java.io.StreamTokenizer.*;
30 import java.math.BigInteger;
31 import java.util.*;
32
33 import java.security.*;
34
35 import sun.security.util.PropertyExpander;
36
37 import sun.security.pkcs11.wrapper.*;
38 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
39 import static sun.security.pkcs11.wrapper.CK_ATTRIBUTE.*;
40
41 import static sun.security.pkcs11.TemplateManager.*;
42
43 /**
44 * Configuration container and file parsing.
45 *
46 * @author Andreas Sterbenz
47 * @since 1.5
48 */
49 final class Config {
50
51 static final int ERR_HALT = 1;
52 static final int ERR_IGNORE_ALL = 2;
53 static final int ERR_IGNORE_LIB = 3;
54
55 // same as allowSingleThreadedModules but controlled via a system property
56 // and applied to all providers. if set to false, no SunPKCS11 instances
57 // will accept single threaded modules regardless of the setting in their
58 // config files.
59 private static final boolean staticAllowSingleThreadedModules;
60 private static final String osName;
61 private static final String osArch;
62
63 static {
64 List<String> props = AccessController.doPrivileged(
65 new PrivilegedAction<>() {
66 @Override
67 public List<String> run() {
68 return List.of(
69 System.getProperty(
70 "sun.security.pkcs11.allowSingleThreadedModules",
71 "true"),
72 System.getProperty("os.name"),
73 System.getProperty("os.arch"));
74 }
75 }
76 );
77 if ("false".equalsIgnoreCase(props.get(0))) {
78 staticAllowSingleThreadedModules = false;
79 } else {
80 staticAllowSingleThreadedModules = true;
81 }
82 osName = props.get(1);
83 osArch = props.get(2);
84 }
85
86 private final static boolean DEBUG = false;
87
88 private static void debug(Object o) {
89 if (DEBUG) {
90 System.out.println(o);
91 }
92 }
93
94 // file name containing this configuration
95 private String filename;
96
97 // Reader and StringTokenizer used during parsing
98 private Reader reader;
99
100 private StreamTokenizer st;
101
102 private Set<String> parsedKeywords;
103
104 // name suffix of the provider
105 private String name;
106
107 // name of the PKCS#11 library
108 private String library;
109
110 // description to pass to the provider class
111 private String description;
112
113 // slotID of the slot to use
114 private int slotID = -1;
115
116 // slot to use, specified as index in the slotlist
117 private int slotListIndex = -1;
118
119 // set of enabled mechanisms (or null to use default)
120 private Set<Long> enabledMechanisms;
121
122 // set of disabled mechanisms
123 private Set<Long> disabledMechanisms;
124
125 // whether to print debug info during startup
126 private boolean showInfo = false;
127
128 // template manager, initialized from parsed attributes
129 private TemplateManager templateManager;
130
131 // how to handle error during startup, one of ERR_
132 private int handleStartupErrors = ERR_HALT;
133
134 // flag indicating whether the P11KeyStore should
135 // be more tolerant of input parameters
136 private boolean keyStoreCompatibilityMode = true;
137
138 // flag indicating whether we need to explicitly cancel operations
139 // see Token
140 private boolean explicitCancel = true;
141
142 // how often to test for token insertion, if no token is present
143 private int insertionCheckInterval = 2000;
144
145 // flag inidicating whether to omit the call to C_Initialize()
146 // should be used only if we are running within a process that
147 // has already called it (e.g. Plugin inside of Mozilla/NSS)
148 private boolean omitInitialize = false;
149
150 // whether to allow modules that only support single threaded access.
151 // they cannot be used safely from multiple PKCS#11 consumers in the
152 // same process, for example NSS and SunPKCS11
153 private boolean allowSingleThreadedModules = true;
154
155 // name of the C function that returns the PKCS#11 functionlist
156 // This option primarily exists for the deprecated
157 // Secmod.Module.getProvider() method.
158 private String functionList = "C_GetFunctionList";
159
160 // whether to use NSS secmod mode. Implicitly set if nssLibraryDirectory,
161 // nssSecmodDirectory, or nssModule is specified.
162 private boolean nssUseSecmod;
163
164 // location of the NSS library files (libnss3.so, etc.)
165 private String nssLibraryDirectory;
166
167 // location of secmod.db
168 private String nssSecmodDirectory;
169
170 // which NSS module to use
171 private String nssModule;
172
173 private Secmod.DbMode nssDbMode = Secmod.DbMode.READ_WRITE;
174
175 // Whether the P11KeyStore should specify the CKA_NETSCAPE_DB attribute
176 // when creating private keys. Only valid if nssUseSecmod is true.
177 private boolean nssNetscapeDbWorkaround = true;
178
179 // Special init argument string for the NSS softtoken.
180 // This is used when using the NSS softtoken directly without secmod mode.
181 private String nssArgs;
182
183 // whether to use NSS trust attributes for the KeyStore of this provider
184 // this option is for internal use by the SunPKCS11 code only and
185 // works only for NSS providers created via the Secmod API
186 private boolean nssUseSecmodTrust = false;
187
188 // Flag to indicate whether the X9.63 encoding for EC points shall be used
189 // (true) or whether that encoding shall be wrapped in an ASN.1 OctetString
190 // (false).
191 private boolean useEcX963Encoding = false;
192
193 // Flag to indicate whether NSS should favour performance (false) or
194 // memory footprint (true).
195 private boolean nssOptimizeSpace = false;
196
197 Config(String fn) throws IOException {
198 this.filename = fn;
199 if (filename.startsWith("--")) {
200 // inline config
201 String config = filename.substring(2).replace("\\n", "\n");
202 reader = new StringReader(config);
203 } else {
204 reader = new BufferedReader(new InputStreamReader
205 (new FileInputStream(expand(filename))));
206 }
207 parsedKeywords = new HashSet<String>();
208 st = new StreamTokenizer(reader);
209 setupTokenizer();
210 parse();
211 }
212
213 String getFileName() {
214 return filename;
215 }
216
217 String getName() {
218 return name;
219 }
220
221 String getLibrary() {
222 return library;
223 }
224
225 String getDescription() {
226 if (description != null) {
227 return description;
228 }
229 return "SunPKCS11-" + name + " using library " + library;
230 }
231
232 int getSlotID() {
233 return slotID;
234 }
235
236 int getSlotListIndex() {
237 if ((slotID == -1) && (slotListIndex == -1)) {
238 // if neither is set, default to first slot
239 return 0;
240 } else {
241 return slotListIndex;
242 }
243 }
244
245 boolean getShowInfo() {
246 return (SunPKCS11.debug != null) || showInfo;
247 }
248
249 TemplateManager getTemplateManager() {
250 if (templateManager == null) {
251 templateManager = new TemplateManager();
252 }
253 return templateManager;
254 }
255
256 boolean isEnabled(long m) {
257 if (enabledMechanisms != null) {
258 return enabledMechanisms.contains(Long.valueOf(m));
259 }
260 if (disabledMechanisms != null) {
261 return !disabledMechanisms.contains(Long.valueOf(m));
262 }
263 return true;
264 }
265
266 int getHandleStartupErrors() {
267 return handleStartupErrors;
268 }
269
270 boolean getKeyStoreCompatibilityMode() {
271 return keyStoreCompatibilityMode;
272 }
273
274 boolean getExplicitCancel() {
275 return explicitCancel;
276 }
277
278 int getInsertionCheckInterval() {
279 return insertionCheckInterval;
280 }
281
282 boolean getOmitInitialize() {
283 return omitInitialize;
284 }
285
286 boolean getAllowSingleThreadedModules() {
287 return staticAllowSingleThreadedModules && allowSingleThreadedModules;
288 }
289
290 String getFunctionList() {
291 return functionList;
292 }
293
294 boolean getNssUseSecmod() {
295 return nssUseSecmod;
296 }
297
298 String getNssLibraryDirectory() {
299 return nssLibraryDirectory;
300 }
301
302 String getNssSecmodDirectory() {
303 return nssSecmodDirectory;
304 }
305
306 String getNssModule() {
307 return nssModule;
308 }
309
310 Secmod.DbMode getNssDbMode() {
311 return nssDbMode;
312 }
313
314 public boolean getNssNetscapeDbWorkaround() {
315 return nssUseSecmod && nssNetscapeDbWorkaround;
316 }
317
318 String getNssArgs() {
319 return nssArgs;
320 }
321
322 boolean getNssUseSecmodTrust() {
323 return nssUseSecmodTrust;
324 }
325
326 boolean getUseEcX963Encoding() {
327 return useEcX963Encoding;
328 }
329
330 boolean getNssOptimizeSpace() {
331 return nssOptimizeSpace;
332 }
333
334 private static String expand(final String s) throws IOException {
335 try {
336 return PropertyExpander.expand(s);
337 } catch (Exception e) {
338 throw new RuntimeException(e.getMessage());
339 }
340 }
341
342 private void setupTokenizer() {
343 st.resetSyntax();
344 st.wordChars('a', 'z');
345 st.wordChars('A', 'Z');
346 st.wordChars('0', '9');
347 st.wordChars(':', ':');
348 st.wordChars('.', '.');
349 st.wordChars('_', '_');
350 st.wordChars('-', '-');
351 st.wordChars('/', '/');
352 st.wordChars('\\', '\\');
353 st.wordChars('$', '$');
354 st.wordChars('{', '{'); // need {} for property subst
355 st.wordChars('}', '}');
356 st.wordChars('*', '*');
357 st.wordChars('+', '+');
358 st.wordChars('~', '~');
359 // XXX check ASCII table and add all other characters except special
360
361 // special: #="(),
362 st.whitespaceChars(0, ' ');
363 st.commentChar('#');
364 st.eolIsSignificant(true);
365 st.quoteChar('\"');
366 }
367
368 private ConfigurationException excToken(String msg) {
369 return new ConfigurationException(msg + " " + st);
370 }
371
372 private ConfigurationException excLine(String msg) {
373 return new ConfigurationException(msg + ", line " + st.lineno());
374 }
375
376 private void parse() throws IOException {
377 while (true) {
378 int token = nextToken();
379 if (token == TT_EOF) {
380 break;
381 }
382 if (token == TT_EOL) {
383 continue;
384 }
385 if (token != TT_WORD) {
386 throw excToken("Unexpected token:");
387 }
388 String word = st.sval;
389 if (word.equals("name")) {
390 name = parseStringEntry(word);
391 } else if (word.equals("library")) {
392 library = parseLibrary(word);
393 } else if (word.equals("description")) {
394 parseDescription(word);
395 } else if (word.equals("slot")) {
396 parseSlotID(word);
397 } else if (word.equals("slotListIndex")) {
398 parseSlotListIndex(word);
399 } else if (word.equals("enabledMechanisms")) {
400 parseEnabledMechanisms(word);
401 } else if (word.equals("disabledMechanisms")) {
402 parseDisabledMechanisms(word);
403 } else if (word.equals("attributes")) {
404 parseAttributes(word);
405 } else if (word.equals("handleStartupErrors")) {
406 parseHandleStartupErrors(word);
407 } else if (word.endsWith("insertionCheckInterval")) {
408 insertionCheckInterval = parseIntegerEntry(word);
409 if (insertionCheckInterval < 100) {
410 throw excLine(word + " must be at least 100 ms");
411 }
412 } else if (word.equals("showInfo")) {
413 showInfo = parseBooleanEntry(word);
414 } else if (word.equals("keyStoreCompatibilityMode")) {
415 keyStoreCompatibilityMode = parseBooleanEntry(word);
416 } else if (word.equals("explicitCancel")) {
417 explicitCancel = parseBooleanEntry(word);
418 } else if (word.equals("omitInitialize")) {
419 omitInitialize = parseBooleanEntry(word);
420 } else if (word.equals("allowSingleThreadedModules")) {
421 allowSingleThreadedModules = parseBooleanEntry(word);
422 } else if (word.equals("functionList")) {
423 functionList = parseStringEntry(word);
424 } else if (word.equals("nssUseSecmod")) {
425 nssUseSecmod = parseBooleanEntry(word);
426 } else if (word.equals("nssLibraryDirectory")) {
427 nssLibraryDirectory = parseLibrary(word);
428 nssUseSecmod = true;
429 } else if (word.equals("nssSecmodDirectory")) {
430 nssSecmodDirectory = expand(parseStringEntry(word));
431 nssUseSecmod = true;
432 } else if (word.equals("nssModule")) {
433 nssModule = parseStringEntry(word);
434 nssUseSecmod = true;
435 } else if (word.equals("nssDbMode")) {
436 String mode = parseStringEntry(word);
437 if (mode.equals("readWrite")) {
438 nssDbMode = Secmod.DbMode.READ_WRITE;
439 } else if (mode.equals("readOnly")) {
440 nssDbMode = Secmod.DbMode.READ_ONLY;
441 } else if (mode.equals("noDb")) {
442 nssDbMode = Secmod.DbMode.NO_DB;
443 } else {
444 throw excToken("nssDbMode must be one of readWrite, readOnly, and noDb:");
445 }
446 nssUseSecmod = true;
447 } else if (word.equals("nssNetscapeDbWorkaround")) {
448 nssNetscapeDbWorkaround = parseBooleanEntry(word);
449 nssUseSecmod = true;
450 } else if (word.equals("nssArgs")) {
451 parseNSSArgs(word);
452 } else if (word.equals("nssUseSecmodTrust")) {
453 nssUseSecmodTrust = parseBooleanEntry(word);
454 } else if (word.equals("useEcX963Encoding")) {
455 useEcX963Encoding = parseBooleanEntry(word);
456 } else if (word.equals("nssOptimizeSpace")) {
457 nssOptimizeSpace = parseBooleanEntry(word);
458 } else {
459 throw new ConfigurationException
460 ("Unknown keyword '" + word + "', line " + st.lineno());
461 }
462 parsedKeywords.add(word);
463 }
464 reader.close();
465 reader = null;
466 st = null;
467 parsedKeywords = null;
468 if (name == null) {
469 throw new ConfigurationException("name must be specified");
470 }
471 if (nssUseSecmod == false) {
472 if (library == null) {
473 throw new ConfigurationException("library must be specified");
474 }
475 } else {
476 if (library != null) {
477 throw new ConfigurationException
478 ("library must not be specified in NSS mode");
479 }
480 if ((slotID != -1) || (slotListIndex != -1)) {
481 throw new ConfigurationException
482 ("slot and slotListIndex must not be specified in NSS mode");
483 }
484 if (nssArgs != null) {
485 throw new ConfigurationException
486 ("nssArgs must not be specified in NSS mode");
487 }
488 if (nssUseSecmodTrust != false) {
489 throw new ConfigurationException("nssUseSecmodTrust is an "
490 + "internal option and must not be specified in NSS mode");
491 }
492 }
493 }
494
495 //
496 // Parsing helper methods
497 //
498
499 private int nextToken() throws IOException {
500 int token = st.nextToken();
501 debug(st);
502 return token;
503 }
504
505 private void parseEquals() throws IOException {
506 int token = nextToken();
507 if (token != '=') {
508 throw excToken("Expected '=', read");
509 }
510 }
511
512 private void parseOpenBraces() throws IOException {
513 while (true) {
514 int token = nextToken();
515 if (token == TT_EOL) {
516 continue;
517 }
518 if ((token == TT_WORD) && st.sval.equals("{")) {
519 return;
520 }
521 throw excToken("Expected '{', read");
522 }
523 }
524
525 private boolean isCloseBraces(int token) {
526 return (token == TT_WORD) && st.sval.equals("}");
527 }
528
529 private String parseWord() throws IOException {
530 int token = nextToken();
531 if (token != TT_WORD) {
532 throw excToken("Unexpected value:");
533 }
534 return st.sval;
535 }
536
537 private String parseStringEntry(String keyword) throws IOException {
538 checkDup(keyword);
539 parseEquals();
540
541 int token = nextToken();
542 if (token != TT_WORD && token != '\"') {
543 // not a word token nor a string enclosed by double quotes
544 throw excToken("Unexpected value:");
545 }
546 String value = st.sval;
547
548 debug(keyword + ": " + value);
549 return value;
550 }
551
552 private boolean parseBooleanEntry(String keyword) throws IOException {
553 checkDup(keyword);
554 parseEquals();
555 boolean value = parseBoolean();
556 debug(keyword + ": " + value);
557 return value;
558 }
559
560 private int parseIntegerEntry(String keyword) throws IOException {
561 checkDup(keyword);
562 parseEquals();
563 int value = decodeNumber(parseWord());
564 debug(keyword + ": " + value);
565 return value;
566 }
567
568 private boolean parseBoolean() throws IOException {
569 String val = parseWord();
570 switch (val) {
571 case "true":
572 return true;
573 case "false":
574 return false;
575 default:
576 throw excToken("Expected boolean value, read:");
577 }
578 }
579
580 private String parseLine() throws IOException {
581 // allow quoted string as part of line
582 String s = null;
583 while (true) {
584 int token = nextToken();
585 if ((token == TT_EOL) || (token == TT_EOF)) {
586 break;
587 }
588 if (token != TT_WORD && token != '\"') {
589 throw excToken("Unexpected value");
590 }
591 if (s == null) {
592 s = st.sval;
593 } else {
594 s = s + " " + st.sval;
595 }
596 }
597 if (s == null) {
598 throw excToken("Unexpected empty line");
599 }
600 return s;
601 }
602
603 private int decodeNumber(String str) throws IOException {
604 try {
605 if (str.startsWith("0x") || str.startsWith("0X")) {
606 return Integer.parseInt(str.substring(2), 16);
607 } else {
608 return Integer.parseInt(str);
609 }
610 } catch (NumberFormatException e) {
611 throw excToken("Expected number, read");
612 }
613 }
614
615 private static boolean isNumber(String s) {
616 if (s.length() == 0) {
617 return false;
618 }
619 char ch = s.charAt(0);
620 return ((ch >= '0') && (ch <= '9'));
621 }
622
623 private void parseComma() throws IOException {
624 int token = nextToken();
625 if (token != ',') {
626 throw excToken("Expected ',', read");
627 }
628 }
629
630 private static boolean isByteArray(String val) {
631 return val.startsWith("0h");
632 }
633
634 private byte[] decodeByteArray(String str) throws IOException {
635 if (str.startsWith("0h") == false) {
636 throw excToken("Expected byte array value, read");
637 }
638 str = str.substring(2);
639 // XXX proper hex parsing
640 try {
641 return new BigInteger(str, 16).toByteArray();
642 } catch (NumberFormatException e) {
643 throw excToken("Expected byte array value, read");
644 }
645 }
646
647 private void checkDup(String keyword) throws IOException {
648 if (parsedKeywords.contains(keyword)) {
649 throw excLine(keyword + " must only be specified once");
650 }
651 }
652
653 //
654 // individual entry parsing methods
655 //
656
657 private String parseLibrary(String keyword) throws IOException {
658 checkDup(keyword);
659 parseEquals();
660 String lib = parseLine();
661 lib = expand(lib);
662 int i = lib.indexOf("/$ISA/");
663 if (i != -1) {
664 // replace "/$ISA/" with "/sparcv9/" on 64-bit Solaris SPARC
665 // and with "/amd64/" on Solaris AMD64.
666 // On all other platforms, just turn it into a "/"
667 String prefix = lib.substring(0, i);
668 String suffix = lib.substring(i + 5);
669 if (osName.equals("SunOS") && osArch.equals("sparcv9")) {
670 lib = prefix + "/sparcv9" + suffix;
671 } else if (osName.equals("SunOS") && osArch.equals("amd64")) {
672 lib = prefix + "/amd64" + suffix;
673 } else {
674 lib = prefix + suffix;
675 }
676 }
677 debug(keyword + ": " + lib);
678
679 // Check to see if full path is specified to prevent the DLL
680 // preloading attack
681 if (!(new File(lib)).isAbsolute()) {
682 throw new ConfigurationException(
683 "Absolute path required for library value: " + lib);
684 }
685 return lib;
686 }
687
688 private void parseDescription(String keyword) throws IOException {
689 checkDup(keyword);
690 parseEquals();
691 description = parseLine();
692 debug("description: " + description);
693 }
694
695 private void parseSlotID(String keyword) throws IOException {
696 if (slotID >= 0) {
697 throw excLine("Duplicate slot definition");
698 }
699 if (slotListIndex >= 0) {
700 throw excLine
701 ("Only one of slot and slotListIndex must be specified");
702 }
703 parseEquals();
704 String slotString = parseWord();
705 slotID = decodeNumber(slotString);
706 debug("slot: " + slotID);
707 }
708
709 private void parseSlotListIndex(String keyword) throws IOException {
710 if (slotListIndex >= 0) {
711 throw excLine("Duplicate slotListIndex definition");
712 }
713 if (slotID >= 0) {
714 throw excLine
715 ("Only one of slot and slotListIndex must be specified");
716 }
717 parseEquals();
718 String slotString = parseWord();
719 slotListIndex = decodeNumber(slotString);
720 debug("slotListIndex: " + slotListIndex);
721 }
722
723 private void parseEnabledMechanisms(String keyword) throws IOException {
724 enabledMechanisms = parseMechanisms(keyword);
725 }
726
727 private void parseDisabledMechanisms(String keyword) throws IOException {
728 disabledMechanisms = parseMechanisms(keyword);
729 }
730
731 private Set<Long> parseMechanisms(String keyword) throws IOException {
732 checkDup(keyword);
733 Set<Long> mechs = new HashSet<Long>();
734 parseEquals();
735 parseOpenBraces();
736 while (true) {
737 int token = nextToken();
738 if (isCloseBraces(token)) {
739 break;
740 }
741 if (token == TT_EOL) {
742 continue;
743 }
744 if (token != TT_WORD) {
745 throw excToken("Expected mechanism, read");
746 }
747 long mech = parseMechanism(st.sval);
748 mechs.add(Long.valueOf(mech));
749 }
750 if (DEBUG) {
751 System.out.print("mechanisms: [");
752 for (Long mech : mechs) {
753 System.out.print(Functions.getMechanismName(mech));
754 System.out.print(", ");
755 }
756 System.out.println("]");
757 }
758 return mechs;
759 }
760
761 private long parseMechanism(String mech) throws IOException {
762 if (isNumber(mech)) {
763 return decodeNumber(mech);
764 } else {
765 try {
766 return Functions.getMechanismId(mech);
767 } catch (IllegalArgumentException e) {
768 throw excLine("Unknown mechanism: " + mech);
769 }
770 }
771 }
772
773 private void parseAttributes(String keyword) throws IOException {
774 if (templateManager == null) {
775 templateManager = new TemplateManager();
776 }
777 int token = nextToken();
778 if (token == '=') {
779 String s = parseWord();
780 if (s.equals("compatibility") == false) {
781 throw excLine("Expected 'compatibility', read " + s);
782 }
783 setCompatibilityAttributes();
784 return;
785 }
786 if (token != '(') {
787 throw excToken("Expected '(' or '=', read");
788 }
789 String op = parseOperation();
790 parseComma();
791 long objectClass = parseObjectClass();
792 parseComma();
793 long keyAlg = parseKeyAlgorithm();
794 token = nextToken();
795 if (token != ')') {
796 throw excToken("Expected ')', read");
797 }
798 parseEquals();
799 parseOpenBraces();
800 List<CK_ATTRIBUTE> attributes = new ArrayList<CK_ATTRIBUTE>();
801 while (true) {
802 token = nextToken();
803 if (isCloseBraces(token)) {
804 break;
805 }
806 if (token == TT_EOL) {
807 continue;
808 }
809 if (token != TT_WORD) {
810 throw excToken("Expected mechanism, read");
811 }
812 String attributeName = st.sval;
813 long attributeId = decodeAttributeName(attributeName);
814 parseEquals();
815 String attributeValue = parseWord();
816 attributes.add(decodeAttributeValue(attributeId, attributeValue));
817 }
818 templateManager.addTemplate
819 (op, objectClass, keyAlg, attributes.toArray(CK_A0));
820 }
821
822 private void setCompatibilityAttributes() {
823 // all secret keys
824 templateManager.addTemplate(O_ANY, CKO_SECRET_KEY, PCKK_ANY,
825 new CK_ATTRIBUTE[] {
826 TOKEN_FALSE,
827 SENSITIVE_FALSE,
828 EXTRACTABLE_TRUE,
829 ENCRYPT_TRUE,
830 DECRYPT_TRUE,
831 WRAP_TRUE,
832 UNWRAP_TRUE,
833 });
834
835 // generic secret keys are special
836 // They are used as MAC keys plus for the SSL/TLS (pre)master secrets
837 templateManager.addTemplate(O_ANY, CKO_SECRET_KEY, CKK_GENERIC_SECRET,
838 new CK_ATTRIBUTE[] {
839 SIGN_TRUE,
840 VERIFY_TRUE,
841 ENCRYPT_NULL,
842 DECRYPT_NULL,
843 WRAP_NULL,
844 UNWRAP_NULL,
845 DERIVE_TRUE,
846 });
847
848 // all private and public keys
849 templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, PCKK_ANY,
850 new CK_ATTRIBUTE[] {
851 TOKEN_FALSE,
852 SENSITIVE_FALSE,
853 EXTRACTABLE_TRUE,
854 });
855 templateManager.addTemplate(O_ANY, CKO_PUBLIC_KEY, PCKK_ANY,
856 new CK_ATTRIBUTE[] {
857 TOKEN_FALSE,
858 });
859
860 // additional attributes for RSA private keys
861 templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, CKK_RSA,
862 new CK_ATTRIBUTE[] {
863 DECRYPT_TRUE,
864 SIGN_TRUE,
865 SIGN_RECOVER_TRUE,
866 UNWRAP_TRUE,
867 });
868 // additional attributes for RSA public keys
869 templateManager.addTemplate(O_ANY, CKO_PUBLIC_KEY, CKK_RSA,
870 new CK_ATTRIBUTE[] {
871 ENCRYPT_TRUE,
872 VERIFY_TRUE,
873 VERIFY_RECOVER_TRUE,
874 WRAP_TRUE,
875 });
876
877 // additional attributes for DSA private keys
878 templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, CKK_DSA,
879 new CK_ATTRIBUTE[] {
880 SIGN_TRUE,
881 });
882 // additional attributes for DSA public keys
883 templateManager.addTemplate(O_ANY, CKO_PUBLIC_KEY, CKK_DSA,
884 new CK_ATTRIBUTE[] {
885 VERIFY_TRUE,
886 });
887
888 // additional attributes for DH private keys
889 templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, CKK_DH,
890 new CK_ATTRIBUTE[] {
891 DERIVE_TRUE,
892 });
893
894 // additional attributes for EC private keys
895 templateManager.addTemplate(O_ANY, CKO_PRIVATE_KEY, CKK_EC,
896 new CK_ATTRIBUTE[] {
897 SIGN_TRUE,
898 DERIVE_TRUE,
899 });
900 // additional attributes for EC public keys
901 templateManager.addTemplate(O_ANY, CKO_PUBLIC_KEY, CKK_EC,
902 new CK_ATTRIBUTE[] {
903 VERIFY_TRUE,
904 });
905 }
906
907 private final static CK_ATTRIBUTE[] CK_A0 = new CK_ATTRIBUTE[0];
908
909 private String parseOperation() throws IOException {
910 String op = parseWord();
911 switch (op) {
912 case "*":
913 return TemplateManager.O_ANY;
914 case "generate":
915 return TemplateManager.O_GENERATE;
916 case "import":
917 return TemplateManager.O_IMPORT;
918 default:
919 throw excLine("Unknown operation " + op);
920 }
921 }
922
923 private long parseObjectClass() throws IOException {
924 String name = parseWord();
925 try {
926 return Functions.getObjectClassId(name);
927 } catch (IllegalArgumentException e) {
928 throw excLine("Unknown object class " + name);
929 }
930 }
931
932 private long parseKeyAlgorithm() throws IOException {
933 String name = parseWord();
934 if (isNumber(name)) {
935 return decodeNumber(name);
936 } else {
937 try {
938 return Functions.getKeyId(name);
939 } catch (IllegalArgumentException e) {
940 throw excLine("Unknown key algorithm " + name);
941 }
942 }
943 }
944
945 private long decodeAttributeName(String name) throws IOException {
946 if (isNumber(name)) {
947 return decodeNumber(name);
948 } else {
949 try {
950 return Functions.getAttributeId(name);
951 } catch (IllegalArgumentException e) {
952 throw excLine("Unknown attribute name " + name);
953 }
954 }
955 }
956
957 private CK_ATTRIBUTE decodeAttributeValue(long id, String value)
958 throws IOException {
959 if (value.equals("null")) {
960 return new CK_ATTRIBUTE(id);
961 } else if (value.equals("true")) {
962 return new CK_ATTRIBUTE(id, true);
963 } else if (value.equals("false")) {
964 return new CK_ATTRIBUTE(id, false);
965 } else if (isByteArray(value)) {
966 return new CK_ATTRIBUTE(id, decodeByteArray(value));
967 } else if (isNumber(value)) {
968 return new CK_ATTRIBUTE(id, Integer.valueOf(decodeNumber(value)));
969 } else {
970 throw excLine("Unknown attribute value " + value);
971 }
972 }
973
974 private void parseNSSArgs(String keyword) throws IOException {
975 checkDup(keyword);
976 parseEquals();
977 int token = nextToken();
978 if (token != '"') {
979 throw excToken("Expected quoted string");
980 }
981 nssArgs = expand(st.sval);
982 debug("nssArgs: " + nssArgs);
983 }
984
985 private void parseHandleStartupErrors(String keyword) throws IOException {
986 checkDup(keyword);
987 parseEquals();
988 String val = parseWord();
989 if (val.equals("ignoreAll")) {
990 handleStartupErrors = ERR_IGNORE_ALL;
991 } else if (val.equals("ignoreMissingLibrary")) {
992 handleStartupErrors = ERR_IGNORE_LIB;
993 } else if (val.equals("halt")) {
994 handleStartupErrors = ERR_HALT;
995 } else {
996 throw excToken("Invalid value for handleStartupErrors:");
997 }
998 debug("handleStartupErrors: " + handleStartupErrors);
999 }
1000
1001 }
1002
1003 class ConfigurationException extends IOException {
1004 private static final long serialVersionUID = 254492758807673194L;
1005 ConfigurationException(String msg) {
1006 super(msg);
1007 }
1008 }