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