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