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 }