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