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