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