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